From a9fa3b2af16a699a504cb86cb73a4bc8d7b24f8a Mon Sep 17 00:00:00 2001
From: MATSUDA Takashi
- [](https://goreportcard.com/report/github.com/jesseduffield/lazygit) [](https://golangci.com) [](http://godoc.org/github.com/jesseduffield/lazygit) [](<>) [](https://www.tickgit.com/browse?repo=github.com/jesseduffield/lazygit)
+ [](https://goreportcard.com/report/github.com/jesseduffield/lazygit) [](https://golangci.com) [](https://godoc.org/github.com/jesseduffield/lazygit) [](<>) [](https://www.tickgit.com/browse?repo=github.com/jesseduffield/lazygit)
A simple terminal UI for git commands, written in Go with the [gocui](https://github.com/jroimartin/gocui "gocui") library.
From 91dab7fef9cffaead9925d22bfb18b1f6c73aa2c Mon Sep 17 00:00:00 2001
From: Moritz Haase - esc: Ga terug naar remotes lijst + esc: ga terug naar remotes lijst g: bekijk reset opties enter: bekijk commits space: uitchecken @@ -179,7 +179,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Bestanden Paneel (Bestanden)## List Panel Navigation @@ -170,20 +169,20 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct @: open command log menu -## Files Panel - -- c: Commit veranderingen + c: commit veranderingen w: commit veranderingen zonder pre-commit hook A: wijzig laatste commit C: commit veranderingen met de git editor @@ -276,7 +276,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct a: toggle selecteer hunk H: scroll left L: scroll right - c: Commit veranderingen + c: commit veranderingen w: commit veranderingen zonder pre-commit hook C: commit veranderingen met de git editordiff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index 94eea0687..546239df5 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -35,13 +35,11 @@ func GetDir() string { } func generateAtDir(cheatsheetDir string) { - os.Setenv("LANG", "en") - translationSetsByLang := i18n.GetTranslationSets() mConfig := config.NewDummyAppConfig() for lang := range translationSetsByLang { - os.Setenv("LC_ALL", lang) + mConfig.GetUserConfig().Gui.Language = lang mApp, _ := app.NewApp(mConfig, "") path := cheatsheetDir + "/Keybindings_" + lang + ".md" file, err := os.Create(path) From 866f4b9f0efa13dfb4b3ab995ab5595a3ed29e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?=Date: Tue, 15 Feb 2022 19:34:36 +0100 Subject: [PATCH 010/385] Support line offset for most common editors by default --- pkg/commands/git_commands/file.go | 10 ++++++++++ pkg/commands/git_commands/file_test.go | 11 ++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/pkg/commands/git_commands/file.go b/pkg/commands/git_commands/file.go index 026d79cb0..353a8dcdc 100644 --- a/pkg/commands/git_commands/file.go +++ b/pkg/commands/git_commands/file.go @@ -58,5 +58,15 @@ func (self *FileCommands) GetEditCmdStr(filename string, lineNumber int) (string } editCmdTemplate := self.UserConfig.OS.EditCommandTemplate + if editCmdTemplate == "{{editor}} {{filename}}" { + switch editor { + case "emacs", "nano", "vi", "vim": + editCmdTemplate = "{{editor}} +{{line}} {{filename}}" + case "subl": + editCmdTemplate = "{{editor}} {{filename}}:{{line}}" + case "code": + editCmdTemplate = "{{editor}} --goto {{filename}}:{{line}}" + } + } return utils.ResolvePlaceholderString(editCmdTemplate, templateValues), nil } diff --git a/pkg/commands/git_commands/file_test.go b/pkg/commands/git_commands/file_test.go index a26699b3e..61482054b 100644 --- a/pkg/commands/git_commands/file_test.go +++ b/pkg/commands/git_commands/file_test.go @@ -47,7 +47,7 @@ func TestEditFileCmdStr(t *testing.T) { gitConfigMockResponses: nil, test: func(cmdStr string, err error) { assert.NoError(t, err) - assert.Equal(t, `nano "test"`, cmdStr) + assert.Equal(t, `nano +1 "test"`, cmdStr) }, }, { @@ -61,7 +61,7 @@ func TestEditFileCmdStr(t *testing.T) { gitConfigMockResponses: map[string]string{"core.editor": "nano"}, test: func(cmdStr string, err error) { assert.NoError(t, err) - assert.Equal(t, `nano "test"`, cmdStr) + assert.Equal(t, `nano +1 "test"`, cmdStr) }, }, { @@ -79,6 +79,7 @@ func TestEditFileCmdStr(t *testing.T) { gitConfigMockResponses: nil, test: func(cmdStr string, err error) { assert.NoError(t, err) + assert.Equal(t, `nano +1 "test"`, cmdStr) }, }, { @@ -96,7 +97,7 @@ func TestEditFileCmdStr(t *testing.T) { gitConfigMockResponses: nil, test: func(cmdStr string, err error) { assert.NoError(t, err) - assert.Equal(t, `emacs "test"`, cmdStr) + assert.Equal(t, `emacs +1 "test"`, cmdStr) }, }, { @@ -111,7 +112,7 @@ func TestEditFileCmdStr(t *testing.T) { gitConfigMockResponses: nil, test: func(cmdStr string, err error) { assert.NoError(t, err) - assert.Equal(t, `vi "test"`, cmdStr) + assert.Equal(t, `vi +1 "test"`, cmdStr) }, }, { @@ -126,7 +127,7 @@ func TestEditFileCmdStr(t *testing.T) { gitConfigMockResponses: nil, test: func(cmdStr string, err error) { assert.NoError(t, err) - assert.Equal(t, `vi "file/with space"`, cmdStr) + assert.Equal(t, `vi +1 "file/with space"`, cmdStr) }, }, { From 11acac00913cccbcde5f6c6112453adf0dec04ed Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Wed, 16 Mar 2022 19:46:02 +1100 Subject: [PATCH 011/385] more explicit --- pkg/commands/git_commands/file.go | 3 ++- pkg/config/config_default_platform.go | 4 +++- pkg/config/config_linux.go | 4 +++- pkg/config/config_windows.go | 4 +++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/pkg/commands/git_commands/file.go b/pkg/commands/git_commands/file.go index 353a8dcdc..8744197f0 100644 --- a/pkg/commands/git_commands/file.go +++ b/pkg/commands/git_commands/file.go @@ -5,6 +5,7 @@ import ( "strconv" "github.com/go-errors/errors" + "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -58,7 +59,7 @@ func (self *FileCommands) GetEditCmdStr(filename string, lineNumber int) (string } editCmdTemplate := self.UserConfig.OS.EditCommandTemplate - if editCmdTemplate == "{{editor}} {{filename}}" { + if editCmdTemplate == config.DefaultEditCommandTemplate { switch editor { case "emacs", "nano", "vi", "vim": editCmdTemplate = "{{editor}} +{{line}} {{filename}}" diff --git a/pkg/config/config_default_platform.go b/pkg/config/config_default_platform.go index 32b1df473..32b76cbf0 100644 --- a/pkg/config/config_default_platform.go +++ b/pkg/config/config_default_platform.go @@ -3,11 +3,13 @@ package config +const DefaultEditCommandTemplate = `{{editor}} {{filename}}` + // GetPlatformDefaultConfig gets the defaults for the platform func GetPlatformDefaultConfig() OSConfig { return OSConfig{ EditCommand: ``, - EditCommandTemplate: `{{editor}} {{filename}}`, + EditCommandTemplate: DefaultEditCommandTemplate, OpenCommand: "open {{filename}}", OpenLinkCommand: "open {{link}}", } diff --git a/pkg/config/config_linux.go b/pkg/config/config_linux.go index dd5708a53..93baa1335 100644 --- a/pkg/config/config_linux.go +++ b/pkg/config/config_linux.go @@ -1,10 +1,12 @@ package config +const DefaultEditCommandTemplate = `{{editor}} {{filename}}` + // GetPlatformDefaultConfig gets the defaults for the platform func GetPlatformDefaultConfig() OSConfig { return OSConfig{ EditCommand: ``, - EditCommandTemplate: `{{editor}} {{filename}}`, + EditCommandTemplate: DefaultEditCommandTemplate, OpenCommand: `xdg-open {{filename}} >/dev/null`, OpenLinkCommand: `xdg-open {{link}} >/dev/null`, } diff --git a/pkg/config/config_windows.go b/pkg/config/config_windows.go index 301eecec1..eb0b00728 100644 --- a/pkg/config/config_windows.go +++ b/pkg/config/config_windows.go @@ -1,10 +1,12 @@ package config +const DefaultEditCommandTemplate = `{{editor}} {{filename}}` + // GetPlatformDefaultConfig gets the defaults for the platform func GetPlatformDefaultConfig() OSConfig { return OSConfig{ EditCommand: ``, - EditCommandTemplate: `{{editor}} {{filename}}`, + EditCommandTemplate: DefaultEditCommandTemplate, OpenCommand: `start "" {{filename}}`, OpenLinkCommand: `start "" {{link}}`, } From f53b10072deeb2923d6b932287c4b39bb7bd389e Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Wed, 16 Mar 2022 19:47:03 +1100 Subject: [PATCH 012/385] open code in existing window --- pkg/commands/git_commands/file.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/commands/git_commands/file.go b/pkg/commands/git_commands/file.go index 8744197f0..1837ee4a4 100644 --- a/pkg/commands/git_commands/file.go +++ b/pkg/commands/git_commands/file.go @@ -66,7 +66,7 @@ func (self *FileCommands) GetEditCmdStr(filename string, lineNumber int) (string case "subl": editCmdTemplate = "{{editor}} {{filename}}:{{line}}" case "code": - editCmdTemplate = "{{editor}} --goto {{filename}}:{{line}}" + editCmdTemplate = "{{editor}} -r --goto {{filename}}:{{line}}" } } return utils.ResolvePlaceholderString(editCmdTemplate, templateValues), nil From ca8180e1b78b4ca6a92bf02caafd2632323c2eba Mon Sep 17 00:00:00 2001 From: Francisco Miamoto Date: Sat, 12 Mar 2022 20:36:50 -0300 Subject: [PATCH 013/385] Use editFileAtLine method for line by line panel --- pkg/gui/line_by_line_panel.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/gui/line_by_line_panel.go b/pkg/gui/line_by_line_panel.go index 0576d3c0f..a033aa0d7 100644 --- a/pkg/gui/line_by_line_panel.go +++ b/pkg/gui/line_by_line_panel.go @@ -1,8 +1,6 @@ package gui import ( - "fmt" - "github.com/go-errors/errors" "github.com/jesseduffield/lazygit/pkg/commands/patch" "github.com/jesseduffield/lazygit/pkg/gui/lbl" @@ -217,8 +215,7 @@ func (gui *Gui) handleOpenFileAtLine() error { // need to look at current index, then work out what my hunk's header information is, and see how far my line is away from the hunk header lineNumber := state.CurrentLineNumber() - filenameWithLineNum := fmt.Sprintf("%s:%d", filename, lineNumber) - if err := gui.OSCommand.OpenFile(filenameWithLineNum); err != nil { + if err := gui.editFileAtLine(filename, lineNumber); err != nil { return err } From 7544d853fc23810052bae188b211d200de000147 Mon Sep 17 00:00:00 2001 From: Moritz Haase Date: Tue, 15 Mar 2022 11:53:51 +0100 Subject: [PATCH 014/385] docs: Remove 'GolangCI' badge from README.md The service has apparently closed down some time ago. See: https://medium.com/golangci/golangci-com-is-closing-d1fc1bd30e0e --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 95f78fa72..9294a2fdb 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ - [](https://goreportcard.com/report/github.com/jesseduffield/lazygit) [](https://golangci.com) [](https://godoc.org/github.com/jesseduffield/lazygit) [](<>) [](https://www.tickgit.com/browse?repo=github.com/jesseduffield/lazygit) + [](https://goreportcard.com/report/github.com/jesseduffield/lazygit) [](https://godoc.org/github.com/jesseduffield/lazygit) [](<>) [](https://www.tickgit.com/browse?repo=github.com/jesseduffield/lazygit) A simple terminal UI for git commands, written in Go with the [gocui](https://github.com/jroimartin/gocui "gocui") library. From 08ee3309cb1125cc06bb10529495695099da0375 Mon Sep 17 00:00:00 2001 From: Moritz Haase
Date: Tue, 15 Mar 2022 11:56:04 +0100 Subject: [PATCH 015/385] docs: Let 'Tag' badge in README.md link to Github 'Releases' page Clicking the badge that shows the current tag (i.e. release) will now direct you to the 'Releases' page. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9294a2fdb..a8b8df058 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ - [](https://goreportcard.com/report/github.com/jesseduffield/lazygit) [](https://godoc.org/github.com/jesseduffield/lazygit) [](<>) [](https://www.tickgit.com/browse?repo=github.com/jesseduffield/lazygit) + [](https://goreportcard.com/report/github.com/jesseduffield/lazygit) [](https://godoc.org/github.com/jesseduffield/lazygit) [](https://github.com/jesseduffield/lazygit/releases) [](https://www.tickgit.com/browse?repo=github.com/jesseduffield/lazygit) A simple terminal UI for git commands, written in Go with the [gocui](https://github.com/jroimartin/gocui "gocui") library. From f0d0d45ba7325f54123756f676f33e0260fa1e15 Mon Sep 17 00:00:00 2001 From: tiwood
Date: Thu, 30 Dec 2021 16:04:49 +0100 Subject: [PATCH 016/385] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20Use=20new=20?= =?UTF-8?q?approach=20introduced=20via=20#1637?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: 馃悰 The root URI for Azure DevOps repositories contains _git refactor so that we don't have conditional logic based on service definition no need for this commend anymore add comment Fixed RegEx for HTTP remote git URL Added Tests pretty sure we can do this safely --- pkg/commands/hosting_service/definitions.go | 28 +++++- .../hosting_service/hosting_service.go | 42 +++----- .../hosting_service/hosting_service_test.go | 97 ++++++++----------- 3 files changed, 79 insertions(+), 88 deletions(-) diff --git a/pkg/commands/hosting_service/definitions.go b/pkg/commands/hosting_service/definitions.go index c70062a67..3e7f144da 100644 --- a/pkg/commands/hosting_service/definitions.go +++ b/pkg/commands/hosting_service/definitions.go @@ -6,6 +6,7 @@ var defaultUrlRegexStrings = []string{ `^(?:https?|ssh)://.*/(?P .*)/(?P .*?)(?:\.git)?$`, `^git@.*:(?P .*)/(?P .*?)(?:\.git)?$`, } +var defaultRepoURLTemplate = "https://{{.webDomain}}/{{.owner}}/{{.repo}}" // we've got less type safety using go templates but this lends itself better to // users adding custom service definitions in their config @@ -15,6 +16,7 @@ var githubServiceDef = ServiceDefinition{ pullRequestURLIntoTargetBranch: "/compare/{{.To}}...{{.From}}?expand=1", commitURL: "/commit/{{.CommitSha}}", regexStrings: defaultUrlRegexStrings, + repoURLTemplate: defaultRepoURLTemplate, } var bitbucketServiceDef = ServiceDefinition{ @@ -23,6 +25,7 @@ var bitbucketServiceDef = ServiceDefinition{ pullRequestURLIntoTargetBranch: "/pull-requests/new?source={{.From}}&dest={{.To}}&t=1", commitURL: "/commits/{{.CommitSha}}", regexStrings: defaultUrlRegexStrings, + repoURLTemplate: defaultRepoURLTemplate, } var gitLabServiceDef = ServiceDefinition{ @@ -31,9 +34,27 @@ var gitLabServiceDef = ServiceDefinition{ pullRequestURLIntoTargetBranch: "/merge_requests/new?merge_request[source_branch]={{.From}}&merge_request[target_branch]={{.To}}", commitURL: "/commit/{{.CommitSha}}", regexStrings: defaultUrlRegexStrings, + repoURLTemplate: defaultRepoURLTemplate, } -var serviceDefinitions = []ServiceDefinition{githubServiceDef, bitbucketServiceDef, gitLabServiceDef} +var azdoServiceDef = ServiceDefinition{ + provider: "azuredevops", + pullRequestURLIntoDefaultBranch: "/pullrequestcreate?sourceRef={{.From}}", + pullRequestURLIntoTargetBranch: "/pullrequestcreate?sourceRef={{.From}}&targetRef={{.To}}", + commitURL: "/commit/{{.CommitSha}}", + regexStrings: []string{ + `^git@ssh.dev.azure.com.*/(?P .*)/(?P .*)/(?P .*?)(?:\.git)?$`, + `^https://.*@dev.azure.com/(?P .*?)/(?P .*?)/_git/(?P .*?)(?:\.git)?$`, + }, + repoURLTemplate: "https://{{.webDomain}}/{{.org}}/{{.project}}/_git/{{.repo}}", +} + +var serviceDefinitions = []ServiceDefinition{ + githubServiceDef, + bitbucketServiceDef, + gitLabServiceDef, + azdoServiceDef, +} var defaultServiceDomains = []ServiceDomain{ { @@ -51,4 +72,9 @@ var defaultServiceDomains = []ServiceDomain{ gitDomain: "gitlab.com", webDomain: "gitlab.com", }, + { + serviceDefinition: azdoServiceDef, + gitDomain: "dev.azure.com", + webDomain: "dev.azure.com", + }, } diff --git a/pkg/commands/hosting_service/hosting_service.go b/pkg/commands/hosting_service/hosting_service.go index 01e07e9eb..4a0a49681 100644 --- a/pkg/commands/hosting_service/hosting_service.go +++ b/pkg/commands/hosting_service/hosting_service.go @@ -1,7 +1,6 @@ package hosting_service import ( - "fmt" "net/url" "regexp" "strings" @@ -66,13 +65,13 @@ func (self *HostingServiceMgr) getService() (*Service, error) { return nil, err } - root, err := serviceDomain.getRootFromRemoteURL(self.remoteURL) + repoURL, err := serviceDomain.serviceDefinition.getRepoURLFromRemoteURL(self.remoteURL, serviceDomain.webDomain) if err != nil { return nil, err } return &Service{ - root: root, + repoURL: repoURL, ServiceDefinition: serviceDomain.serviceDefinition, }, nil } @@ -139,47 +138,32 @@ type ServiceDomain struct { serviceDefinition ServiceDefinition } -func (self ServiceDomain) getRootFromRemoteURL(repoURL string) (string, error) { - // we may want to make this more specific to the service in future e.g. if - // some new service comes along which has a different root url structure. - repoInfo, err := self.serviceDefinition.getRepoInfoFromURL(repoURL) - if err != nil { - return "", err - } - return fmt.Sprintf("https://%s/%s/%s", self.webDomain, repoInfo.Owner, repoInfo.Repository), nil -} - -// RepoInformation holds some basic information about the repo -type RepoInformation struct { - Owner string - Repository string -} - type ServiceDefinition struct { provider string pullRequestURLIntoDefaultBranch string pullRequestURLIntoTargetBranch string commitURL string regexStrings []string + + // can expect 'webdomain' to be passed in. Otherwise, you get to pick what we match in the regex + repoURLTemplate string } -func (self ServiceDefinition) getRepoInfoFromURL(url string) (*RepoInformation, error) { +func (self ServiceDefinition) getRepoURLFromRemoteURL(url string, webDomain string) (string, error) { for _, regexStr := range self.regexStrings { re := regexp.MustCompile(regexStr) - matches := utils.FindNamedMatches(re, url) - if matches != nil { - return &RepoInformation{ - Owner: matches["owner"], - Repository: matches["repo"], - }, nil + input := utils.FindNamedMatches(re, url) + if input != nil { + input["webDomain"] = webDomain + return utils.ResolvePlaceholderString(self.repoURLTemplate, input), nil } } - return nil, errors.New("Failed to parse repo information from url") + return "", errors.New("Failed to parse repo information from url") } type Service struct { - root string + repoURL string ServiceDefinition } @@ -196,5 +180,5 @@ func (self *Service) getCommitURL(commitSha string) string { } func (self *Service) resolveUrl(templateString string, args map[string]string) string { - return self.root + utils.ResolvePlaceholderString(templateString, args) + return self.repoURL + utils.ResolvePlaceholderString(templateString, args) } diff --git a/pkg/commands/hosting_service/hosting_service_test.go b/pkg/commands/hosting_service/hosting_service_test.go index 98c097a33..5bffa0165 100644 --- a/pkg/commands/hosting_service/hosting_service_test.go +++ b/pkg/commands/hosting_service/hosting_service_test.go @@ -8,63 +8,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestGetRepoInfoFromURL(t *testing.T) { - type scenario struct { - serviceDefinition ServiceDefinition - testName string - repoURL string - test func(*RepoInformation) - } - - scenarios := []scenario{ - { - githubServiceDef, - "Returns repository information for git remote url", - "git@github.com:petersmith/super_calculator", - func(repoInfo *RepoInformation) { - assert.EqualValues(t, repoInfo.Owner, "petersmith") - assert.EqualValues(t, repoInfo.Repository, "super_calculator") - }, - }, - { - githubServiceDef, - "Returns repository information for git remote url, trimming trailing '.git'", - "git@github.com:petersmith/super_calculator.git", - func(repoInfo *RepoInformation) { - assert.EqualValues(t, repoInfo.Owner, "petersmith") - assert.EqualValues(t, repoInfo.Repository, "super_calculator") - }, - }, - { - githubServiceDef, - "Returns repository information for ssh remote url", - "ssh://git@github.com/petersmith/super_calculator", - func(repoInfo *RepoInformation) { - assert.EqualValues(t, repoInfo.Owner, "petersmith") - assert.EqualValues(t, repoInfo.Repository, "super_calculator") - }, - }, - { - githubServiceDef, - "Returns repository information for http remote url", - "https://my_username@bitbucket.org/johndoe/social_network.git", - func(repoInfo *RepoInformation) { - assert.EqualValues(t, repoInfo.Owner, "johndoe") - assert.EqualValues(t, repoInfo.Repository, "social_network") - }, - }, - } - - for _, s := range scenarios { - s := s - t.Run(s.testName, func(t *testing.T) { - result, err := s.serviceDefinition.getRepoInfoFromURL(s.repoURL) - assert.NoError(t, err) - s.test(result) - }) - } -} - func TestGetPullRequestURL(t *testing.T) { type scenario struct { testName string @@ -172,6 +115,44 @@ func TestGetPullRequestURL(t *testing.T) { assert.Equal(t, "https://gitlab.com/peter/public/calculator/merge_requests/new?merge_request[source_branch]=feature%2Fcommit-ui&merge_request[target_branch]=epic%2Fui", url) }, }, + { + testName: "Opens a link to new pull request on Azure DevOps (SSH)", + from: "feature/new", + remoteUrl: "git@ssh.dev.azure.com:v3/myorg/myproject/myrepo", + test: func(url string, err error) { + assert.NoError(t, err) + assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature/new", url) + }, + }, + { + testName: "Opens a link to new pull request on Azure DevOps (SSH) with specifc target", + from: "feature/new", + to: "dev", + remoteUrl: "git@ssh.dev.azure.com:v3/myorg/myproject/myrepo", + test: func(url string, err error) { + assert.NoError(t, err) + assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature/new&targetRef=dev", url) + }, + }, + { + testName: "Opens a link to new pull request on Azure DevOps (HTTP)", + from: "feature/new", + remoteUrl: "https://myorg@dev.azure.com/myorg/myproject/_git/myrepo", + test: func(url string, err error) { + assert.NoError(t, err) + assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature/new", url) + }, + }, + { + testName: "Opens a link to new pull request on Azure DevOps (HTTP) with specifc target", + from: "feature/new", + to: "dev", + remoteUrl: "https://myorg@dev.azure.com/myorg/myproject/_git/myrepo", + test: func(url string, err error) { + assert.NoError(t, err) + assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature/new&targetRef=dev", url) + }, + }, { testName: "Throws an error if git service is unsupported", from: "feature/divide-operation", @@ -218,7 +199,7 @@ func TestGetPullRequestURL(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "https://bitbucket.org/johndoe/social_network/pull-requests/new?source=feature%2Fprofile-page&t=1", url) }, - expectedLoggedErrors: []string{"Unknown git service type: 'noservice'. Expected one of github, bitbucket, gitlab"}, + expectedLoggedErrors: []string{"Unknown git service type: 'noservice'. Expected one of github, bitbucket, gitlab, azuredevops"}, }, { testName: "Escapes reserved URL characters in from branch name", From 28c9d85141bac6bc796f286d0a1161de48364887 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Wed, 16 Mar 2022 20:47:39 +1100 Subject: [PATCH 017/385] fix tests --- pkg/commands/hosting_service/hosting_service_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/commands/hosting_service/hosting_service_test.go b/pkg/commands/hosting_service/hosting_service_test.go index 5bffa0165..f5cbe949e 100644 --- a/pkg/commands/hosting_service/hosting_service_test.go +++ b/pkg/commands/hosting_service/hosting_service_test.go @@ -121,7 +121,7 @@ func TestGetPullRequestURL(t *testing.T) { remoteUrl: "git@ssh.dev.azure.com:v3/myorg/myproject/myrepo", test: func(url string, err error) { assert.NoError(t, err) - assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature/new", url) + assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature%2Fnew", url) }, }, { @@ -131,7 +131,7 @@ func TestGetPullRequestURL(t *testing.T) { remoteUrl: "git@ssh.dev.azure.com:v3/myorg/myproject/myrepo", test: func(url string, err error) { assert.NoError(t, err) - assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature/new&targetRef=dev", url) + assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature%2Fnew&targetRef=dev", url) }, }, { @@ -140,7 +140,7 @@ func TestGetPullRequestURL(t *testing.T) { remoteUrl: "https://myorg@dev.azure.com/myorg/myproject/_git/myrepo", test: func(url string, err error) { assert.NoError(t, err) - assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature/new", url) + assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature%2Fnew", url) }, }, { @@ -150,7 +150,7 @@ func TestGetPullRequestURL(t *testing.T) { remoteUrl: "https://myorg@dev.azure.com/myorg/myproject/_git/myrepo", test: func(url string, err error) { assert.NoError(t, err) - assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature/new&targetRef=dev", url) + assert.Equal(t, "https://dev.azure.com/myorg/myproject/_git/myrepo/pullrequestcreate?sourceRef=feature%2Fnew&targetRef=dev", url) }, }, { From 7be25a105d389a262ef040133a4270f2f745d255 Mon Sep 17 00:00:00 2001 From: Ram Bhosale Date: Thu, 17 Mar 2022 17:43:03 +1100 Subject: [PATCH 018/385] allow skipping confirmation prompt after opening subprocess --- docs/Config.md | 1 + pkg/config/user_config.go | 22 ++++++++++++---------- pkg/gui/gui.go | 6 ++++-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/docs/Config.md b/docs/Config.md index 7134d1b8b..aac7f0349 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -95,6 +95,7 @@ confirmOnQuit: false quitOnTopLevelReturn: false disableStartupPopups: false notARepository: 'prompt' # one of: 'prompt' | 'create' | 'skip' +promptToReturnFromSubprocess: true # display confirmation when subprocess terminates keybinding: universal: quit: 'q' diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 3b4e0f139..ac8a2bbc1 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -11,11 +11,12 @@ type UserConfig struct { QuitOnTopLevelReturn bool `yaml:"quitOnTopLevelReturn"` Keybinding KeybindingConfig `yaml:"keybinding"` // OS determines what defaults are set for opening files and links - OS OSConfig `yaml:"os,omitempty"` - DisableStartupPopups bool `yaml:"disableStartupPopups"` - CustomCommands []CustomCommand `yaml:"customCommands"` - Services map[string]string `yaml:"services"` - NotARepository string `yaml:"notARepository"` + OS OSConfig `yaml:"os,omitempty"` + DisableStartupPopups bool `yaml:"disableStartupPopups"` + CustomCommands []CustomCommand `yaml:"customCommands"` + Services map[string]string `yaml:"services"` + NotARepository string `yaml:"notARepository"` + PromptToReturnFromSubprocess bool `yaml:"promptToReturnFromSubprocess"` } type RefresherConfig struct { @@ -535,10 +536,11 @@ func GetDefaultConfig() *UserConfig { BulkMenu: "b", }, }, - OS: GetPlatformDefaultConfig(), - DisableStartupPopups: false, - CustomCommands: []CustomCommand(nil), - Services: map[string]string(nil), - NotARepository: "prompt", + OS: GetPlatformDefaultConfig(), + DisableStartupPopups: false, + CustomCommands: []CustomCommand(nil), + Services: map[string]string(nil), + NotARepository: "prompt", + PromptToReturnFromSubprocess: true, } } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index e5bcd3c88..c6dbf1f65 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -675,8 +675,10 @@ func (gui *Gui) runSubprocess(cmdObj oscommands.ICmdObj) error { //nolint:unpara subprocess.Stderr = ioutil.Discard subprocess.Stdin = nil - fmt.Fprintf(os.Stdout, "\n%s\n", style.FgGreen.Sprint(gui.Tr.PressEnterToReturn)) - fmt.Scanln() // wait for enter press + if gui.Config.GetUserConfig().PromptToReturnFromSubprocess { + fmt.Fprintf(os.Stdout, "\n%s", style.FgGreen.Sprint(gui.Tr.PressEnterToReturn)) + fmt.Scanln() // wait for enter press + } return err } From 950bb5090dfa8e553b6a066b02547fce427c1acd Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Thu, 17 Mar 2022 18:08:26 +1100 Subject: [PATCH 019/385] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a8b8df058..363fccfb0 100644 --- a/README.md +++ b/README.md @@ -292,11 +292,10 @@ If you would like to support the development of lazygit, consider [sponsoring me see [here](https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#struggling-to-see-selected-line) -## Social +## Shameless Plug If you want to see what I (Jesse) am up to in terms of development, follow me on -[twitter](https://twitter.com/DuffieldJesse) or watch me program on -[twitch](https://www.twitch.tv/jesseduffield). +[twitter](https://twitter.com/DuffieldJesse) or check out my [blog](https://jesseduffield.com/) ## Alternatives From b8fc829f860a1d6157ebe49f63e1b16db19c950c Mon Sep 17 00:00:00 2001 From: David Roman Date: Tue, 15 Mar 2022 14:12:26 +0100 Subject: [PATCH 020/385] Record current directory on switch --- pkg/app/app.go | 7 ++++++- pkg/gui/dummies.go | 2 +- pkg/gui/gui.go | 11 ++++++++++- pkg/gui/quitting.go | 10 ++++++---- pkg/gui/recent_repos_panel.go | 4 ++++ 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/pkg/app/app.go b/pkg/app/app.go index cb9aaafea..f38dcb75e 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -128,6 +128,11 @@ func NewApp(config config.AppConfigurer, filterPath string) (*App, error) { return app, err } + dirName, err := os.Getwd() + if err != nil { + return app, err + } + showRecentRepos, err := app.setupRepo() if err != nil { return app, err @@ -135,7 +140,7 @@ func NewApp(config config.AppConfigurer, filterPath string) (*App, error) { gitConfig := git_config.NewStdCachedGitConfig(app.Log) - app.Gui, err = gui.NewGui(app.Common, config, gitConfig, app.Updater, filterPath, showRecentRepos) + app.Gui, err = gui.NewGui(app.Common, config, gitConfig, app.Updater, filterPath, showRecentRepos, dirName) if err != nil { return app, err } diff --git a/pkg/gui/dummies.go b/pkg/gui/dummies.go index 587460ccd..f740b4881 100644 --- a/pkg/gui/dummies.go +++ b/pkg/gui/dummies.go @@ -17,6 +17,6 @@ func NewDummyUpdater() *updates.Updater { func NewDummyGui() *Gui { newAppConfig := config.NewDummyAppConfig() - dummyGui, _ := NewGui(utils.NewDummyCommon(), newAppConfig, git_config.NewFakeGitConfig(nil), NewDummyUpdater(), "", false) + dummyGui, _ := NewGui(utils.NewDummyCommon(), newAppConfig, git_config.NewFakeGitConfig(nil), NewDummyUpdater(), "", false, "") return dummyGui } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index c6dbf1f65..416a2faf7 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -124,6 +124,8 @@ type Gui struct { PopupHandler PopupHandler IsNewRepo bool + + InitialRepoDir string } type listPanelState struct { @@ -447,6 +449,7 @@ func NewGui( updater *updates.Updater, filterPath string, showRecentRepos bool, + initialRepoDir string, ) (*Gui, error) { gui := &Gui{ Common: cmn, @@ -464,6 +467,8 @@ func NewGui( // but now we do it via state. So we need to still support the config for the // sake of backwards compatibility. We're making use of short circuiting here ShowExtrasWindow: cmn.UserConfig.Gui.ShowCommandLog && !config.GetAppState().HideCommandLog, + + InitialRepoDir: initialRepoDir, } guiIO := oscommands.NewGuiIO( @@ -590,7 +595,11 @@ func (gui *Gui) RunAndHandleError() error { switch err { case gocui.ErrQuit: - if !gui.State.RetainOriginalDir { + if gui.State.RetainOriginalDir { + if err := gui.recordDirectory(gui.InitialRepoDir); err != nil { + return err + } + } else { if err := gui.recordCurrentDirectory(); err != nil { return err } diff --git a/pkg/gui/quitting.go b/pkg/gui/quitting.go index c3fd2ce2f..eae68ea5f 100644 --- a/pkg/gui/quitting.go +++ b/pkg/gui/quitting.go @@ -11,16 +11,18 @@ import ( // shell can then change to that directory. That means you don't get kicked // back to the directory that you started with. func (gui *Gui) recordCurrentDirectory() error { - if os.Getenv("LAZYGIT_NEW_DIR_FILE") == "" { - return nil - } - // determine current directory, set it in LAZYGIT_NEW_DIR_FILE dirName, err := os.Getwd() if err != nil { return err } + return gui.recordDirectory(dirName) +} +func (gui *Gui) recordDirectory(dirName string) error { + if os.Getenv("LAZYGIT_NEW_DIR_FILE") == "" { + return nil + } return gui.OSCommand.CreateFileWithContent(os.Getenv("LAZYGIT_NEW_DIR_FILE"), dirName) } diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index 7bf6b068c..01b9a00d3 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -84,6 +84,10 @@ func (gui *Gui) dispatchSwitchToRepo(path string, reuse bool) error { gui.Mutexes.RefreshingFilesMutex.Lock() defer gui.Mutexes.RefreshingFilesMutex.Unlock() + if err := gui.recordCurrentDirectory(); err != nil { + return err + } + gui.resetState("", reuse) return nil From d8d0d4686d15700e67a1ecbcec310ee55f3a16c5 Mon Sep 17 00:00:00 2001 From: David Roman Date: Wed, 16 Mar 2022 14:07:48 +0100 Subject: [PATCH 021/385] Only read env once when recording dirs --- pkg/gui/quitting.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/gui/quitting.go b/pkg/gui/quitting.go index eae68ea5f..d3beaf998 100644 --- a/pkg/gui/quitting.go +++ b/pkg/gui/quitting.go @@ -20,10 +20,11 @@ func (gui *Gui) recordCurrentDirectory() error { } func (gui *Gui) recordDirectory(dirName string) error { - if os.Getenv("LAZYGIT_NEW_DIR_FILE") == "" { + newDirFilePath := os.Getenv("LAZYGIT_NEW_DIR_FILE") + if newDirFilePath == "" { return nil } - return gui.OSCommand.CreateFileWithContent(os.Getenv("LAZYGIT_NEW_DIR_FILE"), dirName) + return gui.OSCommand.CreateFileWithContent(newDirFilePath, dirName) } func (gui *Gui) handleQuitWithoutChangingDirectory() error { From fa8571e1f4c349e401542285ea238acdbd9d17ec Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Thu, 17 Mar 2022 18:42:44 +1100 Subject: [PATCH 022/385] rename field --- pkg/gui/gui.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 416a2faf7..981a81987 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -125,7 +125,13 @@ type Gui struct { IsNewRepo bool - InitialRepoDir string + // this is the initial dir we are in upon opening lazygit. We hold onto this + // in case we want to restore it before quitting for users who have set up + // the feature for changing directory upon quit. + // The reason we don't just wait until quit time to handle changing directories + // is because some users want to keep track of the current lazygit directory in an outside + // process + InitialDir string } type listPanelState struct { @@ -449,7 +455,7 @@ func NewGui( updater *updates.Updater, filterPath string, showRecentRepos bool, - initialRepoDir string, + initialDir string, ) (*Gui, error) { gui := &Gui{ Common: cmn, @@ -468,7 +474,7 @@ func NewGui( // sake of backwards compatibility. We're making use of short circuiting here ShowExtrasWindow: cmn.UserConfig.Gui.ShowCommandLog && !config.GetAppState().HideCommandLog, - InitialRepoDir: initialRepoDir, + InitialDir: initialDir, } guiIO := oscommands.NewGuiIO( @@ -596,7 +602,7 @@ func (gui *Gui) RunAndHandleError() error { switch err { case gocui.ErrQuit: if gui.State.RetainOriginalDir { - if err := gui.recordDirectory(gui.InitialRepoDir); err != nil { + if err := gui.recordDirectory(gui.InitialDir); err != nil { return err } } else { From a90b6efded49abcfa2516db794d7875b0396f558 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Fri, 28 Jan 2022 20:44:36 +1100 Subject: [PATCH 023/385] start refactoring gui --- pkg/gui/app_status_manager.go | 6 +- pkg/gui/branches_panel.go | 164 ++++----- pkg/gui/cherry_picking.go | 15 +- pkg/gui/commit_files_panel.go | 40 ++- pkg/gui/commit_message_panel.go | 2 +- pkg/gui/commits_panel.go | 351 ++++++++++--------- pkg/gui/confirmation_panel.go | 99 ++---- pkg/gui/context_config.go | 3 +- pkg/gui/controllers/submodules_controller.go | 243 +++++++++++++ pkg/gui/controllers/types.go | 13 + pkg/gui/credentials_panel.go | 21 +- pkg/gui/custom_commands.go | 78 +++-- pkg/gui/diff_context_size.go | 4 +- pkg/gui/diff_context_size_test.go | 9 +- pkg/gui/diffing.go | 46 +-- pkg/gui/discard_changes_menu_panel.go | 57 +-- pkg/gui/extras_panel.go | 44 +-- pkg/gui/file_watching.go | 3 +- pkg/gui/files_panel.go | 301 +++++++++------- pkg/gui/filtering.go | 17 +- pkg/gui/filtering_menu_panel.go | 32 +- pkg/gui/find_suggestions.go | 2 +- pkg/gui/git_flow.go | 62 ++-- pkg/gui/global_handlers.go | 11 +- pkg/gui/gpg.go | 11 +- pkg/gui/gui.go | 235 ++++++++----- pkg/gui/keybindings.go | 102 ++---- pkg/gui/layout.go | 10 +- pkg/gui/line_by_line_panel.go | 2 +- pkg/gui/list_context_config.go | 9 +- pkg/gui/menu_panel.go | 56 +-- pkg/gui/merge_panel.go | 5 +- pkg/gui/options_menu_panel.go | 24 +- pkg/gui/patch_options_panel.go | 62 ++-- pkg/gui/popup/popup_handler.go | 223 ++++++++++++ pkg/gui/popup_handler.go | 87 ----- pkg/gui/pull_request_menu_panel.go | 35 +- pkg/gui/quitting.go | 21 +- pkg/gui/rebase_options_panel.go | 38 +- pkg/gui/recent_repos_panel.go | 15 +- pkg/gui/reflog_panel.go | 11 +- pkg/gui/remote_branches_panel.go | 30 +- pkg/gui/remotes_panel.go | 60 ++-- pkg/gui/reset_menu_panel.go | 19 +- pkg/gui/staging_panel.go | 14 +- pkg/gui/stash_panel.go | 38 +- pkg/gui/status_panel.go | 21 +- pkg/gui/sub_commits_panel.go | 9 +- pkg/gui/submodules_panel.go | 199 +---------- pkg/gui/tags_panel.go | 32 +- pkg/gui/types/keybindings.go | 18 + pkg/gui/types/refresh.go | 32 ++ pkg/gui/undoing.go | 26 +- pkg/gui/updates.go | 23 +- pkg/gui/view_helpers.go | 111 +++--- pkg/gui/whitespace-toggle.go | 4 +- pkg/gui/workspace_reset_options_panel.go | 54 +-- pkg/i18n/chinese.go | 1 - pkg/i18n/english.go | 4 +- pkg/updates/updates.go | 10 +- pkg/utils/string_stack.go | 27 ++ 61 files changed, 1779 insertions(+), 1522 deletions(-) create mode 100644 pkg/gui/controllers/submodules_controller.go create mode 100644 pkg/gui/controllers/types.go create mode 100644 pkg/gui/popup/popup_handler.go delete mode 100644 pkg/gui/popup_handler.go create mode 100644 pkg/gui/types/keybindings.go create mode 100644 pkg/gui/types/refresh.go create mode 100644 pkg/utils/string_stack.go diff --git a/pkg/gui/app_status_manager.go b/pkg/gui/app_status_manager.go index e625fcad2..825bb8801 100644 --- a/pkg/gui/app_status_manager.go +++ b/pkg/gui/app_status_manager.go @@ -106,8 +106,8 @@ func (gui *Gui) renderAppStatus() { }) } -// WithWaitingStatus wraps a function and shows a waiting status while the function is still executing -func (gui *Gui) WithWaitingStatus(message string, f func() error) error { +// withWaitingStatus wraps a function and shows a waiting status while the function is still executing +func (gui *Gui) withWaitingStatus(message string, f func() error) error { go utils.Safe(func() { id := gui.statusManager.addWaitingStatus(message) @@ -119,7 +119,7 @@ func (gui *Gui) WithWaitingStatus(message string, f func() error) error { if err := f(); err != nil { gui.OnUIThread(func() error { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) }) } }) diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index feef98431..dca0dc8f0 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -7,6 +7,8 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -62,7 +64,7 @@ func (gui *Gui) refreshBranches() { branches, err := gui.Git.Loaders.Branches.Load(reflogCommits) if err != nil { - _ = gui.surfaceError(err) + _ = gui.PopupHandler.Error(err) } gui.State.Branches = branches @@ -81,7 +83,7 @@ func (gui *Gui) handleBranchPress() error { return nil } if gui.State.Panels.Branches.SelectedLineIdx == 0 { - return gui.createErrorPanel(gui.Tr.AlreadyCheckedOutBranch) + return gui.PopupHandler.ErrorMsg(gui.Tr.AlreadyCheckedOutBranch) } branch := gui.getSelectedBranch() gui.logAction(gui.Tr.Actions.CheckoutBranch) @@ -111,16 +113,16 @@ func (gui *Gui) handleCopyPullRequestURLPress() error { branchExistsOnRemote := gui.Git.Remote.CheckRemoteBranchExists(branch.Name) if !branchExistsOnRemote { - return gui.surfaceError(errors.New(gui.Tr.NoBranchOnRemote)) + return gui.PopupHandler.Error(errors.New(gui.Tr.NoBranchOnRemote)) } url, err := hostingServiceMgr.GetPullRequestURL(branch.Name, "") if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.logAction(gui.Tr.Actions.CopyPullRequestURL) if err := gui.OSCommand.CopyToClipboard(url); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.raiseToast(gui.Tr.PullRequestURLCopiedToClipboard) @@ -129,16 +131,12 @@ func (gui *Gui) handleCopyPullRequestURLPress() error { } func (gui *Gui) handleGitFetch() error { - if err := gui.createLoaderPanel(gui.Tr.FetchWait); err != nil { - return err - } - - go utils.Safe(func() { - err := gui.fetch() - gui.handleCredentialsPopup(err) - _ = gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.PopupHandler.WithLoaderPanel(gui.Tr.FetchWait, func() error { + if err := gui.fetch(); err != nil { + _ = gui.PopupHandler.Error(err) + } + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) }) - return nil } func (gui *Gui) handleForceCheckout() error { @@ -146,15 +144,15 @@ func (gui *Gui) handleForceCheckout() error { message := gui.Tr.SureForceCheckout title := gui.Tr.ForceCheckoutBranch - return gui.ask(askOpts{ - title: title, - prompt: message, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: title, + Prompt: message, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.ForceCheckoutBranch) if err := gui.Git.Branch.Checkout(branch.Name, git_commands.CheckoutOptions{Force: true}); err != nil { - _ = gui.surfaceError(err) + _ = gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) }, }) } @@ -180,7 +178,7 @@ func (gui *Gui) handleCheckoutRef(ref string, options handleCheckoutRefOptions) gui.State.Panels.Commits.LimitCommits = true } - return gui.WithWaitingStatus(waitingStatus, func() error { + return gui.PopupHandler.WithWaitingStatus(waitingStatus, func() error { if err := gui.Git.Branch.Checkout(ref, cmdOptions); err != nil { // note, this will only work for english-language git commands. If we force git to use english, and the error isn't this one, then the user will receive an english command they may not understand. I'm not sure what the best solution to this is. Running the command once in english and a second time in the native language is one option @@ -190,52 +188,52 @@ func (gui *Gui) handleCheckoutRef(ref string, options handleCheckoutRefOptions) if strings.Contains(err.Error(), "Please commit your changes or stash them before you switch branch") { // offer to autostash changes - return gui.ask(askOpts{ + return gui.PopupHandler.Ask(popup.AskOpts{ - title: gui.Tr.AutoStashTitle, - prompt: gui.Tr.AutoStashPrompt, - handleConfirm: func() error { + Title: gui.Tr.AutoStashTitle, + Prompt: gui.Tr.AutoStashPrompt, + HandleConfirm: func() error { if err := gui.Git.Stash.Save(gui.Tr.StashPrefix + ref); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } if err := gui.Git.Branch.Checkout(ref, cmdOptions); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } onSuccess() if err := gui.Git.Stash.Pop(0); err != nil { - if err := gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI}); err != nil { + if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.BLOCK_UI}); err != nil { return err } - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.BLOCK_UI}) }, }) } - if err := gui.surfaceError(err); err != nil { + if err := gui.PopupHandler.Error(err); err != nil { return err } } onSuccess() - return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.BLOCK_UI}) }) } func (gui *Gui) handleCheckoutByName() error { - return gui.prompt(promptOpts{ - title: gui.Tr.BranchName + ":", - findSuggestionsFunc: gui.getRefsSuggestionsFunc(), - handleConfirm: func(response string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: gui.Tr.BranchName + ":", + FindSuggestionsFunc: gui.getRefsSuggestionsFunc(), + HandleConfirm: func(response string) error { gui.logAction("Checkout branch") return gui.handleCheckoutRef(response, handleCheckoutRefOptions{ onRefNotFound: func(ref string) error { - return gui.ask(askOpts{ - title: gui.Tr.BranchNotFoundTitle, - prompt: fmt.Sprintf("%s %s%s", gui.Tr.BranchNotFoundPrompt, ref, "?"), - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.BranchNotFoundTitle, + Prompt: fmt.Sprintf("%s %s%s", gui.Tr.BranchNotFoundPrompt, ref, "?"), + HandleConfirm: func() error { return gui.createNewBranchWithName(ref) }, }) @@ -260,11 +258,11 @@ func (gui *Gui) createNewBranchWithName(newBranchName string) error { } if err := gui.Git.Branch.New(newBranchName, branch.Name); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.State.Panels.Branches.SelectedLineIdx = 0 - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) } func (gui *Gui) handleDeleteBranch() error { @@ -278,7 +276,7 @@ func (gui *Gui) deleteBranch(force bool) error { } checkedOutBranch := gui.getCheckedOutBranch() if checkedOutBranch.Name == selectedBranch.Name { - return gui.createErrorPanel(gui.Tr.CantDeleteCheckOutBranch) + return gui.PopupHandler.ErrorMsg(gui.Tr.CantDeleteCheckOutBranch) } return gui.deleteNamedBranch(selectedBranch, force) } @@ -298,19 +296,19 @@ func (gui *Gui) deleteNamedBranch(selectedBranch *models.Branch, force bool) err }, ) - return gui.ask(askOpts{ - title: title, - prompt: message, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: title, + Prompt: message, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.DeleteBranch) if err := gui.Git.Branch.Delete(selectedBranch.Name, force); err != nil { errMessage := err.Error() if !force && strings.Contains(errMessage, "git branch -D ") { return gui.deleteNamedBranch(selectedBranch, true) } - return gui.createErrorPanel(errMessage) + return gui.PopupHandler.ErrorMsg(errMessage) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{BRANCHES}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) }, }) } @@ -321,11 +319,11 @@ func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error { } if gui.Git.Branch.IsHeadDetached() { - return gui.createErrorPanel("Cannot merge branch in detached head state. You might have checked out a commit directly or a remote branch, in which case you should checkout the local branch you want to be on") + return gui.PopupHandler.ErrorMsg("Cannot merge branch in detached head state. You might have checked out a commit directly or a remote branch, in which case you should checkout the local branch you want to be on") } checkedOutBranchName := gui.getCheckedOutBranch().Name if checkedOutBranchName == branchName { - return gui.createErrorPanel(gui.Tr.CantMergeBranchIntoItself) + return gui.PopupHandler.ErrorMsg(gui.Tr.CantMergeBranchIntoItself) } prompt := utils.ResolvePlaceholderString( gui.Tr.ConfirmMerge, @@ -335,10 +333,10 @@ func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error { }, ) - return gui.ask(askOpts{ - title: gui.Tr.MergingTitle, - prompt: prompt, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.MergingTitle, + Prompt: prompt, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.Merge) err := gui.Git.Branch.Merge(branchName, git_commands.MergeOpts{}) return gui.handleGenericMergeCommandResult(err) @@ -367,7 +365,7 @@ func (gui *Gui) handleRebaseOntoBranch(selectedBranchName string) error { checkedOutBranch := gui.getCheckedOutBranch().Name if selectedBranchName == checkedOutBranch { - return gui.createErrorPanel(gui.Tr.CantRebaseOntoSelf) + return gui.PopupHandler.ErrorMsg(gui.Tr.CantRebaseOntoSelf) } prompt := utils.ResolvePlaceholderString( gui.Tr.ConfirmRebase, @@ -377,10 +375,10 @@ func (gui *Gui) handleRebaseOntoBranch(selectedBranchName string) error { }, ) - return gui.ask(askOpts{ - title: gui.Tr.RebasingTitle, - prompt: prompt, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.RebasingTitle, + Prompt: prompt, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.RebaseBranch) err := gui.Git.Rebase.RebaseBranch(selectedBranchName) return gui.handleGenericMergeCommandResult(err) @@ -395,13 +393,13 @@ func (gui *Gui) handleFastForward() error { } if !branch.IsTrackingRemote() { - return gui.createErrorPanel(gui.Tr.FwdNoUpstream) + return gui.PopupHandler.ErrorMsg(gui.Tr.FwdNoUpstream) } if !branch.RemoteBranchStoredLocally() { - return gui.createErrorPanel(gui.Tr.FwdNoLocalUpstream) + return gui.PopupHandler.ErrorMsg(gui.Tr.FwdNoLocalUpstream) } if branch.HasCommitsToPush() { - return gui.createErrorPanel(gui.Tr.FwdCommitsToPush) + return gui.PopupHandler.ErrorMsg(gui.Tr.FwdCommitsToPush) } action := gui.Tr.Actions.FastForwardBranch @@ -413,19 +411,21 @@ func (gui *Gui) handleFastForward() error { "to": branch.Name, }, ) - go utils.Safe(func() { - _ = gui.createLoaderPanel(message) + return gui.PopupHandler.WithLoaderPanel(message, func() error { if gui.State.Panels.Branches.SelectedLineIdx == 0 { _ = gui.pullWithLock(PullFilesOptions{action: action, FastForwardOnly: true}) } else { gui.logAction(action) err := gui.Git.Sync.FastForward(branch.Name, branch.UpstreamRemote, branch.UpstreamBranch) - gui.handleCredentialsPopup(err) - _ = gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{BRANCHES}}) + if err != nil { + _ = gui.PopupHandler.Error(err) + } + _ = gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) } + + return nil }) - return nil } func (gui *Gui) handleCreateResetToBranchMenu() error { @@ -444,13 +444,13 @@ func (gui *Gui) handleRenameBranch() error { } promptForNewName := func() error { - return gui.prompt(promptOpts{ - title: gui.Tr.NewBranchNamePrompt + " " + branch.Name + ":", - initialContent: branch.Name, - handleConfirm: func(newBranchName string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: gui.Tr.NewBranchNamePrompt + " " + branch.Name + ":", + InitialContent: branch.Name, + HandleConfirm: func(newBranchName string) error { gui.logAction(gui.Tr.Actions.RenameBranch) if err := gui.Git.Branch.Rename(branch.Name, newBranchName); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } // need to find where the branch is now so that we can re-select it. That means we need to refetch the branches synchronously and then find our branch @@ -478,10 +478,10 @@ func (gui *Gui) handleRenameBranch() error { return promptForNewName() } - return gui.ask(askOpts{ - title: gui.Tr.LcRenameBranch, - prompt: gui.Tr.RenameBranchWarning, - handleConfirm: promptForNewName, + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.LcRenameBranch, + Prompt: gui.Tr.RenameBranchWarning, + HandleConfirm: promptForNewName, }) } @@ -513,10 +513,10 @@ func (gui *Gui) handleNewBranchOffCurrentItem() error { prefilledName = strings.SplitAfterN(item.ID(), "/", 2)[1] } - return gui.prompt(promptOpts{ - title: message, - initialContent: prefilledName, - handleConfirm: func(response string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: message, + InitialContent: prefilledName, + HandleConfirm: func(response string) error { gui.logAction(gui.Tr.Actions.CreateBranch) if err := gui.Git.Branch.New(sanitizedBranchName(response), item.ID()); err != nil { return err @@ -536,7 +536,7 @@ func (gui *Gui) handleNewBranchOffCurrentItem() error { gui.State.Panels.Branches.SelectedLineIdx = 0 - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) }, }) } diff --git a/pkg/gui/cherry_picking.go b/pkg/gui/cherry_picking.go index b4b9439cd..225fc3811 100644 --- a/pkg/gui/cherry_picking.go +++ b/pkg/gui/cherry_picking.go @@ -1,6 +1,9 @@ package gui -import "github.com/jesseduffield/lazygit/pkg/commands/models" +import ( + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/popup" +) // you can only copy from one context at a time, because the order and position of commits matter @@ -143,11 +146,11 @@ func (gui *Gui) HandlePasteCommits() error { return err } - return gui.ask(askOpts{ - title: gui.Tr.CherryPick, - prompt: gui.Tr.SureCherryPick, - handleConfirm: func() error { - return gui.WithWaitingStatus(gui.Tr.CherryPickingStatus, func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.CherryPick, + Prompt: gui.Tr.SureCherryPick, + HandleConfirm: func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.CherryPickingStatus, func() error { gui.logAction(gui.Tr.Actions.CherryPick) err := gui.Git.Rebase.CherryPickCommits(gui.State.Modes.CherryPicking.CherryPickedCommits) return gui.handleGenericMergeCommandResult(err) diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index 61f3b72b8..1941802c2 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -4,6 +4,8 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/patch" "github.com/jesseduffield/lazygit/pkg/gui/filetree" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) func (gui *Gui) getSelectedCommitFileNode() *filetree.CommitFileNode { @@ -65,10 +67,10 @@ func (gui *Gui) handleCheckoutCommitFile() error { gui.logAction(gui.Tr.Actions.CheckoutFile) if err := gui.Git.WorkingTree.CheckoutFile(gui.State.CommitFileTreeViewModel.GetParent(), node.GetPath()); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) } func (gui *Gui) handleDiscardOldFileChange() error { @@ -78,11 +80,11 @@ func (gui *Gui) handleDiscardOldFileChange() error { fileName := gui.getSelectedCommitFileName() - return gui.ask(askOpts{ - title: gui.Tr.DiscardFileChangesTitle, - prompt: gui.Tr.DiscardFileChangesPrompt, - handleConfirm: func() error { - return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.DiscardFileChangesTitle, + Prompt: gui.Tr.DiscardFileChangesPrompt, + HandleConfirm: func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { gui.logAction(gui.Tr.Actions.DiscardOldFileChange) if err := gui.Git.Rebase.DiscardOldFileChanges(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, fileName); err != nil { if err := gui.handleGenericMergeCommandResult(err); err != nil { @@ -90,7 +92,7 @@ func (gui *Gui) handleDiscardOldFileChange() error { } } - return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.BLOCK_UI}) }) }, }) @@ -109,7 +111,7 @@ func (gui *Gui) refreshCommitFilesView() error { files, err := gui.Git.Loaders.CommitFiles.GetFilesInDiff(from, to, reverse) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.State.CommitFileTreeViewModel.SetParent(to) gui.State.CommitFileTreeViewModel.SetFiles(files) @@ -133,7 +135,7 @@ func (gui *Gui) handleEditCommitFile() error { } if node.File == nil { - return gui.createErrorPanel(gui.Tr.ErrCannotEditDirectory) + return gui.PopupHandler.ErrorMsg(gui.Tr.ErrCannotEditDirectory) } return gui.editFile(node.GetPath()) @@ -167,7 +169,7 @@ func (gui *Gui) handleToggleFileForPatch() error { }) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } if gui.Git.Patch.PatchManager.IsEmpty() { @@ -178,10 +180,10 @@ func (gui *Gui) handleToggleFileForPatch() error { } if gui.Git.Patch.PatchManager.Active() && gui.Git.Patch.PatchManager.To != gui.State.CommitFileTreeViewModel.GetParent() { - return gui.ask(askOpts{ - title: gui.Tr.DiscardPatch, - prompt: gui.Tr.DiscardPatchConfirm, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.DiscardPatch, + Prompt: gui.Tr.DiscardPatchConfirm, + HandleConfirm: func() error { gui.Git.Patch.PatchManager.Reset() return toggleTheFile() }, @@ -226,10 +228,10 @@ func (gui *Gui) enterCommitFile(opts OnFocusOpts) error { } if gui.Git.Patch.PatchManager.Active() && gui.Git.Patch.PatchManager.To != gui.State.CommitFileTreeViewModel.GetParent() { - return gui.ask(askOpts{ - title: gui.Tr.DiscardPatch, - prompt: gui.Tr.DiscardPatchConfirm, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.DiscardPatch, + Prompt: gui.Tr.DiscardPatchConfirm, + HandleConfirm: func() error { gui.Git.Patch.PatchManager.Reset() return enterTheFile() }, diff --git a/pkg/gui/commit_message_panel.go b/pkg/gui/commit_message_panel.go index 5f5a8741f..feed1aecc 100644 --- a/pkg/gui/commit_message_panel.go +++ b/pkg/gui/commit_message_panel.go @@ -12,7 +12,7 @@ func (gui *Gui) handleCommitConfirm() error { message := strings.TrimSpace(gui.Views.CommitMessage.TextArea.GetContent()) gui.State.failedCommitMessage = message if message == "" { - return gui.createErrorPanel(gui.Tr.CommitWithoutMessageErr) + return gui.PopupHandler.ErrorMsg(gui.Tr.CommitWithoutMessageErr) } cmdObj := gui.Git.Commit.CommitCmdObj(message) diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index 26015c069..342596964 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -6,6 +6,8 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/loaders" "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -29,7 +31,7 @@ func (gui *Gui) onCommitFocus() error { state.LimitCommits = false go utils.Safe(func() { if err := gui.refreshCommitsWithLimit(); err != nil { - _ = gui.surfaceError(err) + _ = gui.PopupHandler.Error(err) } }) } @@ -122,7 +124,7 @@ func (gui *Gui) refreshCommitsWithLimit() error { FilterPath: gui.State.Modes.Filtering.GetPath(), IncludeRebaseCommits: true, RefName: gui.refForLog(), - All: gui.State.ShowWholeGitGraph, + All: gui.ShowWholeGitGraph, }, ) if err != nil { @@ -170,7 +172,7 @@ func (gui *Gui) handleCommitSquashDown() error { } if len(gui.State.Commits) <= 1 { - return gui.createErrorPanel(gui.Tr.YouNoCommitsToSquash) + return gui.PopupHandler.ErrorMsg(gui.Tr.YouNoCommitsToSquash) } applied, err := gui.handleMidRebaseCommand("squash") @@ -181,11 +183,11 @@ func (gui *Gui) handleCommitSquashDown() error { return nil } - return gui.ask(askOpts{ - title: gui.Tr.Squash, - prompt: gui.Tr.SureSquashThisCommit, - handleConfirm: func() error { - return gui.WithWaitingStatus(gui.Tr.SquashingStatus, func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.Squash, + Prompt: gui.Tr.SureSquashThisCommit, + HandleConfirm: func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.SquashingStatus, func() error { gui.logAction(gui.Tr.Actions.SquashCommitDown) err := gui.Git.Rebase.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, "squash") return gui.handleGenericMergeCommandResult(err) @@ -200,7 +202,7 @@ func (gui *Gui) handleCommitFixup() error { } if len(gui.State.Commits) <= 1 { - return gui.createErrorPanel(gui.Tr.YouNoCommitsToSquash) + return gui.PopupHandler.ErrorMsg(gui.Tr.YouNoCommitsToSquash) } applied, err := gui.handleMidRebaseCommand("fixup") @@ -211,11 +213,11 @@ func (gui *Gui) handleCommitFixup() error { return nil } - return gui.ask(askOpts{ - title: gui.Tr.Fixup, - prompt: gui.Tr.SureFixupThisCommit, - handleConfirm: func() error { - return gui.WithWaitingStatus(gui.Tr.FixingStatus, func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.Fixup, + Prompt: gui.Tr.SureFixupThisCommit, + HandleConfirm: func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.FixingStatus, func() error { gui.logAction(gui.Tr.Actions.FixupCommit) err := gui.Git.Rebase.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, "fixup") return gui.handleGenericMergeCommandResult(err) @@ -244,20 +246,20 @@ func (gui *Gui) handleRewordCommit() error { message, err := gui.Git.Commit.GetCommitMessage(commit.Sha) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } // TODO: use the commit message panel here - return gui.prompt(promptOpts{ - title: gui.Tr.LcRewordCommit, - initialContent: message, - handleConfirm: func(response string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: gui.Tr.LcRewordCommit, + InitialContent: message, + HandleConfirm: func(response string) error { gui.logAction(gui.Tr.Actions.RewordCommit) if err := gui.Git.Rebase.RewordCommit(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, response); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) }, }) } @@ -278,7 +280,7 @@ func (gui *Gui) handleRewordCommitEditor() error { gui.logAction(gui.Tr.Actions.RewordCommit) subProcess, err := gui.Git.Rebase.RewordCommitInEditor(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } if subProcess != nil { return gui.runSubprocessWithSuspenseAndRefresh(subProcess) @@ -301,7 +303,7 @@ func (gui *Gui) handleMidRebaseCommand(action string) (bool, error) { // our input or we set a lazygit client as the EDITOR env variable and have it // request us to edit the commit message when prompted. if action == "reword" { - return true, gui.createErrorPanel(gui.Tr.LcRewordNotSupported) + return true, gui.PopupHandler.ErrorMsg(gui.Tr.LcRewordNotSupported) } gui.logAction("Update rebase TODO") @@ -311,7 +313,7 @@ func (gui *Gui) handleMidRebaseCommand(action string) (bool, error) { ) if err := gui.Git.Rebase.EditRebaseTodo(gui.State.Panels.Commits.SelectedLineIdx, action); err != nil { - return false, gui.surfaceError(err) + return false, gui.PopupHandler.Error(err) } return true, gui.refreshRebaseCommits() @@ -330,11 +332,11 @@ func (gui *Gui) handleCommitDelete() error { return nil } - return gui.ask(askOpts{ - title: gui.Tr.DeleteCommitTitle, - prompt: gui.Tr.DeleteCommitPrompt, - handleConfirm: func() error { - return gui.WithWaitingStatus(gui.Tr.DeletingStatus, func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.DeleteCommitTitle, + Prompt: gui.Tr.DeleteCommitPrompt, + HandleConfirm: func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.DeletingStatus, func() error { gui.logAction(gui.Tr.Actions.DropCommit) err := gui.Git.Rebase.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, "drop") return gui.handleGenericMergeCommandResult(err) @@ -361,13 +363,13 @@ func (gui *Gui) handleCommitMoveDown() error { gui.logCommand(fmt.Sprintf("Moving commit %s down", selectedCommit.ShortSha()), false) if err := gui.Git.Rebase.MoveTodoDown(index); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.State.Panels.Commits.SelectedLineIdx++ return gui.refreshRebaseCommits() } - return gui.WithWaitingStatus(gui.Tr.MovingStatus, func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.MovingStatus, func() error { gui.logAction(gui.Tr.Actions.MoveCommitDown) err := gui.Git.Rebase.MoveCommitDown(gui.State.Commits, index) if err == nil { @@ -398,13 +400,13 @@ func (gui *Gui) handleCommitMoveUp() error { ) if err := gui.Git.Rebase.MoveTodoDown(index - 1); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.State.Panels.Commits.SelectedLineIdx-- return gui.refreshRebaseCommits() } - return gui.WithWaitingStatus(gui.Tr.MovingStatus, func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.MovingStatus, func() error { gui.logAction(gui.Tr.Actions.MoveCommitUp) err := gui.Git.Rebase.MoveCommitDown(gui.State.Commits, index-1) if err == nil { @@ -427,7 +429,7 @@ func (gui *Gui) handleCommitEdit() error { return nil } - return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { gui.logAction(gui.Tr.Actions.EditCommit) err = gui.Git.Rebase.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, "edit") return gui.handleGenericMergeCommandResult(err) @@ -439,11 +441,11 @@ func (gui *Gui) handleCommitAmendTo() error { return err } - return gui.ask(askOpts{ - title: gui.Tr.AmendCommitTitle, - prompt: gui.Tr.AmendCommitPrompt, - handleConfirm: func() error { - return gui.WithWaitingStatus(gui.Tr.AmendingStatus, func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.AmendCommitTitle, + Prompt: gui.Tr.AmendCommitPrompt, + HandleConfirm: func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.AmendingStatus, func() error { gui.logAction(gui.Tr.Actions.AmendCommit) err := gui.Git.Rebase.AmendTo(gui.State.Commits[gui.State.Panels.Commits.SelectedLineIdx].Sha) return gui.handleGenericMergeCommandResult(err) @@ -478,17 +480,17 @@ func (gui *Gui) handleCommitRevert() error { if commit.IsMerge() { return gui.createRevertMergeCommitMenu(commit) } else { - return gui.ask(askOpts{ - title: gui.Tr.Actions.RevertCommit, - prompt: utils.ResolvePlaceholderString( + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.Actions.RevertCommit, + Prompt: utils.ResolvePlaceholderString( gui.Tr.ConfirmRevertCommit, map[string]string{ "selectedCommit": commit.ShortSha(), }), - handleConfirm: func() error { + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.RevertCommit) if err := gui.Git.Commit.Revert(commit.Sha); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return gui.afterRevertCommit() }, @@ -497,33 +499,33 @@ func (gui *Gui) handleCommitRevert() error { } func (gui *Gui) createRevertMergeCommitMenu(commit *models.Commit) error { - menuItems := make([]*menuItem, len(commit.Parents)) + menuItems := make([]*popup.MenuItem, len(commit.Parents)) for i, parentSha := range commit.Parents { i := i message, err := gui.Git.Commit.GetCommitMessageFirstLine(parentSha) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - menuItems[i] = &menuItem{ - displayString: fmt.Sprintf("%s: %s", utils.SafeTruncate(parentSha, 8), message), - onPress: func() error { + menuItems[i] = &popup.MenuItem{ + DisplayString: fmt.Sprintf("%s: %s", utils.SafeTruncate(parentSha, 8), message), + OnPress: func() error { parentNumber := i + 1 gui.logAction(gui.Tr.Actions.RevertCommit) if err := gui.Git.Commit.RevertMerge(commit.Sha, parentNumber); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return gui.afterRevertCommit() }, } } - return gui.createMenu(gui.Tr.SelectParentCommitForMerge, menuItems, createMenuOptions{showCancel: true}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: gui.Tr.SelectParentCommitForMerge, Items: menuItems}) } func (gui *Gui) afterRevertCommit() error { gui.State.Panels.Commits.SelectedLineIdx++ - return gui.refreshSidePanels(refreshOptions{mode: BLOCK_UI, scope: []RefreshableView{COMMITS, BRANCHES}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.BLOCK_UI, Scope: []types.RefreshableView{types.COMMITS, types.BRANCHES}}) } func (gui *Gui) handleViewCommitFiles() error { @@ -552,16 +554,16 @@ func (gui *Gui) handleCreateFixupCommit() error { }, ) - return gui.ask(askOpts{ - title: gui.Tr.CreateFixupCommit, - prompt: prompt, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.CreateFixupCommit, + Prompt: prompt, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.CreateFixupCommit) if err := gui.Git.Commit.CreateFixupCommit(commit.Sha); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) }, }) } @@ -583,11 +585,11 @@ func (gui *Gui) handleSquashAllAboveFixupCommits() error { }, ) - return gui.ask(askOpts{ - title: gui.Tr.SquashAboveCommits, - prompt: prompt, - handleConfirm: func() error { - return gui.WithWaitingStatus(gui.Tr.SquashingStatus, func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.SquashAboveCommits, + Prompt: prompt, + HandleConfirm: func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.SquashingStatus, func() error { gui.logAction(gui.Tr.Actions.SquashAllAboveFixupCommits) err := gui.Git.Rebase.SquashAllAboveFixupCommits(commit.Sha) return gui.handleGenericMergeCommandResult(err) @@ -606,39 +608,40 @@ func (gui *Gui) handleTagCommit() error { } func (gui *Gui) createTagMenu(commitSha string) error { - items := []*menuItem{ - { - displayString: gui.Tr.LcLightweightTag, - onPress: func() error { - return gui.handleCreateLightweightTag(commitSha) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{ + Title: gui.Tr.TagMenuTitle, + Items: []*popup.MenuItem{ + { + DisplayString: gui.Tr.LcLightweightTag, + OnPress: func() error { + return gui.handleCreateLightweightTag(commitSha) + }, + }, + { + DisplayString: gui.Tr.LcAnnotatedTag, + OnPress: func() error { + return gui.handleCreateAnnotatedTag(commitSha) + }, }, }, - { - displayString: gui.Tr.LcAnnotatedTag, - onPress: func() error { - return gui.handleCreateAnnotatedTag(commitSha) - }, - }, - } - - return gui.createMenu(gui.Tr.TagMenuTitle, items, createMenuOptions{showCancel: true}) + }) } func (gui *Gui) afterTagCreate() error { gui.State.Panels.Tags.SelectedLineIdx = 0 // Set to the top - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{COMMITS, TAGS}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}}) } func (gui *Gui) handleCreateAnnotatedTag(commitSha string) error { - return gui.prompt(promptOpts{ - title: gui.Tr.TagNameTitle, - handleConfirm: func(tagName string) error { - return gui.prompt(promptOpts{ - title: gui.Tr.TagMessageTitle, - handleConfirm: func(msg string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: gui.Tr.TagNameTitle, + HandleConfirm: func(tagName string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: gui.Tr.TagMessageTitle, + HandleConfirm: func(msg string) error { gui.logAction(gui.Tr.Actions.CreateAnnotatedTag) if err := gui.Git.Tag.CreateAnnotated(tagName, commitSha, msg); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return gui.afterTagCreate() }, @@ -648,12 +651,12 @@ func (gui *Gui) handleCreateAnnotatedTag(commitSha string) error { } func (gui *Gui) handleCreateLightweightTag(commitSha string) error { - return gui.prompt(promptOpts{ - title: gui.Tr.TagNameTitle, - handleConfirm: func(tagName string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: gui.Tr.TagNameTitle, + HandleConfirm: func(tagName string) error { gui.logAction(gui.Tr.Actions.CreateLightweightTag) if err := gui.Git.Tag.CreateLightweight(tagName, commitSha); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return gui.afterTagCreate() }, @@ -666,10 +669,10 @@ func (gui *Gui) handleCheckoutCommit() error { return nil } - return gui.ask(askOpts{ - title: gui.Tr.LcCheckoutCommit, - prompt: gui.Tr.SureCheckoutThisCommit, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.LcCheckoutCommit, + Prompt: gui.Tr.SureCheckoutThisCommit, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.CheckoutCommit) return gui.handleCheckoutRef(commit.Sha, handleCheckoutRefOptions{}) }, @@ -679,7 +682,7 @@ func (gui *Gui) handleCheckoutCommit() error { func (gui *Gui) handleCreateCommitResetMenu() error { commit := gui.getSelectedLocalCommit() if commit == nil { - return gui.createErrorPanel(gui.Tr.NoCommitsThisBranch) + return gui.PopupHandler.ErrorMsg(gui.Tr.NoCommitsThisBranch) } return gui.createResetMenu(commit.Sha) @@ -689,7 +692,7 @@ func (gui *Gui) handleOpenSearchForCommitsPanel(string) error { // we usually lazyload these commits but now that we're searching we need to load them now if gui.State.Panels.Commits.LimitCommits { gui.State.Panels.Commits.LimitCommits = false - if err := gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{COMMITS}}); err != nil { + if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS}}); err != nil { return err } } @@ -701,7 +704,7 @@ func (gui *Gui) handleGotoBottomForCommitsPanel() error { // we usually lazyload these commits but now that we're searching we need to load them now if gui.State.Panels.Commits.LimitCommits { gui.State.Panels.Commits.LimitCommits = false - if err := gui.refreshSidePanels(refreshOptions{mode: SYNC, scope: []RefreshableView{COMMITS}}); err != nil { + if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}); err != nil { return err } } @@ -723,12 +726,12 @@ func (gui *Gui) handleCopySelectedCommitMessageToClipboard() error { message, err := gui.Git.Commit.GetCommitMessage(commit.Sha) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.logAction(gui.Tr.Actions.CopyCommitMessageToClipboard) if err := gui.OSCommand.CopyToClipboard(message); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.raiseToast(gui.Tr.CommitMessageCopiedToClipboard) @@ -737,87 +740,87 @@ func (gui *Gui) handleCopySelectedCommitMessageToClipboard() error { } func (gui *Gui) handleOpenLogMenu() error { - return gui.createMenu(gui.Tr.LogMenuTitle, []*menuItem{ - { - displayString: gui.Tr.ToggleShowGitGraphAll, - onPress: func() error { - gui.State.ShowWholeGitGraph = !gui.State.ShowWholeGitGraph + return gui.PopupHandler.Menu(popup.CreateMenuOptions{ + Title: gui.Tr.LogMenuTitle, + Items: []*popup.MenuItem{ + { + DisplayString: gui.Tr.ToggleShowGitGraphAll, + OnPress: func() error { + gui.ShowWholeGitGraph = !gui.ShowWholeGitGraph - if gui.State.ShowWholeGitGraph { - gui.State.Panels.Commits.LimitCommits = false - } + if gui.ShowWholeGitGraph { + gui.State.Panels.Commits.LimitCommits = false + } - return gui.WithWaitingStatus(gui.Tr.LcLoadingCommits, func() error { - return gui.refreshSidePanels(refreshOptions{mode: SYNC, scope: []RefreshableView{COMMITS}}) - }) - }, - }, - { - displayString: gui.Tr.ShowGitGraph, - opensMenu: true, - onPress: func() error { - onSelect := func(value string) { - gui.UserConfig.Git.Log.ShowGraph = value - gui.render() - } - return gui.createMenu(gui.Tr.LogMenuTitle, []*menuItem{ - { - displayString: "always", - onPress: func() error { - onSelect("always") - return nil - }, - }, - { - displayString: "never", - onPress: func() error { - onSelect("never") - return nil - }, - }, - { - displayString: "when maximised", - onPress: func() error { - onSelect("when-maximised") - return nil - }, - }, - }, createMenuOptions{showCancel: true}) - }, - }, - { - displayString: gui.Tr.SortCommits, - opensMenu: true, - onPress: func() error { - onSelect := func(value string) error { - gui.UserConfig.Git.Log.Order = value - return gui.WithWaitingStatus(gui.Tr.LcLoadingCommits, func() error { - return gui.refreshSidePanels(refreshOptions{mode: SYNC, scope: []RefreshableView{COMMITS}}) + return gui.PopupHandler.WithWaitingStatus(gui.Tr.LcLoadingCommits, func() error { + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}) }) - } - return gui.createMenu(gui.Tr.LogMenuTitle, []*menuItem{ - { - displayString: "topological (topo-order)", - onPress: func() error { - return onSelect("topo-order") + }, + }, + { + DisplayString: gui.Tr.ShowGitGraph, + OpensMenu: true, + OnPress: func() error { + onPress := func(value string) func() error { + return func() error { + gui.UserConfig.Git.Log.ShowGraph = value + gui.render() + return nil + } + } + return gui.PopupHandler.Menu(popup.CreateMenuOptions{ + Title: gui.Tr.LogMenuTitle, + Items: []*popup.MenuItem{ + { + DisplayString: "always", + OnPress: onPress("always"), + }, + { + DisplayString: "never", + OnPress: onPress("never"), + }, + { + DisplayString: "when maximised", + OnPress: onPress("when-maximised"), + }, }, - }, - { - displayString: "date-order", - onPress: func() error { - return onSelect("date-order") + }) + }, + }, + { + DisplayString: gui.Tr.SortCommits, + OpensMenu: true, + OnPress: func() error { + onPress := func(value string) func() error { + return func() error { + gui.UserConfig.Git.Log.Order = value + return gui.PopupHandler.WithWaitingStatus(gui.Tr.LcLoadingCommits, func() error { + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}) + }) + } + } + + return gui.PopupHandler.Menu(popup.CreateMenuOptions{ + Title: gui.Tr.LogMenuTitle, + Items: []*popup.MenuItem{ + { + DisplayString: "topological (topo-order)", + OnPress: onPress("topo-order"), + }, + { + DisplayString: "date-order", + OnPress: onPress("date-order"), + }, + { + DisplayString: "author-date-order", + OnPress: onPress("author-date-order"), + }, }, - }, - { - displayString: "author-date-order", - onPress: func() error { - return onSelect("author-date-order") - }, - }, - }, createMenuOptions{showCancel: true}) + }) + }, }, }, - }, createMenuOptions{showCancel: true}) + }) } func (gui *Gui) handleOpenCommitInBrowser() error { @@ -830,12 +833,12 @@ func (gui *Gui) handleOpenCommitInBrowser() error { url, err := hostingServiceMgr.GetCommitURL(commit.Sha) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.logAction(gui.Tr.Actions.OpenCommitInBrowser) if err := gui.OSCommand.OpenLink(url); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return nil diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index b092b1d10..0d5457101 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -5,53 +5,12 @@ import ( "strings" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/utils" ) -type createPopupPanelOpts struct { - hasLoader bool - editable bool - title string - prompt string - handleConfirm func() error - handleConfirmPrompt func(string) error - handleClose func() error - - // when handlersManageFocus is true, do not return from the confirmation context automatically. It's expected that the handlers will manage focus, whether that means switching to another context, or manually returning the context. - handlersManageFocus bool - - findSuggestionsFunc func(string) []*types.Suggestion -} - -type askOpts struct { - title string - prompt string - handleConfirm func() error - handleClose func() error - handlersManageFocus bool -} - -type promptOpts struct { - title string - initialContent string - findSuggestionsFunc func(string) []*types.Suggestion - handleConfirm func(string) error -} - -func (gui *Gui) ask(opts askOpts) error { - return gui.PopupHandler.Ask(opts) -} - -func (gui *Gui) prompt(opts promptOpts) error { - return gui.PopupHandler.Prompt(opts) -} - -func (gui *Gui) createLoaderPanel(prompt string) error { - return gui.PopupHandler.Loader(prompt) -} - func (gui *Gui) wrappedConfirmationFunction(handlersManageFocus bool, function func() error) func() error { return func() error { if err := gui.closeConfirmationPrompt(handlersManageFocus); err != nil { @@ -60,7 +19,7 @@ func (gui *Gui) wrappedConfirmationFunction(handlersManageFocus bool, function f if function != nil { if err := function(); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } } @@ -76,7 +35,7 @@ func (gui *Gui) wrappedPromptConfirmationFunction(handlersManageFocus bool, func if function != nil { if err := function(getResponse()); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } } @@ -179,31 +138,31 @@ func (gui *Gui) prepareConfirmationPanel( return nil } -func (gui *Gui) createPopupPanel(opts createPopupPanelOpts) error { +func (gui *Gui) createPopupPanel(opts popup.CreatePopupPanelOpts) error { // remove any previous keybindings gui.clearConfirmationViewKeyBindings() err := gui.prepareConfirmationPanel( - opts.title, - opts.prompt, - opts.hasLoader, - opts.findSuggestionsFunc, - opts.editable, + opts.Title, + opts.Prompt, + opts.HasLoader, + opts.FindSuggestionsFunc, + opts.Editable, ) if err != nil { return err } confirmationView := gui.Views.Confirmation - confirmationView.Editable = opts.editable + confirmationView.Editable = opts.Editable confirmationView.Editor = gocui.EditorFunc(gui.defaultEditor) - if opts.editable { + if opts.Editable { textArea := confirmationView.TextArea textArea.Clear() - textArea.TypeString(opts.prompt) + textArea.TypeString(opts.Prompt) confirmationView.RenderTextArea() } else { - if err := gui.renderString(confirmationView, opts.prompt); err != nil { + if err := gui.renderString(confirmationView, opts.Prompt); err != nil { return err } } @@ -215,7 +174,7 @@ func (gui *Gui) createPopupPanel(opts createPopupPanelOpts) error { return gui.pushContext(gui.State.Contexts.Confirmation) } -func (gui *Gui) setKeyBindings(opts createPopupPanelOpts) error { +func (gui *Gui) setKeyBindings(opts popup.CreatePopupPanelOpts) error { actions := utils.ResolvePlaceholderString( gui.Tr.CloseConfirm, map[string]string{ @@ -226,10 +185,10 @@ func (gui *Gui) setKeyBindings(opts createPopupPanelOpts) error { _ = gui.renderString(gui.Views.Options, actions) var onConfirm func() error - if opts.handleConfirmPrompt != nil { - onConfirm = gui.wrappedPromptConfirmationFunction(opts.handlersManageFocus, opts.handleConfirmPrompt, func() string { return gui.Views.Confirmation.TextArea.GetContent() }) + if opts.HandleConfirmPrompt != nil { + onConfirm = gui.wrappedPromptConfirmationFunction(opts.HandlersManageFocus, opts.HandleConfirmPrompt, func() string { return gui.Views.Confirmation.TextArea.GetContent() }) } else { - onConfirm = gui.wrappedConfirmationFunction(opts.handlersManageFocus, opts.handleConfirm) + onConfirm = gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleConfirm) } type confirmationKeybinding struct { @@ -240,8 +199,8 @@ func (gui *Gui) setKeyBindings(opts createPopupPanelOpts) error { keybindingConfig := gui.UserConfig.Keybinding onSuggestionConfirm := gui.wrappedPromptConfirmationFunction( - opts.handlersManageFocus, - opts.handleConfirmPrompt, + opts.HandlersManageFocus, + opts.HandleConfirmPrompt, gui.getSelectedSuggestionValue, ) @@ -259,7 +218,7 @@ func (gui *Gui) setKeyBindings(opts createPopupPanelOpts) error { { viewName: "confirmation", key: gui.getKey(keybindingConfig.Universal.Return), - handler: gui.wrappedConfirmationFunction(opts.handlersManageFocus, opts.handleClose), + handler: gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleClose), }, { viewName: "confirmation", @@ -284,7 +243,7 @@ func (gui *Gui) setKeyBindings(opts createPopupPanelOpts) error { { viewName: "suggestions", key: gui.getKey(keybindingConfig.Universal.Return), - handler: gui.wrappedConfirmationFunction(opts.handlersManageFocus, opts.handleClose), + handler: gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleClose), }, { viewName: "suggestions", @@ -317,19 +276,3 @@ func (gui *Gui) wrappedHandler(f func() error) func(g *gocui.Gui, v *gocui.View) return f() } } - -func (gui *Gui) createErrorPanel(message string) error { - return gui.PopupHandler.Error(message) -} - -func (gui *Gui) surfaceError(err error) error { - if err == nil { - return nil - } - - if err == gocui.ErrQuit { - return err - } - - return gui.createErrorPanel(err.Error()) -} diff --git a/pkg/gui/context_config.go b/pkg/gui/context_config.go index f567f5a5c..e884d32bd 100644 --- a/pkg/gui/context_config.go +++ b/pkg/gui/context_config.go @@ -174,12 +174,13 @@ func (gui *Gui) contextTree() ContextTree { OnGetOptionsMap: gui.getMergingOptions, }, Credentials: &BasicContext{ - OnFocus: OnFocusWrapper(gui.handleCredentialsViewFocused), + OnFocus: OnFocusWrapper(gui.handleAskFocused), Kind: PERSISTENT_POPUP, ViewName: "credentials", Key: CREDENTIALS_CONTEXT_KEY, }, Confirmation: &BasicContext{ + OnFocus: OnFocusWrapper(gui.handleAskFocused), Kind: TEMPORARY_POPUP, ViewName: "confirmation", Key: CONFIRMATION_CONTEXT_KEY, diff --git a/pkg/gui/controllers/submodules_controller.go b/pkg/gui/controllers/submodules_controller.go new file mode 100644 index 000000000..e5eaf98a0 --- /dev/null +++ b/pkg/gui/controllers/submodules_controller.go @@ -0,0 +1,243 @@ +package controllers + +import ( + "fmt" + "path/filepath" + "strings" + + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/common" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/style" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +// if Go let me do private struct embedding of structs with public fields (which it should) +// I would just do that. But alas. +type ControllerCommon struct { + *common.Common + IGuiCommon +} + +type SubmodulesController struct { + // I've said publicly that I'm against single-letter variable names but in this + // case I would actually prefer a _zero_ letter variable name in the form of + // struct embedding, but Go does not allow hiding public fields in an embedded struct + // to the client + c *ControllerCommon + enterSubmoduleFn func(submodule *models.SubmoduleConfig) error + getSelectedSubmodule func() *models.SubmoduleConfig + git *commands.GitCommand + submodules []*models.SubmoduleConfig +} + +func NewSubmodulesController( + c *ControllerCommon, + enterSubmoduleFn func(submodule *models.SubmoduleConfig) error, + git *commands.GitCommand, + submodules []*models.SubmoduleConfig, + getSelectedSubmodule func() *models.SubmoduleConfig, +) *SubmodulesController { + return &SubmodulesController{ + c: c, + enterSubmoduleFn: enterSubmoduleFn, + git: git, + submodules: submodules, + getSelectedSubmodule: getSelectedSubmodule, + } +} + +func (self *SubmodulesController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig) []*types.Binding { + return []*types.Binding{ + { + Key: getKey(config.Universal.GoInto), + Handler: self.forSubmodule(self.enter), + Description: self.c.Tr.LcEnterSubmodule, + }, + { + Key: getKey(config.Universal.Remove), + Handler: self.forSubmodule(self.remove), + Description: self.c.Tr.LcRemoveSubmodule, + }, + { + Key: getKey(config.Submodules.Update), + Handler: self.forSubmodule(self.update), + Description: self.c.Tr.LcSubmoduleUpdate, + }, + { + Key: getKey(config.Universal.New), + Handler: self.add, + Description: self.c.Tr.LcAddSubmodule, + }, + { + Key: getKey(config.Universal.Edit), + Handler: self.forSubmodule(self.editURL), + Description: self.c.Tr.LcEditSubmoduleUrl, + }, + { + Key: getKey(config.Submodules.Init), + Handler: self.forSubmodule(self.init), + Description: self.c.Tr.LcInitSubmodule, + }, + { + Key: getKey(config.Submodules.BulkMenu), + Handler: self.openBulkActionsMenu, + Description: self.c.Tr.LcViewBulkSubmoduleOptions, + OpensMenu: true, + }, + } +} + +func (self *SubmodulesController) enter(submodule *models.SubmoduleConfig) error { + return self.enterSubmoduleFn(submodule) +} + +func (self *SubmodulesController) add() error { + return self.c.Prompt(popup.PromptOpts{ + Title: self.c.Tr.LcNewSubmoduleUrl, + HandleConfirm: func(submoduleUrl string) error { + nameSuggestion := filepath.Base(strings.TrimSuffix(submoduleUrl, filepath.Ext(submoduleUrl))) + + return self.c.Prompt(popup.PromptOpts{ + Title: self.c.Tr.LcNewSubmoduleName, + InitialContent: nameSuggestion, + HandleConfirm: func(submoduleName string) error { + + return self.c.Prompt(popup.PromptOpts{ + Title: self.c.Tr.LcNewSubmodulePath, + InitialContent: submoduleName, + HandleConfirm: func(submodulePath string) error { + return self.c.WithWaitingStatus(self.c.Tr.LcAddingSubmoduleStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.AddSubmodule) + err := self.git.Submodule.Add(submoduleName, submodulePath, submoduleUrl) + if err != nil { + _ = self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}}) + }) + }, + }) + }, + }) + }, + }) +} + +func (self *SubmodulesController) editURL(submodule *models.SubmoduleConfig) error { + return self.c.Prompt(popup.PromptOpts{ + Title: fmt.Sprintf(self.c.Tr.LcUpdateSubmoduleUrl, submodule.Name), + InitialContent: submodule.Url, + HandleConfirm: func(newUrl string) error { + return self.c.WithWaitingStatus(self.c.Tr.LcUpdatingSubmoduleUrlStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.UpdateSubmoduleUrl) + err := self.git.Submodule.UpdateUrl(submodule.Name, submodule.Path, newUrl) + if err != nil { + _ = self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}}) + }) + }, + }) +} + +func (self *SubmodulesController) init(submodule *models.SubmoduleConfig) error { + return self.c.WithWaitingStatus(self.c.Tr.LcInitializingSubmoduleStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.InitialiseSubmodule) + err := self.git.Submodule.Init(submodule.Path) + if err != nil { + _ = self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}}) + }) +} + +func (self *SubmodulesController) openBulkActionsMenu() error { + return self.c.Menu(popup.CreateMenuOptions{ + Title: self.c.Tr.LcBulkSubmoduleOptions, + Items: []*popup.MenuItem{ + { + DisplayStrings: []string{self.c.Tr.LcBulkInitSubmodules, style.FgGreen.Sprint(self.git.Submodule.BulkInitCmdObj().ToString())}, + OnPress: func() error { + return self.c.WithWaitingStatus(self.c.Tr.LcRunningCommand, func() error { + self.c.LogAction(self.c.Tr.Actions.BulkInitialiseSubmodules) + err := self.git.Submodule.BulkInitCmdObj().Run() + if err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}}) + }) + }, + }, + { + DisplayStrings: []string{self.c.Tr.LcBulkUpdateSubmodules, style.FgYellow.Sprint(self.git.Submodule.BulkUpdateCmdObj().ToString())}, + OnPress: func() error { + return self.c.WithWaitingStatus(self.c.Tr.LcRunningCommand, func() error { + self.c.LogAction(self.c.Tr.Actions.BulkUpdateSubmodules) + if err := self.git.Submodule.BulkUpdateCmdObj().Run(); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}}) + }) + }, + }, + { + DisplayStrings: []string{self.c.Tr.LcBulkDeinitSubmodules, style.FgRed.Sprint(self.git.Submodule.BulkDeinitCmdObj().ToString())}, + OnPress: func() error { + return self.c.WithWaitingStatus(self.c.Tr.LcRunningCommand, func() error { + self.c.LogAction(self.c.Tr.Actions.BulkDeinitialiseSubmodules) + if err := self.git.Submodule.BulkDeinitCmdObj().Run(); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}}) + }) + }, + }, + }, + }) +} + +func (self *SubmodulesController) update(submodule *models.SubmoduleConfig) error { + return self.c.WithWaitingStatus(self.c.Tr.LcUpdatingSubmoduleStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.UpdateSubmodule) + err := self.git.Submodule.Update(submodule.Path) + if err != nil { + _ = self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES}}) + }) +} + +func (self *SubmodulesController) remove(submodule *models.SubmoduleConfig) error { + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.RemoveSubmodule, + Prompt: fmt.Sprintf(self.c.Tr.RemoveSubmodulePrompt, submodule.Name), + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.RemoveSubmodule) + if err := self.git.Submodule.Delete(submodule); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.SUBMODULES, types.FILES}}) + }, + }) +} + +func (self *SubmodulesController) forSubmodule(callback func(*models.SubmoduleConfig) error) func() error { + return func() error { + submodule := self.getSelectedSubmodule() + if submodule == nil { + return nil + } + + return callback(submodule) + } +} diff --git a/pkg/gui/controllers/types.go b/pkg/gui/controllers/types.go new file mode 100644 index 000000000..75abc1704 --- /dev/null +++ b/pkg/gui/controllers/types.go @@ -0,0 +1,13 @@ +package controllers + +import ( + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type IGuiCommon interface { + popup.IPopupHandler + + LogAction(string) + Refresh(types.RefreshOptions) error +} diff --git a/pkg/gui/credentials_panel.go b/pkg/gui/credentials_panel.go index 984591a62..b7981338d 100644 --- a/pkg/gui/credentials_panel.go +++ b/pkg/gui/credentials_panel.go @@ -4,6 +4,7 @@ import ( "strings" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -48,15 +49,16 @@ func (gui *Gui) handleSubmitCredential() error { return err } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) } func (gui *Gui) handleCloseCredentialsView() error { + gui.Views.Credentials.ClearTextArea() gui.credentials <- "" return gui.returnFromContext() } -func (gui *Gui) handleCredentialsViewFocused() error { +func (gui *Gui) handleAskFocused() error { keybindingConfig := gui.UserConfig.Keybinding message := utils.ResolvePlaceholderString( @@ -69,18 +71,3 @@ func (gui *Gui) handleCredentialsViewFocused() error { return gui.renderString(gui.Views.Options, message) } - -// handleCredentialsPopup handles the views after executing a command that might ask for credentials -func (gui *Gui) handleCredentialsPopup(cmdErr error) { - if cmdErr != nil { - errMessage := cmdErr.Error() - if strings.Contains(errMessage, "Invalid username, password or passphrase") { - errMessage = gui.Tr.PassUnameWrong - } - _ = gui.returnFromContext() - // we are not logging this error because it may contain a password or a passphrase - _ = gui.createErrorPanel(errMessage) - } else { - _ = gui.closeConfirmationPrompt(false) - } -} diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index 02293dd65..44548ef72 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -12,7 +12,9 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/style" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -62,18 +64,18 @@ func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (s func (gui *Gui) inputPrompt(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error { title, err := gui.resolveTemplate(prompt.Title, promptResponses) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } initialValue, err := gui.resolveTemplate(prompt.InitialValue, promptResponses) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.prompt(promptOpts{ - title: title, - initialContent: initialValue, - handleConfirm: func(str string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: title, + InitialContent: initialValue, + HandleConfirm: func(str string) error { promptResponses[responseIdx] = str return wrappedF() }, @@ -82,7 +84,7 @@ func (gui *Gui) inputPrompt(prompt config.CustomCommandPrompt, promptResponses [ func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error { // need to make a menu here some how - menuItems := make([]*menuItem, len(prompt.Options)) + menuItems := make([]*popup.MenuItem, len(prompt.Options)) for i, option := range prompt.Options { option := option @@ -93,22 +95,22 @@ func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses [] } name, err := gui.resolveTemplate(nameTemplate, promptResponses) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } description, err := gui.resolveTemplate(option.Description, promptResponses) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } value, err := gui.resolveTemplate(option.Value, promptResponses) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - menuItems[i] = &menuItem{ - displayStrings: []string{name, style.FgYellow.Sprint(description)}, - onPress: func() error { + menuItems[i] = &popup.MenuItem{ + DisplayStrings: []string{name, style.FgYellow.Sprint(description)}, + OnPress: func() error { promptResponses[responseIdx] = value return wrappedF() }, @@ -117,30 +119,30 @@ func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses [] title, err := gui.resolveTemplate(prompt.Title, promptResponses) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.createMenu(title, menuItems, createMenuOptions{showCancel: true}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: title, Items: menuItems}) } func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, labelFormat string) ([]commandMenuEntry, error) { reg, err := regexp.Compile(filter) if err != nil { - return nil, gui.surfaceError(errors.New("unable to parse filter regex, error: " + err.Error())) + return nil, gui.PopupHandler.Error(errors.New("unable to parse filter regex, error: " + err.Error())) } buff := bytes.NewBuffer(nil) valueTemp, err := template.New("format").Parse(valueFormat) if err != nil { - return nil, gui.surfaceError(errors.New("unable to parse value format, error: " + err.Error())) + return nil, gui.PopupHandler.Error(errors.New("unable to parse value format, error: " + err.Error())) } colorFuncMap := style.TemplateFuncMapAddColors(template.FuncMap{}) descTemp, err := template.New("format").Funcs(colorFuncMap).Parse(labelFormat) if err != nil { - return nil, gui.surfaceError(errors.New("unable to parse label format, error: " + err.Error())) + return nil, gui.PopupHandler.Error(errors.New("unable to parse label format, error: " + err.Error())) } candidates := []commandMenuEntry{} @@ -165,7 +167,7 @@ func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, label err = valueTemp.Execute(buff, tmplData) if err != nil { - return candidates, gui.surfaceError(err) + return candidates, gui.PopupHandler.Error(err) } entry := commandMenuEntry{ value: strings.TrimSpace(buff.String()), @@ -175,7 +177,7 @@ func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, label buff.Reset() err = descTemp.Execute(buff, tmplData) if err != nil { - return candidates, gui.surfaceError(err) + return candidates, gui.PopupHandler.Error(err) } entry.label = strings.TrimSpace(buff.String()) } else { @@ -193,33 +195,33 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR // Collect cmd to run from config cmdStr, err := gui.resolveTemplate(prompt.Command, promptResponses) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } // Collect Filter regexp filter, err := gui.resolveTemplate(prompt.Filter, promptResponses) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } // Run and save output message, err := gui.Git.Custom.RunWithOutput(cmdStr) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } // Need to make a menu out of what the cmd has displayed candidates, err := gui.GenerateMenuCandidates(message, filter, prompt.ValueFormat, prompt.LabelFormat) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - menuItems := make([]*menuItem, len(candidates)) + menuItems := make([]*popup.MenuItem, len(candidates)) for i := range candidates { i := i - menuItems[i] = &menuItem{ - displayStrings: []string{candidates[i].label}, - onPress: func() error { + menuItems[i] = &popup.MenuItem{ + DisplayStrings: []string{candidates[i].label}, + OnPress: func() error { promptResponses[responseIdx] = candidates[i].value return wrappedF() }, @@ -228,10 +230,10 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR title, err := gui.resolveTemplate(prompt.Title, promptResponses) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.createMenu(title, menuItems, createMenuOptions{showCancel: true}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: title, Items: menuItems}) } func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand) func() error { @@ -241,7 +243,7 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand f := func() error { cmdStr, err := gui.resolveTemplate(customCommand.Command, promptResponses) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } if customCommand.Subprocess { @@ -252,7 +254,7 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand if loadingText == "" { loadingText = gui.Tr.LcRunningCustomCommandStatus } - return gui.WithWaitingStatus(loadingText, func() error { + return gui.PopupHandler.WithWaitingStatus(loadingText, func() error { gui.logAction(gui.Tr.Actions.CustomCommand) cmdObj := gui.OSCommand.Cmd.NewShell(cmdStr) if customCommand.Stream { @@ -260,9 +262,9 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand } err := cmdObj.Run() if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{}) + return gui.refreshSidePanels(types.RefreshOptions{}) }) } @@ -291,7 +293,7 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand return gui.menuPromptFromCommand(prompt, promptResponses, idx, wrappedF) } default: - return gui.createErrorPanel("custom command prompt must have a type of 'input', 'menu' or 'menuFromCommand'") + return gui.PopupHandler.ErrorMsg("custom command prompt must have a type of 'input', 'menu' or 'menuFromCommand'") } } @@ -300,8 +302,8 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand } } -func (gui *Gui) GetCustomCommandKeybindings() []*Binding { - bindings := []*Binding{} +func (gui *Gui) GetCustomCommandKeybindings() []*types.Binding { + bindings := []*types.Binding{} customCommands := gui.UserConfig.CustomCommands for _, customCommand := range customCommands { @@ -334,7 +336,7 @@ func (gui *Gui) GetCustomCommandKeybindings() []*Binding { description = customCommand.Command } - bindings = append(bindings, &Binding{ + bindings = append(bindings, &types.Binding{ ViewName: viewName, Contexts: contexts, Key: gui.getKey(customCommand.Key), diff --git a/pkg/gui/diff_context_size.go b/pkg/gui/diff_context_size.go index 3b6f6b0a9..e5ea340a6 100644 --- a/pkg/gui/diff_context_size.go +++ b/pkg/gui/diff_context_size.go @@ -28,7 +28,7 @@ func isShowingDiff(gui *Gui) bool { func (gui *Gui) IncreaseContextInDiffView() error { if isShowingDiff(gui) { if err := gui.CheckCanChangeContext(); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.UserConfig.Git.DiffContextSize = gui.UserConfig.Git.DiffContextSize + 1 @@ -43,7 +43,7 @@ func (gui *Gui) DecreaseContextInDiffView() error { if isShowingDiff(gui) && old_size > 1 { if err := gui.CheckCanChangeContext(); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.UserConfig.Git.DiffContextSize = old_size - 1 diff --git a/pkg/gui/diff_context_size_test.go b/pkg/gui/diff_context_size_test.go index b459e40d0..4f53cd3ff 100644 --- a/pkg/gui/diff_context_size_test.go +++ b/pkg/gui/diff_context_size_test.go @@ -5,6 +5,7 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/patch" + "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/stretchr/testify/assert" ) @@ -144,8 +145,8 @@ func TestDoesntIncreaseContextInDiffViewInContextWhenInPatchBuildingMode(t *test gui.Git.Patch.PatchManager.Start("from", "to", false, false) errorCount := 0 - gui.PopupHandler = &TestPopupHandler{ - onError: func(message string) error { + gui.PopupHandler = &popup.TestPopupHandler{ + OnErrorMsg: func(message string) error { assert.Equal(t, gui.Tr.CantChangeContextSizeError, message) errorCount += 1 return nil @@ -166,8 +167,8 @@ func TestDoesntDecreaseContextInDiffViewInContextWhenInPatchBuildingMode(t *test gui.Git.Patch.PatchManager.Start("from", "to", false, false) errorCount := 0 - gui.PopupHandler = &TestPopupHandler{ - onError: func(message string) error { + gui.PopupHandler = &popup.TestPopupHandler{ + OnErrorMsg: func(message string) error { assert.Equal(t, gui.Tr.CantChangeContextSizeError, message) errorCount += 1 return nil diff --git a/pkg/gui/diffing.go b/pkg/gui/diffing.go index 2721a1880..232f9130b 100644 --- a/pkg/gui/diffing.go +++ b/pkg/gui/diffing.go @@ -5,11 +5,13 @@ import ( "strings" "github.com/jesseduffield/lazygit/pkg/gui/modes/diffing" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) func (gui *Gui) exitDiffMode() error { gui.State.Modes.Diffing = diffing.New() - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) } func (gui *Gui) renderDiff() error { @@ -105,31 +107,31 @@ func (gui *Gui) diffStr() string { func (gui *Gui) handleCreateDiffingMenuPanel() error { names := gui.currentDiffTerminals() - menuItems := []*menuItem{} + menuItems := []*popup.MenuItem{} for _, name := range names { name := name - menuItems = append(menuItems, []*menuItem{ + menuItems = append(menuItems, []*popup.MenuItem{ { - displayString: fmt.Sprintf("%s %s", gui.Tr.LcDiff, name), - onPress: func() error { + DisplayString: fmt.Sprintf("%s %s", gui.Tr.LcDiff, name), + OnPress: func() error { gui.State.Modes.Diffing.Ref = name // can scope this down based on current view but too lazy right now - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) }, }, }...) } - menuItems = append(menuItems, []*menuItem{ + menuItems = append(menuItems, []*popup.MenuItem{ { - displayString: gui.Tr.LcEnterRefToDiff, - onPress: func() error { - return gui.prompt(promptOpts{ - title: gui.Tr.LcEnteRefName, - findSuggestionsFunc: gui.getRefsSuggestionsFunc(), - handleConfirm: func(response string) error { + DisplayString: gui.Tr.LcEnterRefToDiff, + OnPress: func() error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: gui.Tr.LcEnteRefName, + FindSuggestionsFunc: gui.getRefsSuggestionsFunc(), + HandleConfirm: func(response string) error { gui.State.Modes.Diffing.Ref = strings.TrimSpace(response) - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) }, }) }, @@ -137,23 +139,23 @@ func (gui *Gui) handleCreateDiffingMenuPanel() error { }...) if gui.State.Modes.Diffing.Active() { - menuItems = append(menuItems, []*menuItem{ + menuItems = append(menuItems, []*popup.MenuItem{ { - displayString: gui.Tr.LcSwapDiff, - onPress: func() error { + DisplayString: gui.Tr.LcSwapDiff, + OnPress: func() error { gui.State.Modes.Diffing.Reverse = !gui.State.Modes.Diffing.Reverse - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) }, }, { - displayString: gui.Tr.LcExitDiffMode, - onPress: func() error { + DisplayString: gui.Tr.LcExitDiffMode, + OnPress: func() error { gui.State.Modes.Diffing = diffing.New() - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) }, }, }...) } - return gui.createMenu(gui.Tr.DiffingMenuTitle, menuItems, createMenuOptions{showCancel: true}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: gui.Tr.DiffingMenuTitle, Items: menuItems}) } diff --git a/pkg/gui/discard_changes_menu_panel.go b/pkg/gui/discard_changes_menu_panel.go index 673f057e8..7624730e0 100644 --- a/pkg/gui/discard_changes_menu_panel.go +++ b/pkg/gui/discard_changes_menu_panel.go @@ -1,36 +1,41 @@ package gui +import ( + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + func (gui *Gui) handleCreateDiscardMenu() error { node := gui.getSelectedFileNode() if node == nil { return nil } - var menuItems []*menuItem + var menuItems []*popup.MenuItem if node.File == nil { - menuItems = []*menuItem{ + menuItems = []*popup.MenuItem{ { - displayString: gui.Tr.LcDiscardAllChanges, - onPress: func() error { + DisplayString: gui.Tr.LcDiscardAllChanges, + OnPress: func() error { gui.logAction(gui.Tr.Actions.DiscardAllChangesInDirectory) if err := gui.Git.WorkingTree.DiscardAllDirChanges(node); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, } if node.GetHasStagedChanges() && node.GetHasUnstagedChanges() { - menuItems = append(menuItems, &menuItem{ - displayString: gui.Tr.LcDiscardUnstagedChanges, - onPress: func() error { + menuItems = append(menuItems, &popup.MenuItem{ + DisplayString: gui.Tr.LcDiscardUnstagedChanges, + OnPress: func() error { gui.logAction(gui.Tr.Actions.DiscardUnstagedChangesInDirectory) if err := gui.Git.WorkingTree.DiscardUnstagedDirChanges(node); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }) } @@ -41,43 +46,43 @@ func (gui *Gui) handleCreateDiscardMenu() error { if file.IsSubmodule(submodules) { submodule := file.SubmoduleConfig(submodules) - menuItems = []*menuItem{ + menuItems = []*popup.MenuItem{ { - displayString: gui.Tr.LcSubmoduleStashAndReset, - onPress: func() error { - return gui.handleResetSubmodule(submodule) + DisplayString: gui.Tr.LcSubmoduleStashAndReset, + OnPress: func() error { + return gui.resetSubmodule(submodule) }, }, } } else { - menuItems = []*menuItem{ + menuItems = []*popup.MenuItem{ { - displayString: gui.Tr.LcDiscardAllChanges, - onPress: func() error { + DisplayString: gui.Tr.LcDiscardAllChanges, + OnPress: func() error { gui.logAction(gui.Tr.Actions.DiscardAllChangesInFile) if err := gui.Git.WorkingTree.DiscardAllFileChanges(file); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, } if file.HasStagedChanges && file.HasUnstagedChanges { - menuItems = append(menuItems, &menuItem{ - displayString: gui.Tr.LcDiscardUnstagedChanges, - onPress: func() error { + menuItems = append(menuItems, &popup.MenuItem{ + DisplayString: gui.Tr.LcDiscardUnstagedChanges, + OnPress: func() error { gui.logAction(gui.Tr.Actions.DiscardAllUnstagedChangesInFile) if err := gui.Git.WorkingTree.DiscardUnstagedFileChanges(file); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }) } } } - return gui.createMenu(node.GetPath(), menuItems, createMenuOptions{showCancel: true}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: node.GetPath(), Items: menuItems}) } diff --git a/pkg/gui/extras_panel.go b/pkg/gui/extras_panel.go index 7d68bb1ec..bd65dea87 100644 --- a/pkg/gui/extras_panel.go +++ b/pkg/gui/extras_panel.go @@ -3,34 +3,36 @@ package gui import ( "io" + "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/style" ) func (gui *Gui) handleCreateExtrasMenuPanel() error { - menuItems := []*menuItem{ - { - displayString: gui.Tr.ToggleShowCommandLog, - onPress: func() error { - currentContext := gui.currentStaticContext() - if gui.ShowExtrasWindow && currentContext.GetKey() == COMMAND_LOG_CONTEXT_KEY { - if err := gui.returnFromContext(); err != nil { - return err + return gui.PopupHandler.Menu(popup.CreateMenuOptions{ + Title: gui.Tr.CommandLog, + Items: []*popup.MenuItem{ + { + DisplayString: gui.Tr.ToggleShowCommandLog, + OnPress: func() error { + currentContext := gui.currentStaticContext() + if gui.ShowExtrasWindow && currentContext.GetKey() == COMMAND_LOG_CONTEXT_KEY { + if err := gui.returnFromContext(); err != nil { + return err + } } - } - show := !gui.ShowExtrasWindow - gui.ShowExtrasWindow = show - gui.Config.GetAppState().HideCommandLog = !show - _ = gui.Config.SaveAppState() - return nil + show := !gui.ShowExtrasWindow + gui.ShowExtrasWindow = show + gui.Config.GetAppState().HideCommandLog = !show + _ = gui.Config.SaveAppState() + return nil + }, + }, + { + DisplayString: gui.Tr.FocusCommandLog, + OnPress: gui.handleFocusCommandLog, }, }, - { - displayString: gui.Tr.FocusCommandLog, - onPress: gui.handleFocusCommandLog, - }, - } - - return gui.createMenu(gui.Tr.CommandLog, menuItems, createMenuOptions{showCancel: true}) + }) } func (gui *Gui) handleFocusCommandLog() error { diff --git a/pkg/gui/file_watching.go b/pkg/gui/file_watching.go index f5749a97d..9f4e84a0f 100644 --- a/pkg/gui/file_watching.go +++ b/pkg/gui/file_watching.go @@ -6,6 +6,7 @@ import ( "github.com/fsnotify/fsnotify" "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/sirupsen/logrus" ) @@ -117,7 +118,7 @@ func (gui *Gui) watchFilesForChanges() { } // only refresh if we're not already if !gui.State.IsRefreshingFiles { - _ = gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}}) + _ = gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) } // watch for errors diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index fa8cfa79c..b442a566f 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -12,6 +12,8 @@ import ( "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/mergeconflicts" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -67,7 +69,7 @@ func (gui *Gui) filesRenderToMain() error { gui.resetMergeStateWithLock() - cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(node, false, !node.GetHasUnstagedChanges() && node.GetHasStagedChanges(), gui.State.IgnoreWhitespaceInDiffView) + cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(node, false, !node.GetHasUnstagedChanges() && node.GetHasStagedChanges(), gui.IgnoreWhitespaceInDiffView) refreshOpts := refreshMainOpts{main: &viewUpdateOpts{ title: gui.Tr.UnstagedChanges, @@ -76,7 +78,7 @@ func (gui *Gui) filesRenderToMain() error { if node.GetHasUnstagedChanges() { if node.GetHasStagedChanges() { - cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(node, false, true, gui.State.IgnoreWhitespaceInDiffView) + cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(node, false, true, gui.IgnoreWhitespaceInDiffView) refreshOpts.secondary = &viewUpdateOpts{ title: gui.Tr.StagedChanges, @@ -191,7 +193,7 @@ func (gui *Gui) enterFile(opts OnFocusOpts) error { return gui.switchToMerge() } if file.HasMergeConflicts { - return gui.createErrorPanel(gui.Tr.FileStagingRequirements) + return gui.PopupHandler.ErrorMsg(gui.Tr.FileStagingRequirements) } return gui.pushContext(gui.State.Contexts.Staging, opts) @@ -213,36 +215,36 @@ func (gui *Gui) handleFilePress() error { if file.HasUnstagedChanges { gui.logAction(gui.Tr.Actions.StageFile) if err := gui.Git.WorkingTree.StageFile(file.Name); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } } else { gui.logAction(gui.Tr.Actions.UnstageFile) if err := gui.Git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } } } else { // if any files within have inline merge conflicts we can't stage or unstage, // or it'll end up with those >>>>>> lines actually staged if node.GetHasInlineMergeConflicts() { - return gui.createErrorPanel(gui.Tr.ErrStageDirWithInlineMergeConflicts) + return gui.PopupHandler.ErrorMsg(gui.Tr.ErrStageDirWithInlineMergeConflicts) } if node.GetHasUnstagedChanges() { gui.logAction(gui.Tr.Actions.StageFile) if err := gui.Git.WorkingTree.StageFile(node.Path); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } } else { // pretty sure it doesn't matter that we're always passing true here gui.logAction(gui.Tr.Actions.UnstageFile) if err := gui.Git.WorkingTree.UnStageFile([]string{node.Path}, true); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } } } - if err := gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}); err != nil { + if err := gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}); err != nil { return err } @@ -273,10 +275,10 @@ func (gui *Gui) handleStageAll() error { err = gui.Git.WorkingTree.StageAll() } if err != nil { - _ = gui.surfaceError(err) + _ = gui.PopupHandler.Error(err) } - if err := gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}); err != nil { + if err := gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}); err != nil { return err } @@ -290,7 +292,7 @@ func (gui *Gui) handleIgnoreFile() error { } if node.GetPath() == ".gitignore" { - return gui.createErrorPanel("Cannot ignore .gitignore") + return gui.PopupHandler.ErrorMsg("Cannot ignore .gitignore") } unstageFiles := func() error { @@ -306,10 +308,10 @@ func (gui *Gui) handleIgnoreFile() error { } if node.GetIsTracked() { - return gui.ask(askOpts{ - title: gui.Tr.IgnoreTracked, - prompt: gui.Tr.IgnoreTrackedPrompt, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.IgnoreTracked, + Prompt: gui.Tr.IgnoreTrackedPrompt, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.IgnoreFile) // not 100% sure if this is necessary but I'll assume it is if err := unstageFiles(); err != nil { @@ -323,7 +325,7 @@ func (gui *Gui) handleIgnoreFile() error { if err := gui.Git.WorkingTree.Ignore(node.GetPath()); err != nil { return err } - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}) }, }) } @@ -335,16 +337,16 @@ func (gui *Gui) handleIgnoreFile() error { } if err := gui.Git.WorkingTree.Ignore(node.GetPath()); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}) } func (gui *Gui) handleWIPCommitPress() error { skipHookPrefix := gui.UserConfig.Git.SkipHookPrefix if skipHookPrefix == "" { - return gui.createErrorPanel(gui.Tr.SkipHookPrefixNotConfigured) + return gui.PopupHandler.ErrorMsg(gui.Tr.SkipHookPrefixNotConfigured) } textArea := gui.Views.CommitMessage.TextArea @@ -381,11 +383,11 @@ func (gui *Gui) prepareFilesForCommit() error { func (gui *Gui) handleCommitPress() error { if err := gui.prepareFilesForCommit(); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } if gui.State.FileTreeViewModel.GetItemsLength() == 0 { - return gui.createErrorPanel(gui.Tr.NoFilesStagedTitle) + return gui.PopupHandler.ErrorMsg(gui.Tr.NoFilesStagedTitle) } if len(gui.stagedFiles()) == 0 { @@ -403,7 +405,7 @@ func (gui *Gui) handleCommitPress() error { prefixReplace := commitPrefixConfig.Replace rgx, err := regexp.Compile(prefixPattern) if err != nil { - return gui.createErrorPanel(fmt.Sprintf("%s: %s", gui.Tr.LcCommitPrefixPatternError, err.Error())) + return gui.PopupHandler.ErrorMsg(fmt.Sprintf("%s: %s", gui.Tr.LcCommitPrefixPatternError, err.Error())) } prefix := rgx.ReplaceAllString(gui.getCheckedOutBranch().Name, prefixReplace) gui.Views.CommitMessage.ClearTextArea() @@ -421,16 +423,16 @@ func (gui *Gui) handleCommitPress() error { } func (gui *Gui) promptToStageAllAndRetry(retry func() error) error { - return gui.ask(askOpts{ - title: gui.Tr.NoFilesStagedTitle, - prompt: gui.Tr.NoFilesStagedPrompt, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.NoFilesStagedTitle, + Prompt: gui.Tr.NoFilesStagedPrompt, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.StageAllFiles) if err := gui.Git.WorkingTree.StageAll(); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } if err := gui.refreshFilesAndSubmodules(); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return retry() @@ -440,7 +442,7 @@ func (gui *Gui) promptToStageAllAndRetry(retry func() error) error { func (gui *Gui) handleAmendCommitPress() error { if gui.State.FileTreeViewModel.GetItemsLength() == 0 { - return gui.createErrorPanel(gui.Tr.NoFilesStagedTitle) + return gui.PopupHandler.ErrorMsg(gui.Tr.NoFilesStagedTitle) } if len(gui.stagedFiles()) == 0 { @@ -448,13 +450,13 @@ func (gui *Gui) handleAmendCommitPress() error { } if len(gui.State.Commits) == 0 { - return gui.createErrorPanel(gui.Tr.NoCommitToAmend) + return gui.PopupHandler.ErrorMsg(gui.Tr.NoCommitToAmend) } - return gui.ask(askOpts{ - title: strings.Title(gui.Tr.AmendLastCommit), - prompt: gui.Tr.SureToAmend, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: strings.Title(gui.Tr.AmendLastCommit), + Prompt: gui.Tr.SureToAmend, + HandleConfirm: func() error { cmdObj := gui.Git.Commit.AmendHeadCmdObj() gui.logAction(gui.Tr.Actions.AmendCommit) return gui.withGpgHandling(cmdObj, gui.Tr.AmendingStatus, nil) @@ -466,7 +468,7 @@ func (gui *Gui) handleAmendCommitPress() error { // their editor rather than via the popup panel func (gui *Gui) handleCommitEditorPress() error { if gui.State.FileTreeViewModel.GetItemsLength() == 0 { - return gui.createErrorPanel(gui.Tr.NoFilesStagedTitle) + return gui.PopupHandler.ErrorMsg(gui.Tr.NoFilesStagedTitle) } if len(gui.stagedFiles()) == 0 { @@ -480,28 +482,29 @@ func (gui *Gui) handleCommitEditorPress() error { } func (gui *Gui) handleStatusFilterPressed() error { - menuItems := []*menuItem{ - { - displayString: gui.Tr.FilterStagedFiles, - onPress: func() error { - return gui.setStatusFiltering(filetree.DisplayStaged) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{ + Title: gui.Tr.FilteringMenuTitle, + Items: []*popup.MenuItem{ + { + DisplayString: gui.Tr.FilterStagedFiles, + OnPress: func() error { + return gui.setStatusFiltering(filetree.DisplayStaged) + }, + }, + { + DisplayString: gui.Tr.FilterUnstagedFiles, + OnPress: func() error { + return gui.setStatusFiltering(filetree.DisplayUnstaged) + }, + }, + { + DisplayString: gui.Tr.ResetCommitFilterState, + OnPress: func() error { + return gui.setStatusFiltering(filetree.DisplayAll) + }, }, }, - { - displayString: gui.Tr.FilterUnstagedFiles, - onPress: func() error { - return gui.setStatusFiltering(filetree.DisplayUnstaged) - }, - }, - { - displayString: gui.Tr.ResetCommitFilterState, - onPress: func() error { - return gui.setStatusFiltering(filetree.DisplayAll) - }, - }, - } - - return gui.createMenu(gui.Tr.FilteringMenuTitle, menuItems, createMenuOptions{showCancel: true}) + }) } func (gui *Gui) setStatusFiltering(filter filetree.FileTreeDisplayFilter) error { @@ -517,7 +520,7 @@ func (gui *Gui) editFile(filename string) error { func (gui *Gui) editFileAtLine(filename string, lineNumber int) error { cmdStr, err := gui.Git.File.GetEditCmdStr(filename, lineNumber) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.logAction(gui.Tr.Actions.EditFile) @@ -533,7 +536,7 @@ func (gui *Gui) handleFileEdit() error { } if node.File == nil { - return gui.createErrorPanel(gui.Tr.ErrCannotEditDirectory) + return gui.PopupHandler.ErrorMsg(gui.Tr.ErrCannotEditDirectory) } return gui.editFile(node.GetPath()) @@ -549,7 +552,7 @@ func (gui *Gui) handleFileOpen() error { } func (gui *Gui) handleRefreshFiles() error { - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}) } func (gui *Gui) refreshStateFiles() error { @@ -666,10 +669,10 @@ func (gui *Gui) refreshStateFiles() error { func (gui *Gui) promptToContinueRebase() error { gui.takeOverMergeConflictScrolling() - return gui.ask(askOpts{ - title: "continue", - prompt: gui.Tr.ConflictsResolved, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: "continue", + Prompt: gui.Tr.ConflictsResolved, + HandleConfirm: func() error { return gui.genericMergeCommand(REBASE_OPTION_CONTINUE) }, }) @@ -730,15 +733,15 @@ func (gui *Gui) handlePullFiles() error { if !currentBranch.IsTrackingRemote() { suggestedRemote := getSuggestedRemote(gui.State.Remotes) - return gui.prompt(promptOpts{ - title: gui.Tr.EnterUpstream, - initialContent: suggestedRemote + " " + currentBranch.Name, - findSuggestionsFunc: gui.getRemoteBranchesSuggestionsFunc(" "), - handleConfirm: func(upstream string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: gui.Tr.EnterUpstream, + InitialContent: suggestedRemote + " " + currentBranch.Name, + FindSuggestionsFunc: gui.getRemoteBranchesSuggestionsFunc(" "), + HandleConfirm: func(upstream string) error { var upstreamBranch, upstreamRemote string split := strings.Split(upstream, " ") if len(split) != 2 { - return gui.createErrorPanel(gui.Tr.InvalidUpstream) + return gui.PopupHandler.ErrorMsg(gui.Tr.InvalidUpstream) } upstreamRemote = split[0] @@ -749,7 +752,7 @@ func (gui *Gui) handlePullFiles() error { if strings.Contains(errorMessage, "does not exist") { errorMessage = fmt.Sprintf("upstream branch %s not found.\nIf you expect it to exist, you should fetch (with 'f').\nOtherwise, you should push (with 'shift+P')", upstream) } - return gui.createErrorPanel(errorMessage) + return gui.PopupHandler.ErrorMsg(errorMessage) } return gui.pullFiles(PullFilesOptions{UpstreamRemote: upstreamRemote, UpstreamBranch: upstreamBranch, action: action}) }, @@ -767,14 +770,9 @@ type PullFilesOptions struct { } func (gui *Gui) pullFiles(opts PullFilesOptions) error { - if err := gui.createLoaderPanel(gui.Tr.PullWait); err != nil { - return err - } - - // TODO: this doesn't look like a good idea. Why the goroutine? - go utils.Safe(func() { _ = gui.pullWithLock(opts) }) - - return nil + return gui.PopupHandler.WithLoaderPanel(gui.Tr.PullWait, func() error { + return gui.pullWithLock(opts) + }) } func (gui *Gui) pullWithLock(opts PullFilesOptions) error { @@ -804,10 +802,7 @@ type pushOpts struct { } func (gui *Gui) push(opts pushOpts) error { - if err := gui.createLoaderPanel(gui.Tr.PushWait); err != nil { - return err - } - go utils.Safe(func() { + return gui.PopupHandler.WithLoaderPanel(gui.Tr.PushWait, func() error { gui.logAction(gui.Tr.Actions.Push) err := gui.Git.Sync.Push(git_commands.PushOpts{ Force: opts.force, @@ -816,28 +811,29 @@ func (gui *Gui) push(opts pushOpts) error { SetUpstream: opts.setUpstream, }) - if err != nil && !opts.force && strings.Contains(err.Error(), "Updates were rejected") { - forcePushDisabled := gui.UserConfig.Git.DisableForcePushing - if forcePushDisabled { - _ = gui.createErrorPanel(gui.Tr.UpdatesRejectedAndForcePushDisabled) - return - } - _ = gui.ask(askOpts{ - title: gui.Tr.ForcePush, - prompt: gui.Tr.ForcePushPrompt, - handleConfirm: func() error { - newOpts := opts - newOpts.force = true + if err != nil { + if !opts.force && strings.Contains(err.Error(), "Updates were rejected") { + forcePushDisabled := gui.UserConfig.Git.DisableForcePushing + if forcePushDisabled { + _ = gui.PopupHandler.ErrorMsg(gui.Tr.UpdatesRejectedAndForcePushDisabled) + return nil + } + _ = gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.ForcePush, + Prompt: gui.Tr.ForcePushPrompt, + HandleConfirm: func() error { + newOpts := opts + newOpts.force = true - return gui.push(newOpts) - }, - }) - return + return gui.push(newOpts) + }, + }) + return nil + } + _ = gui.PopupHandler.Error(err) } - gui.handleCredentialsPopup(err) - _ = gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) }) - return nil } func (gui *Gui) pushFiles() error { @@ -870,11 +866,11 @@ func (gui *Gui) pushFiles() error { if gui.Git.Config.GetPushToCurrent() { return gui.push(pushOpts{setUpstream: true}) } else { - return gui.prompt(promptOpts{ - title: gui.Tr.EnterUpstream, - initialContent: suggestedRemote + " " + currentBranch.Name, - findSuggestionsFunc: gui.getRemoteBranchesSuggestionsFunc(" "), - handleConfirm: func(upstream string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: gui.Tr.EnterUpstream, + InitialContent: suggestedRemote + " " + currentBranch.Name, + FindSuggestionsFunc: gui.getRemoteBranchesSuggestionsFunc(" "), + HandleConfirm: func(upstream string) error { var upstreamBranch, upstreamRemote string split := strings.Split(upstream, " ") if len(split) == 2 { @@ -914,13 +910,13 @@ func getSuggestedRemote(remotes []*models.Remote) string { func (gui *Gui) requestToForcePush(opts pushOpts) error { forcePushDisabled := gui.UserConfig.Git.DisableForcePushing if forcePushDisabled { - return gui.createErrorPanel(gui.Tr.ForcePushDisabled) + return gui.PopupHandler.ErrorMsg(gui.Tr.ForcePushDisabled) } - return gui.ask(askOpts{ - title: gui.Tr.ForcePush, - prompt: gui.Tr.ForcePushPrompt, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.ForcePush, + Prompt: gui.Tr.ForcePushPrompt, + HandleConfirm: func() error { return gui.push(opts) }, }) @@ -950,16 +946,16 @@ func (gui *Gui) switchToMerge() error { func (gui *Gui) openFile(filename string) error { gui.logAction(gui.Tr.Actions.OpenFile) if err := gui.OSCommand.OpenFile(filename); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return nil } func (gui *Gui) handleCustomCommand() error { - return gui.prompt(promptOpts{ - title: gui.Tr.CustomCommand, - findSuggestionsFunc: gui.getCustomCommandsHistorySuggestionsFunc(), - handleConfirm: func(command string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: gui.Tr.CustomCommand, + FindSuggestionsFunc: gui.getCustomCommandsHistorySuggestionsFunc(), + HandleConfirm: func(command string) error { gui.Config.GetAppState().CustomCommandsHistory = utils.Limit( utils.Uniq( append(gui.Config.GetAppState().CustomCommandsHistory, command), @@ -981,24 +977,25 @@ func (gui *Gui) handleCustomCommand() error { } func (gui *Gui) handleCreateStashMenu() error { - menuItems := []*menuItem{ - { - displayString: gui.Tr.LcStashAllChanges, - onPress: func() error { - gui.logAction(gui.Tr.Actions.StashAllChanges) - return gui.handleStashSave(gui.Git.Stash.Save) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{ + Title: gui.Tr.LcStashOptions, + Items: []*popup.MenuItem{ + { + DisplayString: gui.Tr.LcStashAllChanges, + OnPress: func() error { + gui.logAction(gui.Tr.Actions.StashAllChanges) + return gui.handleStashSave(gui.Git.Stash.Save) + }, + }, + { + DisplayString: gui.Tr.LcStashStagedChanges, + OnPress: func() error { + gui.logAction(gui.Tr.Actions.StashStagedChanges) + return gui.handleStashSave(gui.Git.Stash.SaveStagedChanges) + }, }, }, - { - displayString: gui.Tr.LcStashStagedChanges, - onPress: func() error { - gui.logAction(gui.Tr.Actions.StashStagedChanges) - return gui.handleStashSave(gui.Git.Stash.SaveStagedChanges) - }, - }, - } - - return gui.createMenu(gui.Tr.LcStashOptions, menuItems, createMenuOptions{showCancel: true}) + }) } func (gui *Gui) handleStashChanges() error { @@ -1052,10 +1049,10 @@ func (gui *Gui) handleToggleFileTreeView() error { } func (gui *Gui) handleOpenMergeTool() error { - return gui.ask(askOpts{ - title: gui.Tr.MergeToolTitle, - prompt: gui.Tr.MergeToolPrompt, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.MergeToolTitle, + Prompt: gui.Tr.MergeToolPrompt, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.OpenMergeTool) return gui.runSubprocessWithSuspenseAndRefresh( gui.Git.WorkingTree.OpenMergeToolCmdObj(), @@ -1063,3 +1060,35 @@ func (gui *Gui) handleOpenMergeTool() error { }, }) } + +func (gui *Gui) resetSubmodule(submodule *models.SubmoduleConfig) error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.LcResettingSubmoduleStatus, func() error { + gui.logAction(gui.Tr.Actions.ResetSubmodule) + + file := gui.fileForSubmodule(submodule) + if file != nil { + if err := gui.Git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil { + return gui.PopupHandler.Error(err) + } + } + + if err := gui.Git.Submodule.Stash(submodule); err != nil { + return gui.PopupHandler.Error(err) + } + if err := gui.Git.Submodule.Reset(submodule); err != nil { + return gui.PopupHandler.Error(err) + } + + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.SUBMODULES}}) + }) +} + +func (gui *Gui) fileForSubmodule(submodule *models.SubmoduleConfig) *models.File { + for _, file := range gui.State.FileManager.GetAllFiles() { + if file.IsSubmodule([]*models.SubmoduleConfig{submodule}) { + return file + } + } + + return nil +} diff --git a/pkg/gui/filtering.go b/pkg/gui/filtering.go index 1f5c5032a..df007b69a 100644 --- a/pkg/gui/filtering.go +++ b/pkg/gui/filtering.go @@ -1,11 +1,16 @@ package gui +import ( + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + func (gui *Gui) validateNotInFilterMode() (bool, error) { if gui.State.Modes.Filtering.Active() { - err := gui.ask(askOpts{ - title: gui.Tr.MustExitFilterModeTitle, - prompt: gui.Tr.MustExitFilterModePrompt, - handleConfirm: gui.exitFilterMode, + err := gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.MustExitFilterModeTitle, + Prompt: gui.Tr.MustExitFilterModePrompt, + HandleConfirm: gui.exitFilterMode, }) return false, err @@ -23,7 +28,7 @@ func (gui *Gui) clearFiltering() error { gui.State.ScreenMode = SCREEN_NORMAL } - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{COMMITS}}) + return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}}) } func (gui *Gui) setFiltering(path string) error { @@ -36,7 +41,7 @@ func (gui *Gui) setFiltering(path string) error { return err } - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{COMMITS}, then: func() { + return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}, Then: func() { gui.State.Contexts.BranchCommits.GetPanelState().SetSelectedLineIdx(0) }}) } diff --git a/pkg/gui/filtering_menu_panel.go b/pkg/gui/filtering_menu_panel.go index 2955f6e8d..dcdf1ec40 100644 --- a/pkg/gui/filtering_menu_panel.go +++ b/pkg/gui/filtering_menu_panel.go @@ -3,6 +3,8 @@ package gui import ( "fmt" "strings" + + "github.com/jesseduffield/lazygit/pkg/gui/popup" ) func (gui *Gui) handleCreateFilteringMenuPanel() error { @@ -20,24 +22,24 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error { } } - menuItems := []*menuItem{} + menuItems := []*popup.MenuItem{} if fileName != "" { - menuItems = append(menuItems, &menuItem{ - displayString: fmt.Sprintf("%s '%s'", gui.Tr.LcFilterBy, fileName), - onPress: func() error { + menuItems = append(menuItems, &popup.MenuItem{ + DisplayString: fmt.Sprintf("%s '%s'", gui.Tr.LcFilterBy, fileName), + OnPress: func() error { return gui.setFiltering(fileName) }, }) } - menuItems = append(menuItems, &menuItem{ - displayString: gui.Tr.LcFilterPathOption, - onPress: func() error { - return gui.prompt(promptOpts{ - findSuggestionsFunc: gui.getFilePathSuggestionsFunc(), - title: gui.Tr.EnterFileName, - handleConfirm: func(response string) error { + menuItems = append(menuItems, &popup.MenuItem{ + DisplayString: gui.Tr.LcFilterPathOption, + OnPress: func() error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + FindSuggestionsFunc: gui.getFilePathSuggestionsFunc(), + Title: gui.Tr.EnterFileName, + HandleConfirm: func(response string) error { return gui.setFiltering(strings.TrimSpace(response)) }, }) @@ -45,11 +47,11 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error { }) if gui.State.Modes.Filtering.Active() { - menuItems = append(menuItems, &menuItem{ - displayString: gui.Tr.LcExitFilterMode, - onPress: gui.clearFiltering, + menuItems = append(menuItems, &popup.MenuItem{ + DisplayString: gui.Tr.LcExitFilterMode, + OnPress: gui.clearFiltering, }) } - return gui.createMenu(gui.Tr.FilteringMenuTitle, menuItems, createMenuOptions{showCancel: true}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: gui.Tr.FilteringMenuTitle, Items: menuItems}) } diff --git a/pkg/gui/find_suggestions.go b/pkg/gui/find_suggestions.go index 343e087e8..75215d673 100644 --- a/pkg/gui/find_suggestions.go +++ b/pkg/gui/find_suggestions.go @@ -84,7 +84,7 @@ func (gui *Gui) getBranchNameSuggestionsFunc() func(string) []*types.Suggestion // Notably, unlike other suggestion functions we're not showing all the options // if nothing has been typed because there'll be too much to display efficiently func (gui *Gui) getFilePathSuggestionsFunc() func(string) []*types.Suggestion { - _ = gui.WithWaitingStatus(gui.Tr.LcLoadingFileSuggestions, func() error { + _ = gui.PopupHandler.WithWaitingStatus(gui.Tr.LcLoadingFileSuggestions, func() error { trie := patricia.NewTrie() // load every non-gitignored file in the repo ignore, err := gitignore.FromGit() diff --git a/pkg/gui/git_flow.go b/pkg/gui/git_flow.go index e89c7637c..ab58adfe8 100644 --- a/pkg/gui/git_flow.go +++ b/pkg/gui/git_flow.go @@ -3,6 +3,7 @@ package gui import ( "fmt" + "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -13,16 +14,16 @@ func (gui *Gui) handleCreateGitFlowMenu() error { } if !gui.Git.Flow.GitFlowEnabled() { - return gui.createErrorPanel("You need to install git-flow and enable it in this repo to use git-flow features") + return gui.PopupHandler.ErrorMsg("You need to install git-flow and enable it in this repo to use git-flow features") } startHandler := func(branchType string) func() error { return func() error { title := utils.ResolvePlaceholderString(gui.Tr.NewGitFlowBranchPrompt, map[string]string{"branchType": branchType}) - return gui.prompt(promptOpts{ - title: title, - handleConfirm: func(name string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: title, + HandleConfirm: func(name string) error { gui.logAction(gui.Tr.Actions.GitFlowStart) return gui.runSubprocessWithSuspenseAndRefresh( gui.Git.Flow.StartCmdObj(branchType, name), @@ -32,39 +33,40 @@ func (gui *Gui) handleCreateGitFlowMenu() error { } } - menuItems := []*menuItem{ - { - // not localising here because it's one to one with the actual git flow commands - displayString: fmt.Sprintf("finish branch '%s'", branch.Name), - onPress: func() error { - return gui.gitFlowFinishBranch(branch.Name) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{ + Title: "git flow", + Items: []*popup.MenuItem{ + { + // not localising here because it's one to one with the actual git flow commands + DisplayString: fmt.Sprintf("finish branch '%s'", branch.Name), + OnPress: func() error { + return gui.gitFlowFinishBranch(branch.Name) + }, + }, + { + DisplayString: "start feature", + OnPress: startHandler("feature"), + }, + { + DisplayString: "start hotfix", + OnPress: startHandler("hotfix"), + }, + { + DisplayString: "start bugfix", + OnPress: startHandler("bugfix"), + }, + { + DisplayString: "start release", + OnPress: startHandler("release"), }, }, - { - displayString: "start feature", - onPress: startHandler("feature"), - }, - { - displayString: "start hotfix", - onPress: startHandler("hotfix"), - }, - { - displayString: "start bugfix", - onPress: startHandler("bugfix"), - }, - { - displayString: "start release", - onPress: startHandler("release"), - }, - } - - return gui.createMenu("git flow", menuItems, createMenuOptions{}) + }) } func (gui *Gui) gitFlowFinishBranch(branchName string) error { cmdObj, err := gui.Git.Flow.FinishCmdObj(branchName) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.logAction(gui.Tr.Actions.GitFlowFinish) diff --git a/pkg/gui/global_handlers.go b/pkg/gui/global_handlers.go index 22b43b6b7..1b4394519 100644 --- a/pkg/gui/global_handlers.go +++ b/pkg/gui/global_handlers.go @@ -7,6 +7,7 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -176,7 +177,7 @@ func (gui *Gui) scrollDownConfirmationPanel() error { } func (gui *Gui) handleRefresh() error { - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) } func (gui *Gui) handleMouseDownMain() error { @@ -218,10 +219,10 @@ func (gui *Gui) fetch() (err error) { err = gui.Git.Sync.Fetch(git_commands.FetchOptions{}) if err != nil && strings.Contains(err.Error(), "exit status 128") { - _ = gui.createErrorPanel(gui.Tr.PassUnameWrong) + _ = gui.PopupHandler.ErrorMsg(gui.Tr.PassUnameWrong) } - _ = gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{BRANCHES, COMMITS, REMOTES, TAGS}, mode: ASYNC}) + _ = gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.ASYNC}) return err } @@ -232,7 +233,7 @@ func (gui *Gui) backgroundFetch() (err error) { err = gui.Git.Sync.Fetch(git_commands.FetchOptions{Background: true}) - _ = gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{BRANCHES, COMMITS, REMOTES, TAGS}, mode: ASYNC}) + _ = gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.ASYNC}) return err } @@ -247,7 +248,7 @@ func (gui *Gui) handleCopySelectedSideContextItemToClipboard() error { gui.logAction(gui.Tr.Actions.CopyToClipboard) if err := gui.OSCommand.CopyToClipboard(itemId); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } truncatedItemId := utils.TruncateWithEllipsis(strings.Replace(itemId, "\n", " ", -1), 50) diff --git a/pkg/gui/gpg.go b/pkg/gui/gpg.go index ca7e4b842..1384055bc 100644 --- a/pkg/gui/gpg.go +++ b/pkg/gui/gpg.go @@ -5,6 +5,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/gui/style" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) // Currently there is a bug where if we switch to a subprocess from within @@ -23,7 +24,7 @@ func (gui *Gui) withGpgHandling(cmdObj oscommands.ICmdObj, waitingStatus string, return err } } - if err := gui.refreshSidePanels(refreshOptions{mode: ASYNC}); err != nil { + if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}); err != nil { return err } @@ -34,7 +35,7 @@ func (gui *Gui) withGpgHandling(cmdObj oscommands.ICmdObj, waitingStatus string, } func (gui *Gui) RunAndStream(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error { - return gui.WithWaitingStatus(waitingStatus, func() error { + return gui.PopupHandler.WithWaitingStatus(waitingStatus, func() error { cmdObj := gui.OSCommand.Cmd.NewShell(cmdObj.ToString()) cmdObj.AddEnvVars("TERM=dumb") cmdWriter := gui.getCmdWriter() @@ -46,8 +47,8 @@ func (gui *Gui) RunAndStream(cmdObj oscommands.ICmdObj, waitingStatus string, on if _, err := cmd.Stdout.Write([]byte(fmt.Sprintf("%s\n", style.FgRed.Sprint(err.Error())))); err != nil { gui.Log.Error(err) } - _ = gui.refreshSidePanels(refreshOptions{mode: ASYNC}) - return gui.surfaceError( + _ = gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.PopupHandler.Error( fmt.Errorf( gui.Tr.GitCommandFailed, gui.UserConfig.Keybinding.Universal.ExtrasMenu, ), @@ -60,6 +61,6 @@ func (gui *Gui) RunAndStream(cmdObj oscommands.ICmdObj, waitingStatus string, on } } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) }) } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 981a81987..2bfd7f2ac 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -18,6 +18,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/lbl" "github.com/jesseduffield/lazygit/pkg/gui/mergeconflicts" @@ -75,11 +76,11 @@ type Gui struct { OSCommand *oscommands.OSCommand // this is the state of the GUI for the current repo - State *guiState + State *GuiRepoState // this is a mapping of repos to gui states, so that we can restore the original // gui state when returning from a subrepo - RepoStateMap map[Repo]*guiState + RepoStateMap map[Repo]*GuiRepoState Config config.AppConfigurer Updater *updates.Updater statusManager *statusManager @@ -101,7 +102,7 @@ type Gui struct { // when you enter into a submodule we'll append the superproject's path to this array // so that you can return to the superproject - RepoPathStack []string + RepoPathStack *utils.StringStack // this tells us whether our views have been initially set up ViewsSetup bool @@ -121,10 +122,21 @@ type Gui struct { suggestionsAsyncHandler *tasks.AsyncHandler - PopupHandler PopupHandler + PopupHandler popup.IPopupHandler IsNewRepo bool + Controllers Controllers + + // flag as to whether or not the diff view should ignore whitespace + IgnoreWhitespaceInDiffView bool + + // if this is true, we'll load our commits using `git log --all` + ShowWholeGitGraph bool + RetainOriginalDir bool + + PrevLayout PrevLayout + // this is the initial dir we are in upon opening lazygit. We hold onto this // in case we want to restore it before quitting for users who have set up // the feature for changing directory upon quit. @@ -134,6 +146,80 @@ type Gui struct { InitialDir string } +// we keep track of some stuff from one render to the next to see if certain +// things have changed +type PrevLayout struct { + Information string + MainWidth int + MainHeight int +} + +type GuiRepoState struct { + // the file panels (files and commit files) can render as a tree, so we have + // managers for them which handle rendering a flat list of files in tree form + FileTreeViewModel *filetree.FileTreeViewModel + CommitFileTreeViewModel *filetree.CommitFileTreeViewModel + Submodules []*models.SubmoduleConfig + Branches []*models.Branch + Commits []*models.Commit + StashEntries []*models.StashEntry + SubCommits []*models.Commit + Remotes []*models.Remote + RemoteBranches []*models.RemoteBranch + Tags []*models.Tag + // FilteredReflogCommits are the ones that appear in the reflog panel. + // when in filtering mode we only include the ones that match the given path + FilteredReflogCommits []*models.Commit + // ReflogCommits are the ones used by the branches panel to obtain recency values + // if we're not in filtering mode, CommitFiles and FilteredReflogCommits will be + // one and the same + ReflogCommits []*models.Commit + + // Suggestions will sometimes appear when typing into a prompt + Suggestions []*types.Suggestion + MenuItems []*popup.MenuItem + BisectInfo *git_commands.BisectInfo + Updating bool + Panels *panelStates + SplitMainPanel bool + MainContext ContextKey // used to keep the main and secondary views' contexts in sync + + IsRefreshingFiles bool + Searching searchingState + Ptmx *os.File + StartupStage StartupStage // Allows us to not load everything at once + + Modes Modes + + ContextManager ContextManager + Contexts ContextTree + ViewContextMap map[string]Context + ViewTabContextMap map[string][]tabContext + + // WindowViewNameMap is a mapping of windows to the current view of that window. + // Some views move between windows for example the commitFiles view and when cycling through + // side windows we need to know which view to give focus to for a given window + WindowViewNameMap map[string]string + + // tells us whether we've set up our views for the current repo. We'll need to + // do this whenever we switch back and forth between repos to get the views + // back in sync with the repo state + ViewsSetup bool + + // for displaying suggestions while typing in a file name + FilesTrie *patricia.Trie + + // this is the message of the last failed commit attempt + failedCommitMessage string + + // TODO: move these into the gui struct + ScreenMode WindowMaximisation +} + +type Controllers struct { + Submodules *controllers.SubmodulesController +} + type listPanelState struct { SelectedLineIdx int } @@ -296,75 +382,6 @@ type guiMutexes struct { SubprocessMutex sync.Mutex } -type guiState struct { - // the file panels (files and commit files) can render as a tree, so we have - // managers for them which handle rendering a flat list of files in tree form - FileTreeViewModel *filetree.FileTreeViewModel - CommitFileTreeViewModel *filetree.CommitFileTreeViewModel - - Submodules []*models.SubmoduleConfig - Branches []*models.Branch - Commits []*models.Commit - StashEntries []*models.StashEntry - // Suggestions will sometimes appear when typing into a prompt - Suggestions []*types.Suggestion - // FilteredReflogCommits are the ones that appear in the reflog panel. - // when in filtering mode we only include the ones that match the given path - FilteredReflogCommits []*models.Commit - // ReflogCommits are the ones used by the branches panel to obtain recency values - // if we're not in filtering mode, CommitFiles and FilteredReflogCommits will be - // one and the same - ReflogCommits []*models.Commit - SubCommits []*models.Commit - Remotes []*models.Remote - RemoteBranches []*models.RemoteBranch - Tags []*models.Tag - MenuItems []*menuItem - BisectInfo *git_commands.BisectInfo - - Updating bool - Panels *panelStates - SplitMainPanel bool - MainContext ContextKey // used to keep the main and secondary views' contexts in sync - RetainOriginalDir bool - IsRefreshingFiles bool - Searching searchingState - // if this is true, we'll load our commits using `git log --all` - ShowWholeGitGraph bool - ScreenMode WindowMaximisation - Ptmx *os.File - PrevMainWidth int - PrevMainHeight int - OldInformation string - StartupStage StartupStage // Allows us to not load everything at once - - Modes Modes - - ContextManager ContextManager - Contexts ContextTree - ViewContextMap map[string]Context - ViewTabContextMap map[string][]tabContext - - // WindowViewNameMap is a mapping of windows to the current view of that window. - // Some views move between windows for example the commitFiles view and when cycling through - // side windows we need to know which view to give focus to for a given window - WindowViewNameMap map[string]string - - // tells us whether we've set up our views for the current repo. We'll need to - // do this whenever we switch back and forth between repos to get the views - // back in sync with the repo state - ViewsSetup bool - - // flag as to whether or not the diff view should ignore whitespace - IgnoreWhitespaceInDiffView bool - - // for displaying suggestions while typing in a file name - FilesTrie *patricia.Trie - - // this is the message of the last failed commit attempt - failedCommitMessage string -} - // reuseState determines if we pull the repo state from our repo state map or // just re-initialize it. For now we're only re-using state when we're going // in and out of submodules, for the sake of having the cursor back on the submodule @@ -400,14 +417,13 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { initialContext = contexts.BranchCommits } - gui.State = &guiState{ + gui.State = &GuiRepoState{ FileTreeViewModel: filetree.NewFileTreeViewModel(make([]*models.File, 0), gui.Log, showTree), CommitFileTreeViewModel: filetree.NewCommitFileTreeViewModel(make([]*models.CommitFile, 0), gui.Log, showTree), Commits: make([]*models.Commit, 0), FilteredReflogCommits: make([]*models.Commit, 0), ReflogCommits: make([]*models.Commit, 0), StashEntries: make([]*models.StashEntry, 0), - BisectInfo: gui.Git.Bisect.GetInfo(), Panels: &panelStates{ // TODO: work out why some of these are -1 and some are 0. Last time I checked there was a good reason but I'm less certain now Files: &filePanelState{listPanelState{SelectedLineIdx: -1}}, @@ -446,6 +462,21 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { gui.RepoStateMap[Repo(currentDir)] = gui.State } +type guiCommon struct { + gui *Gui + popup.IPopupHandler +} + +var _ controllers.IGuiCommon = &guiCommon{} + +func (self *guiCommon) LogAction(msg string) { + self.gui.logAction(msg) +} + +func (self *guiCommon) Refresh(opts types.RefreshOptions) error { + return self.gui.refreshSidePanels(opts) +} + // for now the split view will always be on // NewGui builds a new gui handler func NewGui( @@ -464,8 +495,8 @@ func NewGui( statusManager: &statusManager{}, viewBufferManagerMap: map[string]*tasks.ViewBufferManager{}, showRecentRepos: showRecentRepos, - RepoPathStack: []string{}, - RepoStateMap: map[Repo]*guiState{}, + RepoPathStack: &utils.StringStack{}, + RepoStateMap: map[Repo]*GuiRepoState{}, CmdLog: []string{}, suggestionsAsyncHandler: tasks.NewAsyncHandler(), @@ -501,11 +532,31 @@ func NewGui( gui.watchFilesForChanges() - gui.PopupHandler = &RealPopupHandler{gui: gui} + gui.PopupHandler = popup.NewPopupHandler( + cmn, + gui.createPopupPanel, + func() error { return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) }, + func() error { return gui.closeConfirmationPrompt(false) }, + gui.createMenu, + gui.withWaitingStatus, + ) authors.SetCustomAuthors(gui.UserConfig.Gui.AuthorColors) presentation.SetCustomBranches(gui.UserConfig.Gui.BranchColors) + guiCommon := &guiCommon{gui: gui, IPopupHandler: gui.PopupHandler} + controllerCommon := &controllers.ControllerCommon{IGuiCommon: guiCommon, Common: cmn} + + gui.Controllers = Controllers{ + Submodules: controllers.NewSubmodulesController( + controllerCommon, + gui.enterSubmodule, + gui.Git, + gui.State.Submodules, + gui.getSelectedSubmodule, + ), + } + return gui, nil } @@ -601,7 +652,7 @@ func (gui *Gui) RunAndHandleError() error { switch err { case gocui.ErrQuit: - if gui.State.RetainOriginalDir { + if gui.RetainOriginalDir { if err := gui.recordDirectory(gui.InitialDir); err != nil { return err } @@ -633,7 +684,7 @@ func (gui *Gui) runSubprocessWithSuspenseAndRefresh(subprocess oscommands.ICmdOb return err } - if err := gui.refreshSidePanels(refreshOptions{mode: ASYNC}); err != nil { + if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}); err != nil { return err } @@ -654,7 +705,7 @@ func (gui *Gui) runSubprocessWithSuspense(subprocess oscommands.ICmdObj) (bool, } if err := gui.g.Suspend(); err != nil { - return false, gui.surfaceError(err) + return false, gui.PopupHandler.Error(err) } gui.PauseBackgroundThreads = true @@ -668,7 +719,7 @@ func (gui *Gui) runSubprocessWithSuspense(subprocess oscommands.ICmdObj) (bool, gui.PauseBackgroundThreads = false if cmdErr != nil { - return false, gui.surfaceError(cmdErr) + return false, gui.PopupHandler.Error(cmdErr) } return true, nil @@ -703,7 +754,7 @@ func (gui *Gui) loadNewRepo() error { return err } - if err := gui.refreshSidePanels(refreshOptions{mode: ASYNC}); err != nil { + if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}); err != nil { return err } @@ -723,7 +774,7 @@ func (gui *Gui) showInitialPopups(tasks []func(chan struct{}) error) { task := task go utils.Safe(func() { if err := task(done); err != nil { - _ = gui.surfaceError(err) + _ = gui.PopupHandler.Error(err) } }) @@ -740,11 +791,11 @@ func (gui *Gui) showIntroPopupMessage(done chan struct{}) error { return gui.Config.SaveAppState() } - return gui.ask(askOpts{ - title: "", - prompt: gui.Tr.IntroPopupMessage, - handleConfirm: onConfirm, - handleClose: onConfirm, + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: "", + Prompt: gui.Tr.IntroPopupMessage, + HandleConfirm: onConfirm, + HandleClose: onConfirm, }) } @@ -775,9 +826,9 @@ func (gui *Gui) startBackgroundFetch() { } err := gui.backgroundFetch() if err != nil && strings.Contains(err.Error(), "exit status 128") && isNew { - _ = gui.ask(askOpts{ - title: gui.Tr.NoAutomaticGitFetchTitle, - prompt: gui.Tr.NoAutomaticGitFetchBody, + _ = gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.NoAutomaticGitFetchTitle, + Prompt: gui.Tr.NoAutomaticGitFetchBody, }) } else { gui.goEvery(time.Second*time.Duration(userConfig.Refresher.FetchInterval), gui.stopChan, func() error { diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index fa2e0e49b..644e4560b 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -9,28 +9,9 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/constants" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) -// Binding - a keybinding mapping a key and modifier to a handler. The keypress -// is only handled if the given view has focus, or handled globally if the view -// is "" -type Binding struct { - ViewName string - Contexts []string - Handler func() error - Key interface{} // FIXME: find out how to get `gocui.Key | rune` - Modifier gocui.Modifier - Description string - Alternative string - Tag string // e.g. 'navigation'. Used for grouping things in the cheatsheet - OpensMenu bool -} - -// GetDisplayStrings returns the display string of a file -func (b *Binding) GetDisplayStrings(isFocused bool) []string { - return []string{GetKeyDisplay(b.Key), b.Description} -} - var keyMapReversed = map[gocui.Key]string{ gocui.KeyF1: "f1", gocui.KeyF2: "f2", @@ -203,10 +184,10 @@ func (gui *Gui) getKey(key string) interface{} { } // GetInitialKeybindings is a function. -func (gui *Gui) GetInitialKeybindings() []*Binding { +func (gui *Gui) GetInitialKeybindings() []*types.Binding { config := gui.UserConfig.Keybinding - bindings := []*Binding{ + bindings := []*types.Binding{ { ViewName: "", Key: gui.getKey(config.Universal.Quit), @@ -1713,57 +1694,6 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { Handler: gui.handleCopySelectedSideContextItemToClipboard, Description: gui.Tr.LcCopySubmoduleNameToClipboard, }, - { - ViewName: "files", - Contexts: []string{string(SUBMODULES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.GoInto), - Handler: gui.forSubmodule(gui.handleSubmoduleEnter), - Description: gui.Tr.LcEnterSubmodule, - }, - { - ViewName: "files", - Contexts: []string{string(SUBMODULES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Remove), - Handler: gui.forSubmodule(gui.removeSubmodule), - Description: gui.Tr.LcRemoveSubmodule, - OpensMenu: true, - }, - { - ViewName: "files", - Contexts: []string{string(SUBMODULES_CONTEXT_KEY)}, - Key: gui.getKey(config.Submodules.Update), - Handler: gui.forSubmodule(gui.handleUpdateSubmodule), - Description: gui.Tr.LcSubmoduleUpdate, - }, - { - ViewName: "files", - Contexts: []string{string(SUBMODULES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.New), - Handler: gui.handleAddSubmodule, - Description: gui.Tr.LcAddSubmodule, - }, - { - ViewName: "files", - Contexts: []string{string(SUBMODULES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Edit), - Handler: gui.forSubmodule(gui.handleEditSubmoduleUrl), - Description: gui.Tr.LcEditSubmoduleUrl, - }, - { - ViewName: "files", - Contexts: []string{string(SUBMODULES_CONTEXT_KEY)}, - Key: gui.getKey(config.Submodules.Init), - Handler: gui.forSubmodule(gui.handleSubmoduleInit), - Description: gui.Tr.LcInitSubmodule, - }, - { - ViewName: "files", - Contexts: []string{string(SUBMODULES_CONTEXT_KEY)}, - Key: gui.getKey(config.Submodules.BulkMenu), - Handler: gui.handleBulkSubmoduleActionsMenu, - Description: gui.Tr.LcViewBulkSubmoduleOptions, - OpensMenu: true, - }, { ViewName: "files", Contexts: []string{string(FILES_CONTEXT_KEY)}, @@ -1841,8 +1771,28 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { }, } + type ContextKeybindings struct { + contextKey ContextKey + viewName string + bindings []*types.Binding + } + + for _, contextKeybindings := range []ContextKeybindings{ + { + contextKey: SUBMODULES_CONTEXT_KEY, + viewName: "files", + bindings: gui.Controllers.Submodules.Keybindings(gui.getKey, config), + }, + } { + for _, binding := range contextKeybindings.bindings { + binding.Contexts = []string{string(contextKeybindings.contextKey)} + binding.ViewName = contextKeybindings.viewName + bindings = append(bindings, binding) + } + } + for _, viewName := range []string{"status", "branches", "files", "commits", "commitFiles", "stash", "menu"} { - bindings = append(bindings, []*Binding{ + bindings = append(bindings, []*types.Binding{ {ViewName: viewName, Key: gui.getKey(config.Universal.PrevBlock), Modifier: gocui.ModNone, Handler: gui.previousSideWindow}, {ViewName: viewName, Key: gui.getKey(config.Universal.NextBlock), Modifier: gocui.ModNone, Handler: gui.nextSideWindow}, {ViewName: viewName, Key: gui.getKey(config.Universal.PrevBlockAlt), Modifier: gocui.ModNone, Handler: gui.previousSideWindow}, @@ -1859,7 +1809,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { log.Fatal("Jump to block keybindings cannot be set. Exactly 5 keybindings must be supplied.") } else { for i, window := range windows { - bindings = append(bindings, &Binding{ + bindings = append(bindings, &types.Binding{ ViewName: "", Key: gui.getKey(config.Universal.JumpToBlock[i]), Modifier: gocui.ModNone, @@ -1868,7 +1818,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { } for viewName := range gui.State.Contexts.initialViewTabContextMap() { - bindings = append(bindings, []*Binding{ + bindings = append(bindings, []*types.Binding{ { ViewName: viewName, Key: gui.getKey(config.Universal.NextTab), diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index c5872654a..3af9ea9af 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -234,9 +234,9 @@ func (gui *Gui) layout(g *gocui.Gui) error { // if the commit files view is the view to be displayed for its window, we'll display it gui.Views.CommitFiles.Visible = gui.getViewNameForWindow(gui.State.Contexts.CommitFiles.GetWindowName()) == "commitFiles" - if gui.State.OldInformation != informationStr { + if gui.PrevLayout.Information != informationStr { gui.setViewContent(gui.Views.Information, informationStr) - gui.State.OldInformation = informationStr + gui.PrevLayout.Information = informationStr } if !gui.ViewsSetup { @@ -277,9 +277,9 @@ func (gui *Gui) layout(g *gocui.Gui) error { gui.Views.Main.SetOnSelectItem(gui.onSelectItemWrapper(gui.handlelineByLineNavigateTo)) mainViewWidth, mainViewHeight := gui.Views.Main.Size() - if mainViewWidth != gui.State.PrevMainWidth || mainViewHeight != gui.State.PrevMainHeight { - gui.State.PrevMainWidth = mainViewWidth - gui.State.PrevMainHeight = mainViewHeight + if mainViewWidth != gui.PrevLayout.MainWidth || mainViewHeight != gui.PrevLayout.MainHeight { + gui.PrevLayout.MainWidth = mainViewWidth + gui.PrevLayout.MainHeight = mainViewHeight if err := gui.onResize(); err != nil { return err } diff --git a/pkg/gui/line_by_line_panel.go b/pkg/gui/line_by_line_panel.go index a033aa0d7..e851bc821 100644 --- a/pkg/gui/line_by_line_panel.go +++ b/pkg/gui/line_by_line_panel.go @@ -89,7 +89,7 @@ func (gui *Gui) copySelectedToClipboard() error { gui.logAction(gui.Tr.Actions.CopySelectedTextToClipboard) if err := gui.OSCommand.CopyToClipboard(selected); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return nil diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index 7ddd56e25..c40cade2c 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -7,6 +7,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/style" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) func (gui *Gui) menuListContext() IListContext { @@ -391,15 +392,15 @@ func (gui *Gui) getListContexts() []IListContext { } } -func (gui *Gui) getListContextKeyBindings() []*Binding { - bindings := make([]*Binding, 0) +func (gui *Gui) getListContextKeyBindings() []*types.Binding { + bindings := make([]*types.Binding, 0) keybindingConfig := gui.UserConfig.Keybinding for _, listContext := range gui.getListContexts() { listContext := listContext - bindings = append(bindings, []*Binding{ + bindings = append(bindings, []*types.Binding{ {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: listContext.handlePrevLine}, {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.PrevItem), Modifier: gocui.ModNone, Handler: listContext.handlePrevLine}, {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, Handler: listContext.handlePrevLine}, @@ -423,7 +424,7 @@ func (gui *Gui) getListContextKeyBindings() []*Binding { gotoBottomHandler = gui.handleGotoBottomForCommitsPanel } - bindings = append(bindings, []*Binding{ + bindings = append(bindings, []*types.Binding{ { ViewName: listContext.GetViewName(), Contexts: []string{string(listContext.GetKey())}, diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go index b32b3bf44..f1bc558c4 100644 --- a/pkg/gui/menu_panel.go +++ b/pkg/gui/menu_panel.go @@ -3,31 +3,12 @@ package gui import ( "errors" "fmt" - "strings" + "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/utils" ) -type menuItem struct { - displayString string - displayStrings []string - onPress func() error - // only applies when displayString is used - opensMenu bool -} - -// every item in a list context needs an ID -func (i *menuItem) ID() string { - if i.displayString != "" { - return i.displayString - } - - return strings.Join(i.displayStrings, "-") -} - -// specific functions - func (gui *Gui) getMenuOptions() map[string]string { keybindingConfig := gui.UserConfig.Keybinding @@ -42,37 +23,34 @@ func (gui *Gui) handleMenuClose() error { return gui.returnFromContext() } -type createMenuOptions struct { - showCancel bool -} - -func (gui *Gui) createMenu(title string, items []*menuItem, createMenuOptions createMenuOptions) error { - if createMenuOptions.showCancel { +// note: items option is mutated by this function +func (gui *Gui) createMenu(opts popup.CreateMenuOptions) error { + if !opts.HideCancel { // this is mutative but I'm okay with that for now - items = append(items, &menuItem{ - displayStrings: []string{gui.Tr.LcCancel}, - onPress: func() error { + opts.Items = append(opts.Items, &popup.MenuItem{ + DisplayStrings: []string{gui.Tr.LcCancel}, + OnPress: func() error { return nil }, }) } - gui.State.MenuItems = items + gui.State.MenuItems = opts.Items - stringArrays := make([][]string, len(items)) - for i, item := range items { - if item.opensMenu && item.displayStrings != nil { + stringArrays := make([][]string, len(opts.Items)) + for i, item := range opts.Items { + if item.OpensMenu && item.DisplayStrings != nil { return errors.New("Message for the developer of this app: you've set opensMenu with displaystrings on the menu panel. Bad developer!. Apologies, user") } - if item.displayStrings == nil { - styledStr := item.displayString - if item.opensMenu { + if item.DisplayStrings == nil { + styledStr := item.DisplayString + if item.OpensMenu { styledStr = opensMenuStyle(styledStr) } stringArrays[i] = []string{styledStr} } else { - stringArrays[i] = item.displayStrings + stringArrays[i] = item.DisplayStrings } } @@ -80,7 +58,7 @@ func (gui *Gui) createMenu(title string, items []*menuItem, createMenuOptions cr x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(false, list) menuView, _ := gui.g.SetView("menu", x0, y0, x1, y1, 0) - menuView.Title = title + menuView.Title = opts.Title menuView.FgColor = theme.GocuiDefaultTextColor menuView.SetOnSelectItem(gui.onSelectItemWrapper(func(selectedLine int) error { return nil @@ -97,7 +75,7 @@ func (gui *Gui) onMenuPress() error { return err } - if err := gui.State.MenuItems[selectedLine].onPress(); err != nil { + if err := gui.State.MenuItems[selectedLine].OnPress(); err != nil { return err } diff --git a/pkg/gui/merge_panel.go b/pkg/gui/merge_panel.go index dbd5b3be7..9f46c177c 100644 --- a/pkg/gui/merge_panel.go +++ b/pkg/gui/merge_panel.go @@ -9,6 +9,7 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/mergeconflicts" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) func (gui *Gui) handleSelectPrevConflictHunk() error { @@ -189,7 +190,7 @@ func (gui *Gui) getMergingOptions() map[string]string { } func (gui *Gui) handleEscapeMerge() error { - if err := gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}); err != nil { + if err := gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}); err != nil { return err } @@ -199,7 +200,7 @@ func (gui *Gui) handleEscapeMerge() error { func (gui *Gui) onLastConflictResolved() error { // as part of refreshing files, we handle the situation where a file has had // its merge conflicts resolved. - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{mode: types.ASYNC, scope: []types.RefreshableView{types.FILES}}) } func (gui *Gui) resetMergeState() { diff --git a/pkg/gui/options_menu_panel.go b/pkg/gui/options_menu_panel.go index 12507597f..f02f96a95 100644 --- a/pkg/gui/options_menu_panel.go +++ b/pkg/gui/options_menu_panel.go @@ -4,13 +4,15 @@ import ( "strings" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/style" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) -func (gui *Gui) getBindings(v *gocui.View) []*Binding { +func (gui *Gui) getBindings(v *gocui.View) []*types.Binding { var ( - bindingsGlobal, bindingsPanel []*Binding + bindingsGlobal, bindingsPanel []*types.Binding ) bindings := append(gui.GetCustomCommandKeybindings(), gui.GetInitialKeybindings()...) @@ -30,11 +32,11 @@ func (gui *Gui) getBindings(v *gocui.View) []*Binding { // append dummy element to have a separator between // panel and global keybindings - bindingsPanel = append(bindingsPanel, &Binding{}) + bindingsPanel = append(bindingsPanel, &types.Binding{}) return append(bindingsPanel, bindingsGlobal...) } -func (gui *Gui) displayDescription(binding *Binding) string { +func (gui *Gui) displayDescription(binding *types.Binding) string { if binding.OpensMenu { return opensMenuStyle(binding.Description) } @@ -54,13 +56,13 @@ func (gui *Gui) handleCreateOptionsMenu() error { bindings := gui.getBindings(view) - menuItems := make([]*menuItem, len(bindings)) + menuItems := make([]*popup.MenuItem, len(bindings)) for i, binding := range bindings { binding := binding // note to self, never close over loop variables - menuItems[i] = &menuItem{ - displayStrings: []string{GetKeyDisplay(binding.Key), gui.displayDescription(binding)}, - onPress: func() error { + menuItems[i] = &popup.MenuItem{ + DisplayStrings: []string{GetKeyDisplay(binding.Key), gui.displayDescription(binding)}, + OnPress: func() error { if binding.Key == nil { return nil } @@ -72,5 +74,9 @@ func (gui *Gui) handleCreateOptionsMenu() error { } } - return gui.createMenu(strings.Title(gui.Tr.LcMenu), menuItems, createMenuOptions{}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{ + Title: strings.Title(gui.Tr.LcMenu), + Items: menuItems, + HideCancel: true, + }) } diff --git a/pkg/gui/patch_options_panel.go b/pkg/gui/patch_options_panel.go index c9a3defce..915572c16 100644 --- a/pkg/gui/patch_options_panel.go +++ b/pkg/gui/patch_options_panel.go @@ -4,41 +4,43 @@ import ( "fmt" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) func (gui *Gui) handleCreatePatchOptionsMenu() error { if !gui.Git.Patch.PatchManager.Active() { - return gui.createErrorPanel(gui.Tr.NoPatchError) + return gui.PopupHandler.ErrorMsg(gui.Tr.NoPatchError) } - menuItems := []*menuItem{ + menuItems := []*popup.MenuItem{ { - displayString: "reset patch", - onPress: gui.handleResetPatch, + DisplayString: "reset patch", + OnPress: gui.handleResetPatch, }, { - displayString: "apply patch", - onPress: func() error { return gui.handleApplyPatch(false) }, + DisplayString: "apply patch", + OnPress: func() error { return gui.handleApplyPatch(false) }, }, { - displayString: "apply patch in reverse", - onPress: func() error { return gui.handleApplyPatch(true) }, + DisplayString: "apply patch in reverse", + OnPress: func() error { return gui.handleApplyPatch(true) }, }, } if gui.Git.Patch.PatchManager.CanRebase && gui.Git.Status.WorkingTreeState() == enums.REBASE_MODE_NONE { - menuItems = append(menuItems, []*menuItem{ + menuItems = append(menuItems, []*popup.MenuItem{ { - displayString: fmt.Sprintf("remove patch from original commit (%s)", gui.Git.Patch.PatchManager.To), - onPress: gui.handleDeletePatchFromCommit, + DisplayString: fmt.Sprintf("remove patch from original commit (%s)", gui.Git.Patch.PatchManager.To), + OnPress: gui.handleDeletePatchFromCommit, }, { - displayString: "move patch out into index", - onPress: gui.handleMovePatchIntoWorkingTree, + DisplayString: "move patch out into index", + OnPress: gui.handleMovePatchIntoWorkingTree, }, { - displayString: "move patch into new commit", - onPress: gui.handlePullPatchIntoNewCommit, + DisplayString: "move patch into new commit", + OnPress: gui.handlePullPatchIntoNewCommit, }, }...) @@ -49,10 +51,10 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error { menuItems = append( menuItems[:1], append( - []*menuItem{ + []*popup.MenuItem{ { - displayString: fmt.Sprintf("move patch to selected commit (%s)", selectedCommit.Sha), - onPress: gui.handleMovePatchToSelectedCommit, + DisplayString: fmt.Sprintf("move patch to selected commit (%s)", selectedCommit.Sha), + OnPress: gui.handleMovePatchToSelectedCommit, }, }, menuItems[1:]..., )..., @@ -61,7 +63,7 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error { } } - return gui.createMenu(gui.Tr.PatchOptionsTitle, menuItems, createMenuOptions{showCancel: true}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: gui.Tr.PatchOptionsTitle, Items: menuItems}) } func (gui *Gui) getPatchCommitIndex() int { @@ -75,7 +77,7 @@ func (gui *Gui) getPatchCommitIndex() int { func (gui *Gui) validateNormalWorkingTreeState() (bool, error) { if gui.Git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE { - return false, gui.createErrorPanel(gui.Tr.CantPatchWhileRebasingError) + return false, gui.PopupHandler.ErrorMsg(gui.Tr.CantPatchWhileRebasingError) } return true, nil } @@ -96,7 +98,7 @@ func (gui *Gui) handleDeletePatchFromCommit() error { return err } - return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() gui.logAction(gui.Tr.Actions.RemovePatchFromCommit) err := gui.Git.Patch.DeletePatchesFromCommit(gui.State.Commits, commitIndex) @@ -113,7 +115,7 @@ func (gui *Gui) handleMovePatchToSelectedCommit() error { return err } - return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() gui.logAction(gui.Tr.Actions.MovePatchToSelectedCommit) err := gui.Git.Patch.MovePatchToSelectedCommit(gui.State.Commits, commitIndex, gui.State.Panels.Commits.SelectedLineIdx) @@ -131,7 +133,7 @@ func (gui *Gui) handleMovePatchIntoWorkingTree() error { } pull := func(stash bool) error { - return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() gui.logAction(gui.Tr.Actions.MovePatchIntoIndex) err := gui.Git.Patch.MovePatchIntoIndex(gui.State.Commits, commitIndex, stash) @@ -140,10 +142,10 @@ func (gui *Gui) handleMovePatchIntoWorkingTree() error { } if len(gui.trackedFiles()) > 0 { - return gui.ask(askOpts{ - title: gui.Tr.MustStashTitle, - prompt: gui.Tr.MustStashWarning, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.MustStashTitle, + Prompt: gui.Tr.MustStashWarning, + HandleConfirm: func() error { return pull(true) }, }) @@ -161,7 +163,7 @@ func (gui *Gui) handlePullPatchIntoNewCommit() error { return err } - return gui.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() gui.logAction(gui.Tr.Actions.MovePatchIntoNewCommit) err := gui.Git.Patch.PullPatchIntoNewCommit(gui.State.Commits, commitIndex) @@ -180,9 +182,9 @@ func (gui *Gui) handleApplyPatch(reverse bool) error { } gui.logAction(action) if err := gui.Git.Patch.PatchManager.ApplyPatches(reverse); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) } func (gui *Gui) handleResetPatch() error { diff --git a/pkg/gui/popup/popup_handler.go b/pkg/gui/popup/popup_handler.go new file mode 100644 index 000000000..adc276d5f --- /dev/null +++ b/pkg/gui/popup/popup_handler.go @@ -0,0 +1,223 @@ +package popup + +import ( + "strings" + "sync" + + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/common" + "github.com/jesseduffield/lazygit/pkg/gui/style" + "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +type IPopupHandler interface { + ErrorMsg(message string) error + Error(err error) error + Ask(opts AskOpts) error + Prompt(opts PromptOpts) error + WithLoaderPanel(message string, f func() error) error + WithWaitingStatus(message string, f func() error) error + Menu(opts CreateMenuOptions) error +} + +type CreateMenuOptions struct { + Title string + Items []*MenuItem + HideCancel bool +} + +type CreatePopupPanelOpts struct { + HasLoader bool + Editable bool + Title string + Prompt string + HandleConfirm func() error + HandleConfirmPrompt func(string) error + HandleClose func() error + + // when HandlersManageFocus is true, do not return from the confirmation context automatically. It's expected that the handlers will manage focus, whether that means switching to another context, or manually returning the context. + HandlersManageFocus bool + + FindSuggestionsFunc func(string) []*types.Suggestion +} + +type AskOpts struct { + Title string + Prompt string + HandleConfirm func() error + HandleClose func() error + HandlersManageFocus bool +} + +type PromptOpts struct { + Title string + InitialContent string + FindSuggestionsFunc func(string) []*types.Suggestion + HandleConfirm func(string) error +} + +type MenuItem struct { + DisplayString string + DisplayStrings []string + OnPress func() error + // only applies when displayString is used + OpensMenu bool +} + +type RealPopupHandler struct { + *common.Common + index int + sync.Mutex + createPopupPanelFn func(CreatePopupPanelOpts) error + onErrorFn func() error + closePopupFn func() error + createMenuFn func(CreateMenuOptions) error + withWaitingStatusFn func(message string, f func() error) error +} + +var _ IPopupHandler = &RealPopupHandler{} + +func NewPopupHandler( + common *common.Common, + createPopupPanelFn func(CreatePopupPanelOpts) error, + onErrorFn func() error, + closePopupFn func() error, + createMenuFn func(CreateMenuOptions) error, + withWaitingStatusFn func(message string, f func() error) error, +) *RealPopupHandler { + return &RealPopupHandler{ + Common: common, + index: 0, + createPopupPanelFn: createPopupPanelFn, + onErrorFn: onErrorFn, + closePopupFn: closePopupFn, + createMenuFn: createMenuFn, + withWaitingStatusFn: withWaitingStatusFn, + } +} + +func (self *RealPopupHandler) Menu(opts CreateMenuOptions) error { + return self.createMenuFn(opts) +} + +func (self *RealPopupHandler) WithWaitingStatus(message string, f func() error) error { + return self.withWaitingStatusFn(message, f) +} + +func (self *RealPopupHandler) Error(err error) error { + if err == gocui.ErrQuit { + return err + } + + return self.ErrorMsg(err.Error()) +} + +func (self *RealPopupHandler) ErrorMsg(message string) error { + self.Lock() + self.index++ + self.Unlock() + + coloredMessage := style.FgRed.Sprint(strings.TrimSpace(message)) + if err := self.onErrorFn(); err != nil { + return err + } + + return self.Ask(AskOpts{ + Title: self.Tr.Error, + Prompt: coloredMessage, + }) +} + +func (self *RealPopupHandler) Ask(opts AskOpts) error { + self.Lock() + self.index++ + self.Unlock() + + return self.createPopupPanelFn(CreatePopupPanelOpts{ + Title: opts.Title, + Prompt: opts.Prompt, + HandleConfirm: opts.HandleConfirm, + HandleClose: opts.HandleClose, + HandlersManageFocus: opts.HandlersManageFocus, + }) +} + +func (self *RealPopupHandler) Prompt(opts PromptOpts) error { + self.Lock() + self.index++ + self.Unlock() + + return self.createPopupPanelFn(CreatePopupPanelOpts{ + Title: opts.Title, + Prompt: opts.InitialContent, + Editable: true, + HandleConfirmPrompt: opts.HandleConfirm, + FindSuggestionsFunc: opts.FindSuggestionsFunc, + }) +} + +func (self *RealPopupHandler) WithLoaderPanel(message string, f func() error) error { + index := 0 + self.Lock() + self.index++ + index = self.index + self.Unlock() + + err := self.createPopupPanelFn(CreatePopupPanelOpts{ + Prompt: message, + HasLoader: true, + }) + if err != nil { + self.Log.Error(err) + return nil + } + + go utils.Safe(func() { + if err := f(); err != nil { + self.Log.Error(err) + } + + self.Lock() + if index == self.index { + _ = self.closePopupFn() + } + self.Unlock() + }) + + return nil +} + +type TestPopupHandler struct { + OnErrorMsg func(message string) error + OnAsk func(opts AskOpts) error + OnPrompt func(opts PromptOpts) error +} + +func (self *TestPopupHandler) Error(err error) error { + return self.ErrorMsg(err.Error()) +} + +func (self *TestPopupHandler) ErrorMsg(message string) error { + return self.OnErrorMsg(message) +} + +func (self *TestPopupHandler) Ask(opts AskOpts) error { + return self.OnAsk(opts) +} + +func (self *TestPopupHandler) Prompt(opts PromptOpts) error { + return self.OnPrompt(opts) +} + +func (self *TestPopupHandler) WithLoaderPanel(message string, f func() error) error { + return f() +} + +func (self *TestPopupHandler) WithWaitingStatus(message string, f func() error) error { + return f() +} + +func (self *TestPopupHandler) Menu(opts CreateMenuOptions) error { + panic("not yet implemented") +} diff --git a/pkg/gui/popup_handler.go b/pkg/gui/popup_handler.go deleted file mode 100644 index 9cacc3574..000000000 --- a/pkg/gui/popup_handler.go +++ /dev/null @@ -1,87 +0,0 @@ -package gui - -import ( - "strings" - - "github.com/jesseduffield/lazygit/pkg/gui/style" -) - -type PopupHandler interface { - Error(message string) error - Ask(opts askOpts) error - Prompt(opts promptOpts) error - Loader(message string) error -} - -type RealPopupHandler struct { - gui *Gui -} - -func (self *RealPopupHandler) Error(message string) error { - gui := self.gui - - coloredMessage := style.FgRed.Sprint(strings.TrimSpace(message)) - if err := gui.refreshSidePanels(refreshOptions{mode: ASYNC}); err != nil { - return err - } - - return self.Ask(askOpts{ - title: gui.Tr.Error, - prompt: coloredMessage, - }) -} - -func (self *RealPopupHandler) Ask(opts askOpts) error { - gui := self.gui - - return gui.createPopupPanel(createPopupPanelOpts{ - title: opts.title, - prompt: opts.prompt, - handleConfirm: opts.handleConfirm, - handleClose: opts.handleClose, - handlersManageFocus: opts.handlersManageFocus, - }) -} - -func (self *RealPopupHandler) Prompt(opts promptOpts) error { - gui := self.gui - - return gui.createPopupPanel(createPopupPanelOpts{ - title: opts.title, - prompt: opts.initialContent, - editable: true, - handleConfirmPrompt: opts.handleConfirm, - findSuggestionsFunc: opts.findSuggestionsFunc, - }) -} - -func (self *RealPopupHandler) Loader(message string) error { - gui := self.gui - - return gui.createPopupPanel(createPopupPanelOpts{ - prompt: message, - hasLoader: true, - }) -} - -type TestPopupHandler struct { - onError func(message string) error - onAsk func(opts askOpts) error - onPrompt func(opts promptOpts) error -} - -func (self *TestPopupHandler) Error(message string) error { - return self.onError(message) -} - -func (self *TestPopupHandler) Ask(opts askOpts) error { - return self.onAsk(opts) -} - -func (self *TestPopupHandler) Prompt(opts promptOpts) error { - return self.onPrompt(opts) -} - -func (self *TestPopupHandler) Loader(message string) error { - return nil -} diff --git a/pkg/gui/pull_request_menu_panel.go b/pkg/gui/pull_request_menu_panel.go index c2d5c9f57..5c2a3df8d 100644 --- a/pkg/gui/pull_request_menu_panel.go +++ b/pkg/gui/pull_request_menu_panel.go @@ -5,30 +5,31 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/hosting_service" "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/popup" ) func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutBranch *models.Branch) error { - menuItems := make([]*menuItem, 0, 4) + menuItems := make([]*popup.MenuItem, 0, 4) fromToDisplayStrings := func(from string, to string) []string { return []string{fmt.Sprintf("%s 鈫 %s", from, to)} } - menuItemsForBranch := func(branch *models.Branch) []*menuItem { - return []*menuItem{ + menuItemsForBranch := func(branch *models.Branch) []*popup.MenuItem { + return []*popup.MenuItem{ { - displayStrings: fromToDisplayStrings(branch.Name, gui.Tr.LcDefaultBranch), - onPress: func() error { + DisplayStrings: fromToDisplayStrings(branch.Name, gui.Tr.LcDefaultBranch), + OnPress: func() error { return gui.createPullRequest(branch.Name, "") }, }, { - displayStrings: fromToDisplayStrings(branch.Name, gui.Tr.LcSelectBranch), - onPress: func() error { - return gui.prompt(promptOpts{ - title: branch.Name + " 鈫", - findSuggestionsFunc: gui.getBranchNameSuggestionsFunc(), - handleConfirm: func(targetBranchName string) error { + DisplayStrings: fromToDisplayStrings(branch.Name, gui.Tr.LcSelectBranch), + OnPress: func() error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: branch.Name + " 鈫", + FindSuggestionsFunc: gui.getBranchNameSuggestionsFunc(), + HandleConfirm: func(targetBranchName string) error { return gui.createPullRequest(branch.Name, targetBranchName) }}, ) @@ -39,9 +40,9 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB if selectedBranch != checkedOutBranch { menuItems = append(menuItems, - &menuItem{ - displayStrings: fromToDisplayStrings(checkedOutBranch.Name, selectedBranch.Name), - onPress: func() error { + &popup.MenuItem{ + DisplayStrings: fromToDisplayStrings(checkedOutBranch.Name, selectedBranch.Name), + OnPress: func() error { return gui.createPullRequest(checkedOutBranch.Name, selectedBranch.Name) }, }, @@ -51,20 +52,20 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB menuItems = append(menuItems, menuItemsForBranch(selectedBranch)...) - return gui.createMenu(fmt.Sprintf(gui.Tr.CreatePullRequestOptions), menuItems, createMenuOptions{showCancel: true}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: fmt.Sprintf(gui.Tr.CreatePullRequestOptions), Items: menuItems}) } func (gui *Gui) createPullRequest(from string, to string) error { hostingServiceMgr := gui.getHostingServiceMgr() url, err := hostingServiceMgr.GetPullRequestURL(from, to) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.logAction(gui.Tr.Actions.OpenPullRequest) if err := gui.OSCommand.OpenLink(url); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return nil diff --git a/pkg/gui/quitting.go b/pkg/gui/quitting.go index d3beaf998..4e9242640 100644 --- a/pkg/gui/quitting.go +++ b/pkg/gui/quitting.go @@ -4,6 +4,7 @@ import ( "os" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/popup" ) // when a user runs lazygit with the LAZYGIT_NEW_DIR_FILE env variable defined @@ -28,12 +29,12 @@ func (gui *Gui) recordDirectory(dirName string) error { } func (gui *Gui) handleQuitWithoutChangingDirectory() error { - gui.State.RetainOriginalDir = true + gui.RetainOriginalDir = true return gui.quit() } func (gui *Gui) handleQuit() error { - gui.State.RetainOriginalDir = false + gui.RetainOriginalDir = false return gui.quit() } @@ -53,12 +54,8 @@ func (gui *Gui) handleTopLevelReturn() error { } repoPathStack := gui.RepoPathStack - if len(repoPathStack) > 0 { - n := len(repoPathStack) - 1 - - path := repoPathStack[n] - - gui.RepoPathStack = repoPathStack[:n] + if !repoPathStack.IsEmpty() { + path := repoPathStack.Pop() return gui.dispatchSwitchToRepo(path, true) } @@ -76,10 +73,10 @@ func (gui *Gui) quit() error { } if gui.UserConfig.ConfirmOnQuit { - return gui.ask(askOpts{ - title: "", - prompt: gui.Tr.ConfirmQuit, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: "", + Prompt: gui.Tr.ConfirmQuit, + HandleConfirm: func() error { return gocui.ErrQuit }, }) diff --git a/pkg/gui/rebase_options_panel.go b/pkg/gui/rebase_options_panel.go index a9e7d9317..b4a37e956 100644 --- a/pkg/gui/rebase_options_panel.go +++ b/pkg/gui/rebase_options_panel.go @@ -5,6 +5,8 @@ import ( "strings" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) type RebaseOption string @@ -22,13 +24,13 @@ func (gui *Gui) handleCreateRebaseOptionsMenu() error { options = append(options, REBASE_OPTION_SKIP) } - menuItems := make([]*menuItem, len(options)) + menuItems := make([]*popup.MenuItem, len(options)) for i, option := range options { // note to self. Never, EVER, close over loop variables in a function option := option - menuItems[i] = &menuItem{ - displayString: option, - onPress: func() error { + menuItems[i] = &popup.MenuItem{ + DisplayString: option, + OnPress: func() error { return gui.genericMergeCommand(option) }, } @@ -41,14 +43,14 @@ func (gui *Gui) handleCreateRebaseOptionsMenu() error { title = gui.Tr.RebaseOptionsTitle } - return gui.createMenu(title, menuItems, createMenuOptions{showCancel: true}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: title, Items: menuItems}) } func (gui *Gui) genericMergeCommand(command string) error { status := gui.Git.Status.WorkingTreeState() if status != enums.REBASE_MODE_MERGING && status != enums.REBASE_MODE_REBASING { - return gui.createErrorPanel(gui.Tr.NotMergingOrRebasing) + return gui.PopupHandler.ErrorMsg(gui.Tr.NotMergingOrRebasing) } gui.logAction(fmt.Sprintf("Merge/Rebase: %s", command)) @@ -97,7 +99,7 @@ func isMergeConflictErr(errStr string) bool { } func (gui *Gui) handleGenericMergeCommandResult(result error) error { - if err := gui.refreshSidePanels(refreshOptions{mode: ASYNC}); err != nil { + if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}); err != nil { return err } if result == nil { @@ -110,14 +112,14 @@ func (gui *Gui) handleGenericMergeCommandResult(result error) error { // assume in this case that we're already done return nil } else if isMergeConflictErr(result.Error()) { - return gui.ask(askOpts{ - title: gui.Tr.FoundConflictsTitle, - prompt: gui.Tr.FoundConflicts, - handlersManageFocus: true, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.FoundConflictsTitle, + Prompt: gui.Tr.FoundConflicts, + HandlersManageFocus: true, + HandleConfirm: func() error { return gui.pushContext(gui.State.Contexts.Files) }, - handleClose: func() error { + HandleClose: func() error { if err := gui.returnFromContext(); err != nil { return err } @@ -126,17 +128,17 @@ func (gui *Gui) handleGenericMergeCommandResult(result error) error { }, }) } else { - return gui.createErrorPanel(result.Error()) + return gui.PopupHandler.ErrorMsg(result.Error()) } } func (gui *Gui) abortMergeOrRebaseWithConfirm() error { // prompt user to confirm that they want to abort, then do it mode := gui.workingTreeStateNoun() - return gui.ask(askOpts{ - title: fmt.Sprintf(gui.Tr.AbortTitle, mode), - prompt: fmt.Sprintf(gui.Tr.AbortPrompt, mode), - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: fmt.Sprintf(gui.Tr.AbortTitle, mode), + Prompt: fmt.Sprintf(gui.Tr.AbortPrompt, mode), + HandleConfirm: func() error { return gui.genericMergeCommand(REBASE_OPTION_ABORT) }, }) diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index 01b9a00d3..ec6a1ffc7 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -7,6 +7,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_config" "github.com/jesseduffield/lazygit/pkg/env" + "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -16,24 +17,24 @@ func (gui *Gui) handleCreateRecentReposMenu() error { reposCount := utils.Min(len(recentRepoPaths), 20) // we won't show the current repo hence the -1 - menuItems := make([]*menuItem, reposCount-1) + menuItems := make([]*popup.MenuItem, reposCount-1) for i, path := range recentRepoPaths[1:reposCount] { path := path // cos we're closing over the loop variable - menuItems[i] = &menuItem{ - displayStrings: []string{ + menuItems[i] = &popup.MenuItem{ + DisplayStrings: []string{ filepath.Base(path), style.FgMagenta.Sprint(path), }, - onPress: func() error { + OnPress: func() error { // if we were in a submodule, we want to forget about that stack of repos // so that hitting escape in the new repo does nothing - gui.RepoPathStack = []string{} + gui.RepoPathStack.Clear() return gui.dispatchSwitchToRepo(path, false) }, } } - return gui.createMenu(gui.Tr.RecentRepos, menuItems, createMenuOptions{showCancel: true}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: gui.Tr.RecentRepos, Items: menuItems}) } func (gui *Gui) handleShowAllBranchLogs() error { @@ -57,7 +58,7 @@ func (gui *Gui) dispatchSwitchToRepo(path string, reuse bool) error { if err := os.Chdir(path); err != nil { if os.IsNotExist(err) { - return gui.createErrorPanel(gui.Tr.ErrRepositoryMovedOrDeleted) + return gui.PopupHandler.ErrorMsg(gui.Tr.ErrRepositoryMovedOrDeleted) } return err } diff --git a/pkg/gui/reflog_panel.go b/pkg/gui/reflog_panel.go index af8e8092c..3ccbdb7c8 100644 --- a/pkg/gui/reflog_panel.go +++ b/pkg/gui/reflog_panel.go @@ -2,6 +2,7 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/popup" ) // list panel functions @@ -55,7 +56,7 @@ func (gui *Gui) refreshReflogCommits() error { commits, onlyObtainedNewReflogCommits, err := gui.Git.Loaders.ReflogCommits. GetReflogCommits(lastReflogCommit, filterPath) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } if onlyObtainedNewReflogCommits { @@ -87,10 +88,10 @@ func (gui *Gui) handleCheckoutReflogCommit() error { return nil } - err := gui.ask(askOpts{ - title: gui.Tr.LcCheckoutCommit, - prompt: gui.Tr.SureCheckoutThisCommit, - handleConfirm: func() error { + err := gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.LcCheckoutCommit, + Prompt: gui.Tr.SureCheckoutThisCommit, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.CheckoutReflogCommit) return gui.handleCheckoutRef(commit.Sha, handleCheckoutRefOptions{}) }, diff --git a/pkg/gui/remote_branches_panel.go b/pkg/gui/remote_branches_panel.go index 29ab59187..1ee402097 100644 --- a/pkg/gui/remote_branches_panel.go +++ b/pkg/gui/remote_branches_panel.go @@ -4,6 +4,8 @@ import ( "fmt" "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -52,16 +54,18 @@ func (gui *Gui) handleDeleteRemoteBranch() error { } message := fmt.Sprintf("%s '%s'?", gui.Tr.DeleteRemoteBranchMessage, remoteBranch.FullName()) - return gui.ask(askOpts{ - title: gui.Tr.DeleteRemoteBranch, - prompt: message, - handleConfirm: func() error { - return gui.WithWaitingStatus(gui.Tr.DeletingStatus, func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.DeleteRemoteBranch, + Prompt: message, + HandleConfirm: func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.DeletingStatus, func() error { gui.logAction(gui.Tr.Actions.DeleteRemoteBranch) err := gui.Git.Remote.DeleteRemoteBranch(remoteBranch.RemoteName, remoteBranch.Name) - gui.handleCredentialsPopup(err) + if err != nil { + _ = gui.PopupHandler.Error(err) + } - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{BRANCHES, REMOTES}}) + return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) }) }, }) @@ -84,16 +88,16 @@ func (gui *Gui) handleSetBranchUpstream() error { }, ) - return gui.ask(askOpts{ - title: gui.Tr.SetUpstreamTitle, - prompt: message, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.SetUpstreamTitle, + Prompt: message, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.SetBranchUpstream) if err := gui.Git.Branch.SetUpstream(selectedBranch.RemoteName, selectedBranch.Name, checkedOutBranch.Name); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{BRANCHES, REMOTES}}) + return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) }, }) } diff --git a/pkg/gui/remotes_panel.go b/pkg/gui/remotes_panel.go index c74653a27..bc06f77f0 100644 --- a/pkg/gui/remotes_panel.go +++ b/pkg/gui/remotes_panel.go @@ -5,7 +5,9 @@ import ( "strings" "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/style" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -42,7 +44,7 @@ func (gui *Gui) refreshRemotes() error { remotes, err := gui.Git.Loaders.Remotes.GetRemotes() if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.State.Remotes = remotes @@ -79,17 +81,17 @@ func (gui *Gui) handleRemoteEnter() error { } func (gui *Gui) handleAddRemote() error { - return gui.prompt(promptOpts{ - title: gui.Tr.LcNewRemoteName, - handleConfirm: func(remoteName string) error { - return gui.prompt(promptOpts{ - title: gui.Tr.LcNewRemoteUrl, - handleConfirm: func(remoteUrl string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: gui.Tr.LcNewRemoteName, + HandleConfirm: func(remoteName string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: gui.Tr.LcNewRemoteUrl, + HandleConfirm: func(remoteUrl string) error { gui.logAction(gui.Tr.Actions.AddRemote) if err := gui.Git.Remote.AddRemote(remoteName, remoteUrl); err != nil { return err } - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{REMOTES}}) + return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.REMOTES}}) }, }) }, @@ -103,16 +105,16 @@ func (gui *Gui) handleRemoveRemote() error { return nil } - return gui.ask(askOpts{ - title: gui.Tr.LcRemoveRemote, - prompt: gui.Tr.LcRemoveRemotePrompt + " '" + remote.Name + "'?", - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.LcRemoveRemote, + Prompt: gui.Tr.LcRemoveRemotePrompt + " '" + remote.Name + "'?", + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.RemoveRemote) if err := gui.Git.Remote.RemoveRemote(remote.Name); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{BRANCHES, REMOTES}}) + return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) }, }) } @@ -130,14 +132,14 @@ func (gui *Gui) handleEditRemote() error { }, ) - return gui.prompt(promptOpts{ - title: editNameMessage, - initialContent: remote.Name, - handleConfirm: func(updatedRemoteName string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: editNameMessage, + InitialContent: remote.Name, + HandleConfirm: func(updatedRemoteName string) error { if updatedRemoteName != remote.Name { gui.logAction(gui.Tr.Actions.UpdateRemote) if err := gui.Git.Remote.RenameRemote(remote.Name, updatedRemoteName); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } } @@ -154,15 +156,15 @@ func (gui *Gui) handleEditRemote() error { url = urls[0] } - return gui.prompt(promptOpts{ - title: editUrlMessage, - initialContent: url, - handleConfirm: func(updatedRemoteUrl string) error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: editUrlMessage, + InitialContent: url, + HandleConfirm: func(updatedRemoteUrl string) error { gui.logAction(gui.Tr.Actions.UpdateRemote) if err := gui.Git.Remote.UpdateRemoteUrl(updatedRemoteName, updatedRemoteUrl); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{BRANCHES, REMOTES}}) + return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) }, }) }, @@ -175,13 +177,15 @@ func (gui *Gui) handleFetchRemote() error { return nil } - return gui.WithWaitingStatus(gui.Tr.FetchingRemoteStatus, func() error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.FetchingRemoteStatus, func() error { gui.Mutexes.FetchMutex.Lock() defer gui.Mutexes.FetchMutex.Unlock() err := gui.Git.Sync.FetchRemote(remote.Name) - gui.handleCredentialsPopup(err) + if err != nil { + _ = gui.PopupHandler.Error(err) + } - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{BRANCHES, REMOTES}}) + return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) }) } diff --git a/pkg/gui/reset_menu_panel.go b/pkg/gui/reset_menu_panel.go index 586987778..d920765f9 100644 --- a/pkg/gui/reset_menu_panel.go +++ b/pkg/gui/reset_menu_panel.go @@ -3,12 +3,14 @@ package gui import ( "fmt" + "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/style" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) func (gui *Gui) resetToRef(ref string, strength string, envVars []string) error { if err := gui.Git.Commit.ResetToCommit(ref, strength, envVars); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.State.Panels.Commits.SelectedLineIdx = 0 @@ -20,7 +22,7 @@ func (gui *Gui) resetToRef(ref string, strength string, envVars []string) error return err } - if err := gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES, BRANCHES, REFLOG, COMMITS}}); err != nil { + if err := gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES, types.BRANCHES, types.REFLOG, types.COMMITS}}); err != nil { return err } @@ -29,20 +31,23 @@ func (gui *Gui) resetToRef(ref string, strength string, envVars []string) error func (gui *Gui) createResetMenu(ref string) error { strengths := []string{"soft", "mixed", "hard"} - menuItems := make([]*menuItem, len(strengths)) + menuItems := make([]*popup.MenuItem, len(strengths)) for i, strength := range strengths { strength := strength - menuItems[i] = &menuItem{ - displayStrings: []string{ + menuItems[i] = &popup.MenuItem{ + DisplayStrings: []string{ fmt.Sprintf("%s reset", strength), style.FgRed.Sprintf("reset --%s %s", strength, ref), }, - onPress: func() error { + OnPress: func() error { gui.logAction("Reset") return gui.resetToRef(ref, strength, []string{}) }, } } - return gui.createMenu(fmt.Sprintf("%s %s", gui.Tr.LcResetTo, ref), menuItems, createMenuOptions{showCancel: true}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{ + Title: fmt.Sprintf("%s %s", gui.Tr.LcResetTo, ref), + Items: menuItems, + }) } diff --git a/pkg/gui/staging_panel.go b/pkg/gui/staging_panel.go index ecb208dcc..f4cd98ea2 100644 --- a/pkg/gui/staging_panel.go +++ b/pkg/gui/staging_panel.go @@ -4,6 +4,8 @@ import ( "strings" "github.com/jesseduffield/lazygit/pkg/commands/patch" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) func (gui *Gui) refreshStagingPanel(forceSecondaryFocused bool, selectedLineIdx int) error { @@ -112,10 +114,10 @@ func (gui *Gui) handleResetSelection() error { } if !gui.UserConfig.Gui.SkipUnstageLineWarning { - return gui.ask(askOpts{ - title: gui.Tr.UnstageLinesTitle, - prompt: gui.Tr.UnstageLinesPrompt, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.UnstageLinesTitle, + Prompt: gui.Tr.UnstageLinesPrompt, + HandleConfirm: func() error { return gui.withLBLActiveCheck(func(state *LblPanelState) error { return gui.applySelection(true, state) }) @@ -149,14 +151,14 @@ func (gui *Gui) applySelection(reverse bool, state *LblPanelState) error { gui.logAction(gui.Tr.Actions.ApplyPatch) err := gui.Git.WorkingTree.ApplyPatch(patch, applyFlags...) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } if state.SelectingRange() { state.SetLineSelectMode() } - if err := gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}); err != nil { + if err := gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}); err != nil { return err } if err := gui.refreshStagingPanel(false, -1); err != nil { diff --git a/pkg/gui/stash_panel.go b/pkg/gui/stash_panel.go index 2b9bae445..f8121bf94 100644 --- a/pkg/gui/stash_panel.go +++ b/pkg/gui/stash_panel.go @@ -2,6 +2,8 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) // list panel functions @@ -54,7 +56,7 @@ func (gui *Gui) handleStashApply() error { err := gui.Git.Stash.Apply(stashEntry.Index) _ = gui.postStashRefresh() if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return nil } @@ -63,10 +65,10 @@ func (gui *Gui) handleStashApply() error { return apply() } - return gui.ask(askOpts{ - title: gui.Tr.StashApply, - prompt: gui.Tr.SureApplyStashEntry, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.StashApply, + Prompt: gui.Tr.SureApplyStashEntry, + HandleConfirm: func() error { return apply() }, }) @@ -85,7 +87,7 @@ func (gui *Gui) handleStashPop() error { err := gui.Git.Stash.Pop(stashEntry.Index) _ = gui.postStashRefresh() if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return nil } @@ -94,10 +96,10 @@ func (gui *Gui) handleStashPop() error { return pop() } - return gui.ask(askOpts{ - title: gui.Tr.StashPop, - prompt: gui.Tr.SurePopStashEntry, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.StashPop, + Prompt: gui.Tr.SurePopStashEntry, + HandleConfirm: func() error { return pop() }, }) @@ -109,15 +111,15 @@ func (gui *Gui) handleStashDrop() error { return nil } - return gui.ask(askOpts{ - title: gui.Tr.StashDrop, - prompt: gui.Tr.SureDropStashEntry, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.StashDrop, + Prompt: gui.Tr.SureDropStashEntry, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.Stash) err := gui.Git.Stash.Drop(stashEntry.Index) _ = gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{STASH}}) if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return nil }, @@ -125,12 +127,12 @@ func (gui *Gui) handleStashDrop() error { } func (gui *Gui) postStashRefresh() error { - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{STASH, FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}}) } func (gui *Gui) handleStashSave(stashFunc func(message string) error) error { if len(gui.trackedFiles()) == 0 && len(gui.stagedFiles()) == 0 { - return gui.createErrorPanel(gui.Tr.NoTrackedStagedFilesStash) + return gui.PopupHandler.ErrorMsg(gui.Tr.NoTrackedStagedFilesStash) } return gui.prompt(promptOpts{ @@ -139,7 +141,7 @@ func (gui *Gui) handleStashSave(stashFunc func(message string) error) error { err := stashFunc(stashComment) _ = gui.postStashRefresh() if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return nil }, diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go index 444c32da1..d9fff2913 100644 --- a/pkg/gui/status_panel.go +++ b/pkg/gui/status_panel.go @@ -7,6 +7,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/constants" + "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/utils" @@ -49,8 +50,10 @@ func cursorInSubstring(cx int, prefix string, substring string) bool { } func (gui *Gui) handleCheckForUpdate() error { - gui.Updater.CheckForNewUpdate(gui.onUserUpdateCheckFinish, true) - return gui.createLoaderPanel(gui.Tr.CheckingForUpdates) + return gui.PopupHandler.WithWaitingStatus(gui.Tr.CheckingForUpdates, func() error { + gui.Updater.CheckForNewUpdate(gui.onUserUpdateCheckFinish, true) + return nil + }) } func (gui *Gui) handleStatusClick() error { @@ -136,17 +139,21 @@ func (gui *Gui) askForConfigFile(action func(file string) error) error { case 1: return action(confPaths[0]) default: - menuItems := make([]*menuItem, len(confPaths)) + menuItems := make([]*popup.MenuItem, len(confPaths)) for i, file := range confPaths { i := i - menuItems[i] = &menuItem{ - displayString: file, - onPress: func() error { + menuItems[i] = &popup.MenuItem{ + DisplayString: file, + OnPress: func() error { return action(confPaths[i]) }, } } - return gui.createMenu(gui.Tr.SelectConfigFile, menuItems, createMenuOptions{}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{ + Title: gui.Tr.SelectConfigFile, + Items: menuItems, + HideCancel: true, + }) } } diff --git a/pkg/gui/sub_commits_panel.go b/pkg/gui/sub_commits_panel.go index d023d261f..97f57d158 100644 --- a/pkg/gui/sub_commits_panel.go +++ b/pkg/gui/sub_commits_panel.go @@ -3,6 +3,7 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/loaders" "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/popup" ) // list panel functions @@ -42,10 +43,10 @@ func (gui *Gui) handleCheckoutSubCommit() error { return nil } - err := gui.ask(askOpts{ - title: gui.Tr.LcCheckoutCommit, - prompt: gui.Tr.SureCheckoutThisCommit, - handleConfirm: func() error { + err := gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.LcCheckoutCommit, + Prompt: gui.Tr.SureCheckoutThisCommit, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.CheckoutCommit) return gui.handleCheckoutRef(commit.Sha, handleCheckoutRefOptions{}) }, diff --git a/pkg/gui/submodules_panel.go b/pkg/gui/submodules_panel.go index be0574356..e63634bc6 100644 --- a/pkg/gui/submodules_panel.go +++ b/pkg/gui/submodules_panel.go @@ -3,8 +3,6 @@ package gui import ( "fmt" "os" - "path/filepath" - "strings" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/style" @@ -36,7 +34,7 @@ func (gui *Gui) submodulesRenderToMain() error { if file == nil { task = NewRenderStringTask(prefix) } else { - cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(file, false, !file.HasUnstagedChanges && file.HasStagedChanges, gui.State.IgnoreWhitespaceInDiffView) + cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(file, false, !file.HasUnstagedChanges && file.HasStagedChanges, gui.IgnoreWhitespaceInDiffView) task = NewRunCommandTaskWithPrefix(cmdObj.GetCmd(), prefix) } } @@ -60,205 +58,12 @@ func (gui *Gui) refreshStateSubmoduleConfigs() error { return nil } -func (gui *Gui) handleSubmoduleEnter(submodule *models.SubmoduleConfig) error { - return gui.enterSubmodule(submodule) -} - func (gui *Gui) enterSubmodule(submodule *models.SubmoduleConfig) error { wd, err := os.Getwd() if err != nil { return err } - gui.RepoPathStack = append(gui.RepoPathStack, wd) + gui.RepoPathStack.Push(wd) return gui.dispatchSwitchToRepo(submodule.Path, true) } - -func (gui *Gui) removeSubmodule(submodule *models.SubmoduleConfig) error { - return gui.ask(askOpts{ - title: gui.Tr.RemoveSubmodule, - prompt: fmt.Sprintf(gui.Tr.RemoveSubmodulePrompt, submodule.Name), - handleConfirm: func() error { - gui.logAction(gui.Tr.Actions.RemoveSubmodule) - if err := gui.Git.Submodule.Delete(submodule); err != nil { - return gui.surfaceError(err) - } - - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES, FILES}}) - }, - }) -} - -func (gui *Gui) handleResetSubmodule(submodule *models.SubmoduleConfig) error { - return gui.WithWaitingStatus(gui.Tr.LcResettingSubmoduleStatus, func() error { - return gui.resetSubmodule(submodule) - }) -} - -func (gui *Gui) fileForSubmodule(submodule *models.SubmoduleConfig) *models.File { - for _, file := range gui.State.FileTreeViewModel.GetAllFiles() { - if file.IsSubmodule([]*models.SubmoduleConfig{submodule}) { - return file - } - } - - return nil -} - -func (gui *Gui) resetSubmodule(submodule *models.SubmoduleConfig) error { - gui.logAction(gui.Tr.Actions.ResetSubmodule) - - file := gui.fileForSubmodule(submodule) - if file != nil { - if err := gui.Git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil { - return gui.surfaceError(err) - } - } - - if err := gui.Git.Submodule.Stash(submodule); err != nil { - return gui.surfaceError(err) - } - if err := gui.Git.Submodule.Reset(submodule); err != nil { - return gui.surfaceError(err) - } - - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES, SUBMODULES}}) -} - -func (gui *Gui) handleAddSubmodule() error { - return gui.prompt(promptOpts{ - title: gui.Tr.LcNewSubmoduleUrl, - handleConfirm: func(submoduleUrl string) error { - nameSuggestion := filepath.Base(strings.TrimSuffix(submoduleUrl, filepath.Ext(submoduleUrl))) - - return gui.prompt(promptOpts{ - title: gui.Tr.LcNewSubmoduleName, - initialContent: nameSuggestion, - handleConfirm: func(submoduleName string) error { - - return gui.prompt(promptOpts{ - title: gui.Tr.LcNewSubmodulePath, - initialContent: submoduleName, - handleConfirm: func(submodulePath string) error { - return gui.WithWaitingStatus(gui.Tr.LcAddingSubmoduleStatus, func() error { - gui.logAction(gui.Tr.Actions.AddSubmodule) - err := gui.Git.Submodule.Add(submoduleName, submodulePath, submoduleUrl) - gui.handleCredentialsPopup(err) - - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}}) - }) - }, - }) - }, - }) - }, - }) - -} - -func (gui *Gui) handleEditSubmoduleUrl(submodule *models.SubmoduleConfig) error { - return gui.prompt(promptOpts{ - title: fmt.Sprintf(gui.Tr.LcUpdateSubmoduleUrl, submodule.Name), - initialContent: submodule.Url, - handleConfirm: func(newUrl string) error { - return gui.WithWaitingStatus(gui.Tr.LcUpdatingSubmoduleUrlStatus, func() error { - gui.logAction(gui.Tr.Actions.UpdateSubmoduleUrl) - err := gui.Git.Submodule.UpdateUrl(submodule.Name, submodule.Path, newUrl) - gui.handleCredentialsPopup(err) - - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}}) - }) - }, - }) -} - -func (gui *Gui) handleSubmoduleInit(submodule *models.SubmoduleConfig) error { - return gui.WithWaitingStatus(gui.Tr.LcInitializingSubmoduleStatus, func() error { - gui.logAction(gui.Tr.Actions.InitialiseSubmodule) - err := gui.Git.Submodule.Init(submodule.Path) - gui.handleCredentialsPopup(err) - - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}}) - }) -} - -func (gui *Gui) forSubmodule(callback func(*models.SubmoduleConfig) error) func() error { - return func() error { - submodule := gui.getSelectedSubmodule() - if submodule == nil { - return nil - } - - return callback(submodule) - } -} - -func (gui *Gui) handleBulkSubmoduleActionsMenu() error { - menuItems := []*menuItem{ - { - displayStrings: []string{gui.Tr.LcBulkInitSubmodules, style.FgGreen.Sprint(gui.Git.Submodule.BulkInitCmdObj().ToString())}, - onPress: func() error { - return gui.WithWaitingStatus(gui.Tr.LcRunningCommand, func() error { - gui.logAction(gui.Tr.Actions.BulkInitialiseSubmodules) - err := gui.Git.Submodule.BulkInitCmdObj().Run() - if err != nil { - return gui.surfaceError(err) - } - - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}}) - }) - }, - }, - { - displayStrings: []string{gui.Tr.LcBulkUpdateSubmodules, style.FgYellow.Sprint(gui.Git.Submodule.BulkUpdateCmdObj().ToString())}, - onPress: func() error { - return gui.WithWaitingStatus(gui.Tr.LcRunningCommand, func() error { - gui.logAction(gui.Tr.Actions.BulkUpdateSubmodules) - if err := gui.Git.Submodule.BulkUpdateCmdObj().Run(); err != nil { - return gui.surfaceError(err) - } - - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}}) - }) - }, - }, - { - displayStrings: []string{gui.Tr.LcSubmoduleStashAndReset, style.FgRed.Sprintf("git stash in each submodule && %s", gui.Git.Submodule.ForceBulkUpdateCmdObj().ToString())}, - onPress: func() error { - return gui.WithWaitingStatus(gui.Tr.LcRunningCommand, func() error { - gui.logAction(gui.Tr.Actions.BulkStashAndResetSubmodules) - if err := gui.Git.Submodule.ResetSubmodules(gui.State.Submodules); err != nil { - return gui.surfaceError(err) - } - - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}}) - }) - }, - }, - { - displayStrings: []string{gui.Tr.LcBulkDeinitSubmodules, style.FgRed.Sprint(gui.Git.Submodule.BulkDeinitCmdObj().ToString())}, - onPress: func() error { - return gui.WithWaitingStatus(gui.Tr.LcRunningCommand, func() error { - gui.logAction(gui.Tr.Actions.BulkDeinitialiseSubmodules) - if err := gui.Git.Submodule.BulkDeinitCmdObj().Run(); err != nil { - return gui.surfaceError(err) - } - - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}}) - }) - }, - }, - } - - return gui.createMenu(gui.Tr.LcBulkSubmoduleOptions, menuItems, createMenuOptions{showCancel: true}) -} - -func (gui *Gui) handleUpdateSubmodule(submodule *models.SubmoduleConfig) error { - return gui.WithWaitingStatus(gui.Tr.LcUpdatingSubmoduleStatus, func() error { - gui.logAction(gui.Tr.Actions.UpdateSubmodule) - err := gui.Git.Submodule.Update(submodule.Path) - gui.handleCredentialsPopup(err) - - return gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{SUBMODULES}}) - }) -} diff --git a/pkg/gui/tags_panel.go b/pkg/gui/tags_panel.go index efad33fbf..9f516a006 100644 --- a/pkg/gui/tags_panel.go +++ b/pkg/gui/tags_panel.go @@ -2,6 +2,8 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -41,7 +43,7 @@ func (gui *Gui) tagsRenderToMain() error { func (gui *Gui) refreshTags() error { tags, err := gui.Git.Loaders.Tags.GetTags() if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } gui.State.Tags = tags @@ -78,15 +80,15 @@ func (gui *Gui) handleDeleteTag(tag *models.Tag) error { }, ) - return gui.ask(askOpts{ - title: gui.Tr.DeleteTagTitle, - prompt: prompt, - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.DeleteTagTitle, + Prompt: prompt, + HandleConfirm: func() error { gui.logAction(gui.Tr.Actions.DeleteTag) if err := gui.Git.Tag.Delete(tag.Name); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{COMMITS, TAGS}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}}) }, }) } @@ -99,15 +101,17 @@ func (gui *Gui) handlePushTag(tag *models.Tag) error { }, ) - return gui.prompt(promptOpts{ - title: title, - initialContent: "origin", - findSuggestionsFunc: gui.getRemoteSuggestionsFunc(), - handleConfirm: func(response string) error { - return gui.WithWaitingStatus(gui.Tr.PushingTagStatus, func() error { + return gui.PopupHandler.Prompt(popup.PromptOpts{ + Title: title, + InitialContent: "origin", + FindSuggestionsFunc: gui.getRemoteSuggestionsFunc(), + HandleConfirm: func(response string) error { + return gui.PopupHandler.WithWaitingStatus(gui.Tr.PushingTagStatus, func() error { gui.logAction(gui.Tr.Actions.PushTag) err := gui.Git.Tag.Push(response, tag.Name) - gui.handleCredentialsPopup(err) + if err != nil { + _ = gui.PopupHandler.Error(err) + } return nil }) diff --git a/pkg/gui/types/keybindings.go b/pkg/gui/types/keybindings.go new file mode 100644 index 000000000..abe3f84d0 --- /dev/null +++ b/pkg/gui/types/keybindings.go @@ -0,0 +1,18 @@ +package types + +import "github.com/jesseduffield/gocui" + +// Binding - a keybinding mapping a key and modifier to a handler. The keypress +// is only handled if the given view has focus, or handled globally if the view +// is "" +type Binding struct { + ViewName string + Contexts []string + Handler func() error + Key interface{} // FIXME: find out how to get `gocui.Key | rune` + Modifier gocui.Modifier + Description string + Alternative string + Tag string // e.g. 'navigation'. Used for grouping things in the cheatsheet + OpensMenu bool +} diff --git a/pkg/gui/types/refresh.go b/pkg/gui/types/refresh.go new file mode 100644 index 000000000..d0cbe02ba --- /dev/null +++ b/pkg/gui/types/refresh.go @@ -0,0 +1,32 @@ +package types + +// models/views that we can refresh +type RefreshableView int + +const ( + COMMITS RefreshableView = iota + BRANCHES + FILES + STASH + REFLOG + TAGS + REMOTES + STATUS + SUBMODULES + // not actually a view. Will refactor this later + BISECT_INFO +) + +type RefreshMode int + +const ( + SYNC RefreshMode = iota // wait until everything is done before returning + ASYNC // return immediately, allowing each independent thing to update itself + BLOCK_UI // wrap code in an update call to ensure UI updates all at once and keybindings aren't executed till complete +) + +type RefreshOptions struct { + Then func() + Scope []RefreshableView // e.g. []int{COMMITS, BRANCHES}. Leave empty to refresh everything + Mode RefreshMode // one of SYNC (default), ASYNC, and BLOCK_UI +} diff --git a/pkg/gui/undoing.go b/pkg/gui/undoing.go index 72a4ef302..e61950700 100644 --- a/pkg/gui/undoing.go +++ b/pkg/gui/undoing.go @@ -2,6 +2,8 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/types/enums" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -89,7 +91,7 @@ func (gui *Gui) reflogUndo() error { undoingStatus := gui.Tr.UndoingStatus if gui.Git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING { - return gui.createErrorPanel(gui.Tr.LcCantUndoWhileRebasing) + return gui.PopupHandler.ErrorMsg(gui.Tr.LcCantUndoWhileRebasing) } return gui.parseReflogForActions(func(counter int, action reflogAction) (bool, error) { @@ -124,7 +126,7 @@ func (gui *Gui) reflogRedo() error { redoingStatus := gui.Tr.RedoingStatus if gui.Git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING { - return gui.createErrorPanel(gui.Tr.LcCantRedoWhileRebasing) + return gui.PopupHandler.ErrorMsg(gui.Tr.LcCantRedoWhileRebasing) } return gui.parseReflogForActions(func(counter int, action reflogAction) (bool, error) { @@ -166,7 +168,7 @@ type handleHardResetWithAutoStashOptions struct { func (gui *Gui) handleHardResetWithAutoStash(commitSha string, options handleHardResetWithAutoStashOptions) error { reset := func() error { if err := gui.resetToRef(commitSha, "hard", options.EnvVars); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return nil } @@ -175,24 +177,24 @@ func (gui *Gui) handleHardResetWithAutoStash(commitSha string, options handleHar dirtyWorkingTree := len(gui.trackedFiles()) > 0 || len(gui.stagedFiles()) > 0 if dirtyWorkingTree { // offer to autostash changes - return gui.ask(askOpts{ - title: gui.Tr.AutoStashTitle, - prompt: gui.Tr.AutoStashPrompt, - handleConfirm: func() error { - return gui.WithWaitingStatus(options.WaitingStatus, func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: gui.Tr.AutoStashTitle, + Prompt: gui.Tr.AutoStashPrompt, + HandleConfirm: func() error { + return gui.PopupHandler.WithWaitingStatus(options.WaitingStatus, func() error { if err := gui.Git.Stash.Save(gui.Tr.StashPrefix + commitSha); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } if err := reset(); err != nil { return err } err := gui.Git.Stash.Pop(0) - if err := gui.refreshSidePanels(refreshOptions{}); err != nil { + if err := gui.refreshSidePanels(types.RefreshOptions{}); err != nil { return err } if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } return nil }) @@ -200,7 +202,7 @@ func (gui *Gui) handleHardResetWithAutoStash(commitSha string, options handleHar }) } - return gui.WithWaitingStatus(options.WaitingStatus, func() error { + return gui.PopupHandler.WithWaitingStatus(options.WaitingStatus, func() error { return reset() }) } diff --git a/pkg/gui/updates.go b/pkg/gui/updates.go index cce723c4f..5eb08dae3 100644 --- a/pkg/gui/updates.go +++ b/pkg/gui/updates.go @@ -4,13 +4,14 @@ import ( "fmt" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/popup" ) func (gui *Gui) showUpdatePrompt(newVersion string) error { - return gui.ask(askOpts{ - title: "New version available!", - prompt: fmt.Sprintf("Download version %s? (enter/esc)", newVersion), - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: "New version available!", + Prompt: fmt.Sprintf("Download version %s? (enter/esc)", newVersion), + HandleConfirm: func() error { gui.startUpdating(newVersion) return nil }, @@ -19,10 +20,10 @@ func (gui *Gui) showUpdatePrompt(newVersion string) error { func (gui *Gui) onUserUpdateCheckFinish(newVersion string, err error) error { if err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } if newVersion == "" { - return gui.createErrorPanel("New version not found") + return gui.PopupHandler.ErrorMsg("New version not found") } return gui.showUpdatePrompt(newVersion) } @@ -55,7 +56,7 @@ func (gui *Gui) onUpdateFinish(statusId int, err error) error { gui.OnUIThread(func() error { _ = gui.renderString(gui.Views.AppStatus, "") if err != nil { - return gui.createErrorPanel("Update failed: " + err.Error()) + return gui.PopupHandler.ErrorMsg("Update failed: " + err.Error()) } return nil }) @@ -64,10 +65,10 @@ func (gui *Gui) onUpdateFinish(statusId int, err error) error { } func (gui *Gui) createUpdateQuitConfirmation() error { - return gui.ask(askOpts{ - title: "Currently Updating", - prompt: "An update is in progress. Are you sure you want to quit?", - handleConfirm: func() error { + return gui.PopupHandler.Ask(popup.AskOpts{ + Title: "Currently Updating", + Prompt: "An update is in progress. Are you sure you want to quit?", + HandleConfirm: func() error { return gocui.ErrQuit }, }) diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index 300571ad3..089cee454 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -7,6 +7,7 @@ import ( "sync" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/spkg/bom" ) @@ -15,34 +16,18 @@ func (gui *Gui) getCyclableWindows() []string { return []string{"status", "files", "branches", "commits", "stash"} } -// models/views that we can refresh -type RefreshableView int - -const ( - COMMITS RefreshableView = iota - BRANCHES - FILES - STASH - REFLOG - TAGS - REMOTES - STATUS - SUBMODULES - // not actually a view. Will refactor this later - BISECT_INFO -) - -func getScopeNames(scopes []RefreshableView) []string { - scopeNameMap := map[RefreshableView]string{ - COMMITS: "commits", - BRANCHES: "branches", - FILES: "files", - SUBMODULES: "submodules", - STASH: "stash", - REFLOG: "reflog", - TAGS: "tags", - REMOTES: "remotes", - STATUS: "status", +func getScopeNames(scopes []types.RefreshableView) []string { + scopeNameMap := map[types.RefreshableView]string{ + types.COMMITS: "commits", + types.BRANCHES: "branches", + types.FILES: "files", + types.SUBMODULES: "submodules", + types.STASH: "stash", + types.REFLOG: "reflog", + types.TAGS: "tags", + types.REMOTES: "remotes", + types.STATUS: "status", + types.BISECT_INFO: "bisect", } scopeNames := make([]string, len(scopes)) @@ -53,69 +38,55 @@ func getScopeNames(scopes []RefreshableView) []string { return scopeNames } -func getModeName(mode RefreshMode) string { +func getModeName(mode types.RefreshMode) string { switch mode { - case SYNC: + case types.SYNC: return "sync" - case ASYNC: + case types.ASYNC: return "async" - case BLOCK_UI: + case types.BLOCK_UI: return "block-ui" default: return "unknown mode" } } -type RefreshMode int - -const ( - SYNC RefreshMode = iota // wait until everything is done before returning - ASYNC // return immediately, allowing each independent thing to update itself - BLOCK_UI // wrap code in an update call to ensure UI updates all at once and keybindings aren't executed till complete -) - -type refreshOptions struct { - then func() - scope []RefreshableView // e.g. []int{COMMITS, BRANCHES}. Leave empty to refresh everything - mode RefreshMode // one of SYNC (default), ASYNC, and BLOCK_UI -} - -func arrToMap(arr []RefreshableView) map[RefreshableView]bool { - output := map[RefreshableView]bool{} +func arrToMap(arr []types.RefreshableView) map[types.RefreshableView]bool { + output := map[types.RefreshableView]bool{} for _, el := range arr { output[el] = true } return output } -func (gui *Gui) refreshSidePanels(options refreshOptions) error { - if options.scope == nil { +func (gui *Gui) refreshSidePanels(options types.RefreshOptions) error { + if options.Scope == nil { gui.Log.Infof( "refreshing all scopes in %s mode", - getModeName(options.mode), + getModeName(options.Mode), ) } else { gui.Log.Infof( "refreshing the following scopes in %s mode: %s", - getModeName(options.mode), - strings.Join(getScopeNames(options.scope), ","), + getModeName(options.Mode), + strings.Join(getScopeNames(options.Scope), ","), ) } wg := sync.WaitGroup{} f := func() { - var scopeMap map[RefreshableView]bool - if len(options.scope) == 0 { - scopeMap = arrToMap([]RefreshableView{COMMITS, BRANCHES, FILES, STASH, REFLOG, TAGS, REMOTES, STATUS, BISECT_INFO}) + var scopeMap map[types.RefreshableView]bool + if len(options.Scope) == 0 { + scopeMap = arrToMap([]types.RefreshableView{types.COMMITS, types.BRANCHES, types.FILES, types.STASH, types.REFLOG, types.TAGS, types.REMOTES, types.STATUS, types.BISECT_INFO}) } else { - scopeMap = arrToMap(options.scope) + scopeMap = arrToMap(options.Scope) } - if scopeMap[COMMITS] || scopeMap[BRANCHES] || scopeMap[REFLOG] || scopeMap[BISECT_INFO] { + if scopeMap[types.COMMITS] || scopeMap[types.BRANCHES] || scopeMap[types.REFLOG] || scopeMap[types.BISECT_INFO] { wg.Add(1) func() { - if options.mode == ASYNC { + if options.Mode == types.ASYNC { go utils.Safe(func() { gui.refreshCommits() }) } else { gui.refreshCommits() @@ -124,10 +95,10 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error { }() } - if scopeMap[FILES] || scopeMap[SUBMODULES] { + if scopeMap[types.FILES] || scopeMap[types.SUBMODULES] { wg.Add(1) func() { - if options.mode == ASYNC { + if options.Mode == types.ASYNC { go utils.Safe(func() { _ = gui.refreshFilesAndSubmodules() }) } else { _ = gui.refreshFilesAndSubmodules() @@ -136,10 +107,10 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error { }() } - if scopeMap[STASH] { + if scopeMap[types.STASH] { wg.Add(1) func() { - if options.mode == ASYNC { + if options.Mode == types.ASYNC { go utils.Safe(func() { _ = gui.refreshStashEntries() }) } else { _ = gui.refreshStashEntries() @@ -148,10 +119,10 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error { }() } - if scopeMap[TAGS] { + if scopeMap[types.TAGS] { wg.Add(1) func() { - if options.mode == ASYNC { + if options.Mode == types.ASYNC { go utils.Safe(func() { _ = gui.refreshTags() }) } else { _ = gui.refreshTags() @@ -160,10 +131,10 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error { }() } - if scopeMap[REMOTES] { + if scopeMap[types.REMOTES] { wg.Add(1) func() { - if options.mode == ASYNC { + if options.Mode == types.ASYNC { go utils.Safe(func() { _ = gui.refreshRemotes() }) } else { _ = gui.refreshRemotes() @@ -176,12 +147,12 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error { gui.refreshStatus() - if options.then != nil { - options.then() + if options.Then != nil { + options.Then() } } - if options.mode == BLOCK_UI { + if options.Mode == types.BLOCK_UI { gui.OnUIThread(func() error { f() return nil diff --git a/pkg/gui/whitespace-toggle.go b/pkg/gui/whitespace-toggle.go index e7df9d879..7ded50c18 100644 --- a/pkg/gui/whitespace-toggle.go +++ b/pkg/gui/whitespace-toggle.go @@ -1,10 +1,10 @@ package gui func (gui *Gui) toggleWhitespaceInDiffView() error { - gui.State.IgnoreWhitespaceInDiffView = !gui.State.IgnoreWhitespaceInDiffView + gui.IgnoreWhitespaceInDiffView = !gui.IgnoreWhitespaceInDiffView toastMessage := gui.Tr.ShowingWhitespaceInDiffView - if gui.State.IgnoreWhitespaceInDiffView { + if gui.IgnoreWhitespaceInDiffView { toastMessage = gui.Tr.IgnoringWhitespaceInDiffView } gui.raiseToast(toastMessage) diff --git a/pkg/gui/workspace_reset_options_panel.go b/pkg/gui/workspace_reset_options_panel.go index ba2df22e6..6230e0966 100644 --- a/pkg/gui/workspace_reset_options_panel.go +++ b/pkg/gui/workspace_reset_options_panel.go @@ -3,7 +3,9 @@ package gui import ( "fmt" + "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/style" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) func (gui *Gui) handleCreateResetMenu() error { @@ -14,92 +16,92 @@ func (gui *Gui) handleCreateResetMenu() error { nukeStr = fmt.Sprintf("%s (%s)", nukeStr, gui.Tr.LcAndResetSubmodules) } - menuItems := []*menuItem{ + menuItems := []*popup.MenuItem{ { - displayStrings: []string{ + DisplayStrings: []string{ gui.Tr.LcDiscardAllChangesToAllFiles, red.Sprint(nukeStr), }, - onPress: func() error { + OnPress: func() error { gui.logAction(gui.Tr.Actions.NukeWorkingTree) if err := gui.Git.WorkingTree.ResetAndClean(); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, { - displayStrings: []string{ + DisplayStrings: []string{ gui.Tr.LcDiscardAnyUnstagedChanges, red.Sprint("git checkout -- ."), }, - onPress: func() error { + OnPress: func() error { gui.logAction(gui.Tr.Actions.DiscardUnstagedFileChanges) if err := gui.Git.WorkingTree.DiscardAnyUnstagedFileChanges(); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, { - displayStrings: []string{ + DisplayStrings: []string{ gui.Tr.LcDiscardUntrackedFiles, red.Sprint("git clean -fd"), }, - onPress: func() error { + OnPress: func() error { gui.logAction(gui.Tr.Actions.RemoveUntrackedFiles) if err := gui.Git.WorkingTree.RemoveUntrackedFiles(); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, { - displayStrings: []string{ + DisplayStrings: []string{ gui.Tr.LcSoftReset, red.Sprint("git reset --soft HEAD"), }, - onPress: func() error { + OnPress: func() error { gui.logAction(gui.Tr.Actions.SoftReset) if err := gui.Git.WorkingTree.ResetSoft("HEAD"); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, { - displayStrings: []string{ + DisplayStrings: []string{ "mixed reset", red.Sprint("git reset --mixed HEAD"), }, - onPress: func() error { + OnPress: func() error { gui.logAction(gui.Tr.Actions.MixedReset) if err := gui.Git.WorkingTree.ResetMixed("HEAD"); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, { - displayStrings: []string{ + DisplayStrings: []string{ gui.Tr.LcHardReset, red.Sprint("git reset --hard HEAD"), }, - onPress: func() error { + OnPress: func() error { gui.logAction(gui.Tr.Actions.HardReset) if err := gui.Git.WorkingTree.ResetHard("HEAD"); err != nil { - return gui.surfaceError(err) + return gui.PopupHandler.Error(err) } - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{FILES}}) + return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, } - return gui.createMenu("", menuItems, createMenuOptions{showCancel: true}) + return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: "", Items: menuItems}) } diff --git a/pkg/i18n/chinese.go b/pkg/i18n/chinese.go index 3bc9e34d9..fc2983dee 100644 --- a/pkg/i18n/chinese.go +++ b/pkg/i18n/chinese.go @@ -504,7 +504,6 @@ func chineseTranslationSet() TranslationSet { InitialiseSubmodule: "鍒濆鍖栧瓙妯″潡", BulkInitialiseSubmodules: "鎵归噺鍒濆鍖栧瓙妯″潡", BulkUpdateSubmodules: "鎵归噺鏇存柊瀛愭ā鍧", - BulkStashAndResetSubmodules: "鎵归噺瀛樺偍鍜岄噸缃瓙妯″潡", BulkDeinitialiseSubmodules: "鎵归噺鍙栨秷鍒濆鍖栧瓙妯″潡", UpdateSubmodule: "鏇存柊瀛愭ā鍧", DeleteTag: "鍒犻櫎鏍囩", diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 381baa57b..f3b90a194 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -540,7 +540,6 @@ type Actions struct { InitialiseSubmodule string BulkInitialiseSubmodules string BulkUpdateSubmodules string - BulkStashAndResetSubmodules string BulkDeinitialiseSubmodules string UpdateSubmodule string CreateLightweightTag string @@ -651,7 +650,7 @@ func EnglishTranslationSet() TranslationSet { NoBranchesThisRepo: "No branches for this repo", CommitMessageConfirm: "{{.keyBindClose}}: close, {{.keyBindNewLine}}: new line, {{.keyBindConfirm}}: confirm", CommitWithoutMessageErr: "You cannot commit without a commit message", - CloseConfirm: "{{.keyBindClose}}: close, {{.keyBindConfirm}}: confirm", + CloseConfirm: "{{.keyBindClose}}: close/cancel, {{.keyBindConfirm}}: confirm", LcClose: "close", LcQuit: "quit", LcSquashDown: "squash down", @@ -1097,7 +1096,6 @@ func EnglishTranslationSet() TranslationSet { InitialiseSubmodule: "Initialise submodule", BulkInitialiseSubmodules: "Bulk initialise submodules", BulkUpdateSubmodules: "Bulk update submodules", - BulkStashAndResetSubmodules: "Bulk stash and reset submodules", BulkDeinitialiseSubmodules: "Bulk deinitialise submodules", UpdateSubmodule: "Update submodule", DeleteTag: "Delete tag", diff --git a/pkg/updates/updates.go b/pkg/updates/updates.go index 1c52d0419..95fcfa0eb 100644 --- a/pkg/updates/updates.go +++ b/pkg/updates/updates.go @@ -144,12 +144,10 @@ func (u *Updater) CheckForNewUpdate(onFinish func(string, error) error, userRequ return } - go utils.Safe(func() { - newVersion, err := u.checkForNewUpdate() - if err = onFinish(newVersion, err); err != nil { - u.Log.Error(err) - } - }) + newVersion, err := u.checkForNewUpdate() + if err = onFinish(newVersion, err); err != nil { + u.Log.Error(err) + } } func (u *Updater) skipUpdateCheck() bool { diff --git a/pkg/utils/string_stack.go b/pkg/utils/string_stack.go new file mode 100644 index 000000000..c2d18c70c --- /dev/null +++ b/pkg/utils/string_stack.go @@ -0,0 +1,27 @@ +package utils + +type StringStack struct { + stack []string +} + +func (self *StringStack) Push(s string) { + self.stack = append(self.stack, s) +} + +func (self *StringStack) Pop() string { + if len(self.stack) == 0 { + return "" + } + n := len(self.stack) - 1 + last := self.stack[n] + self.stack = self.stack[:n] + return last +} + +func (self *StringStack) IsEmpty() bool { + return len(self.stack) == 0 +} + +func (self *StringStack) Clear() { + self.stack = []string{} +} From 1dd7307fde033dae5fececac15810a99e26c3d91 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 16 Jan 2022 14:46:53 +1100 Subject: [PATCH 024/385] start moving commit panel handlers into controller more and more move rebase commit refreshing into existing abstraction and more and more WIP and more handling clicks properly fix merge conflicts update cheatsheet lots more preparation to start moving things into controllers WIP better typing expand on remotes controller moving more code into controllers --- docs/keybindings/Keybindings_en.md | 36 +- docs/keybindings/Keybindings_nl.md | 36 +- docs/keybindings/Keybindings_pl.md | 36 +- docs/keybindings/Keybindings_zh.md | 36 +- pkg/cheatsheet/generate.go | 17 +- pkg/commands/git.go | 6 +- pkg/commands/git_commands/common.go | 6 + pkg/commands/git_commands/remote.go | 2 +- pkg/commands/git_commands/sync.go | 10 +- pkg/commands/git_commands/tag.go | 2 +- pkg/commands/git_test.go | 8 +- pkg/commands/oscommands/cmd_obj.go | 17 + pkg/commands/oscommands/cmd_obj_runner.go | 33 +- pkg/gui/app_status_manager.go | 4 +- pkg/gui/arrangement.go | 11 +- pkg/gui/basic_context.go | 26 +- pkg/gui/bisect.go | 219 ----- pkg/gui/branches_panel.go | 265 ++---- pkg/gui/cherry_picking.go | 43 +- pkg/gui/command_log_panel.go | 14 +- pkg/gui/commit_files_panel.go | 110 ++- pkg/gui/commit_message_panel.go | 20 +- pkg/gui/commits_panel.go | 701 +-------------- pkg/gui/confirmation_panel.go | 21 +- pkg/gui/context.go | 104 +-- pkg/gui/context/context.go | 98 +++ pkg/gui/context_config.go | 183 ++-- pkg/gui/controllers/bisect_controller.go | 273 ++++++ pkg/gui/controllers/controller_common.go | 10 + pkg/gui/controllers/files_controller.go | 737 ++++++++++++++++ .../controllers/local_commits_controller.go | 783 +++++++++++++++++ pkg/gui/controllers/menu_controller.go | 70 ++ pkg/gui/controllers/remotes_controller.go | 204 +++++ pkg/gui/controllers/submodules_controller.go | 62 +- pkg/gui/controllers/sync_controller.go | 253 ++++++ pkg/gui/controllers/tags_controller.go | 229 +++++ pkg/gui/controllers/types.go | 53 +- .../undo_controller.go} | 242 ++++-- pkg/gui/credentials_panel.go | 15 +- pkg/gui/custom_commands.go | 66 +- pkg/gui/diff_context_size.go | 18 +- pkg/gui/diff_context_size_test.go | 50 +- pkg/gui/diffing.go | 26 +- pkg/gui/discard_changes_menu_panel.go | 46 +- pkg/gui/editors.go | 4 +- pkg/gui/extras_panel.go | 17 +- pkg/gui/file_helper.go | 51 ++ pkg/gui/file_watching.go | 4 +- pkg/gui/files_panel.go | 815 +----------------- pkg/gui/filetree/commit_file_node.go | 4 +- pkg/gui/filetree/file_node.go | 4 +- pkg/gui/filtering.go | 28 +- pkg/gui/filtering_menu_panel.go | 14 +- pkg/gui/git_flow.go | 20 +- pkg/gui/global_handlers.go | 38 +- pkg/gui/gpg.go | 18 +- pkg/gui/gui.go | 243 ++++-- pkg/gui/gui_common.go | 53 ++ pkg/gui/information_panel.go | 10 +- pkg/gui/keybindings.go | 751 +++++----------- pkg/gui/layout.go | 37 +- pkg/gui/line_by_line_panel.go | 8 +- pkg/gui/list_context.go | 116 +-- pkg/gui/list_context_config.go | 200 ++--- pkg/gui/main_panels.go | 2 +- pkg/gui/menu_panel.go | 25 +- pkg/gui/merge_panel.go | 47 +- pkg/gui/misc.go | 19 + pkg/gui/modes.go | 16 +- pkg/gui/options_menu_panel.go | 4 +- pkg/gui/patch_building_panel.go | 24 +- pkg/gui/patch_options_panel.go | 72 +- pkg/gui/popup/popup_handler.go | 26 + pkg/gui/pty.go | 4 +- pkg/gui/pull_request_menu_panel.go | 20 +- pkg/gui/quitting.go | 10 +- pkg/gui/rebase_options_panel.go | 46 +- pkg/gui/recent_repos_panel.go | 27 +- pkg/gui/ref_helper.go | 137 +++ pkg/gui/reflog_panel.go | 31 +- pkg/gui/remote_branches_panel.go | 36 +- pkg/gui/remotes_panel.go | 136 +-- pkg/gui/reset_menu_panel.go | 53 -- pkg/gui/searching.go | 4 +- pkg/gui/staging_panel.go | 30 +- pkg/gui/stash_panel.go | 76 +- pkg/gui/status_panel.go | 22 +- pkg/gui/style/style_test.go | 15 +- pkg/gui/sub_commits_panel.go | 31 +- pkg/gui/submodules_panel.go | 6 +- ...d_suggestions.go => suggestions_helper.go} | 88 +- pkg/gui/tags_panel.go | 106 +-- pkg/gui/tasks_adapter.go | 8 +- pkg/gui/types/common_commands.go | 7 + pkg/gui/types/context.go | 87 ++ pkg/gui/types/keybindings.go | 9 + pkg/gui/types/refresh.go | 1 + pkg/gui/updates.go | 14 +- pkg/gui/view_helpers.go | 96 +-- pkg/gui/whitespace-toggle.go | 6 +- pkg/gui/working_tree_helper.go | 50 ++ pkg/gui/workspace_reset_options_panel.go | 62 +- pkg/i18n/english.go | 2 + .../commit/expected/.git_keep/index | Bin 425 -> 425 bytes 104 files changed, 4980 insertions(+), 4111 deletions(-) delete mode 100644 pkg/gui/bisect.go create mode 100644 pkg/gui/context/context.go create mode 100644 pkg/gui/controllers/bisect_controller.go create mode 100644 pkg/gui/controllers/controller_common.go create mode 100644 pkg/gui/controllers/files_controller.go create mode 100644 pkg/gui/controllers/local_commits_controller.go create mode 100644 pkg/gui/controllers/menu_controller.go create mode 100644 pkg/gui/controllers/remotes_controller.go create mode 100644 pkg/gui/controllers/sync_controller.go create mode 100644 pkg/gui/controllers/tags_controller.go rename pkg/gui/{undoing.go => controllers/undo_controller.go} (56%) create mode 100644 pkg/gui/file_helper.go create mode 100644 pkg/gui/gui_common.go create mode 100644 pkg/gui/misc.go create mode 100644 pkg/gui/ref_helper.go delete mode 100644 pkg/gui/reset_menu_panel.go rename pkg/gui/{find_suggestions.go => suggestions_helper.go} (61%) create mode 100644 pkg/gui/types/common_commands.go create mode 100644 pkg/gui/types/context.go create mode 100644 pkg/gui/working_tree_helper.go diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index 43e586897..09a933f81 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -123,30 +123,30 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Commits Panel (Commits) - ctrl+l: open log menu - s: squash down - r: reword commit - R: reword commit with editor - g: reset to this commit - f: fixup commit - F: create fixup commit for this commit - S: squash all 'fixup!' commits above selected commit (autosquash) - d: delete commit - ctrl+j: move commit down one - ctrl+k: move commit up one - e: edit commit - A: amend commit with staged changes - p: pick commit (when mid-rebase) - t: revert commit c: copy commit (cherry-pick) ctrl+o: copy commit SHA to clipboard C: copy commit range (cherry-pick) v: paste commits (cherry-pick) + n: create new branch off of commit + ctrl+r: reset cherry-picked (copied) commits selection + s: squash down + f: fixup commit + r: reword commit + R: reword commit with editor + d: delete commit + e: edit commit + p: pick commit (when mid-rebase) + F: create fixup commit for this commit + S: squash all 'fixup!' commits above selected commit (autosquash) + ctrl+j: move commit down one + ctrl+k: move commit up one + A: amend commit with staged changes + t: revert commit + ctrl+l: open log menu + g: reset to this commit enter: view commit's files space: checkout commit - n: create new branch off of commit T: tag commit - ctrl+r: reset cherry-picked (copied) commits selection ctrl+y: copy commit message to clipboard o: open commit in browser b: view bisect options @@ -183,7 +183,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct w: commit changes without pre-commit hook A: amend last commit C: commit changes using git editor - space: toggle staged d: view 'discard changes' options e: edit file o: open file @@ -200,6 +199,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct `: toggle file tree view M: open external merge tool (git mergetool) ctrl+w: Toggle whether or not whitespace changes are shown in the diff view + space: toggle staged## Files Panel (Submodules) diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index 7d5b8f78c..5e0d62fac 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -123,30 +123,30 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Commits Paneel (Commits)- ctrl+l: open log menu - s: squash beneden - r: hernoem commit - R: hernoem commit met editor - g: reset naar deze commit - f: Fixup commit - F: cre毛er fixup commit voor deze commit - S: squash bovenstaande commits - d: verwijder commit - ctrl+j: verplaats commit 1 naar beneden - ctrl+k: verplaats commit 1 naar boven - e: wijzig commit - A: wijzig commit met staged veranderingen - p: kies commit (wanneer midden in rebase) - t: commit ongedaan maken c: kopieer commit (cherry-pick) ctrl+o: kopieer commit SHA naar klembord C: kopieer commit reeks (cherry-pick) v: plak commits (cherry-pick) + n: cre毛er nieuwe branch van commit + ctrl+r: reset cherry-picked (gekopieerde) commits selectie + s: squash beneden + f: Fixup commit + r: hernoem commit + R: hernoem commit met editor + d: verwijder commit + e: wijzig commit + p: kies commit (wanneer midden in rebase) + F: cre毛er fixup commit voor deze commit + S: squash bovenstaande commits + ctrl+j: verplaats commit 1 naar beneden + ctrl+k: verplaats commit 1 naar boven + A: wijzig commit met staged veranderingen + t: commit ongedaan maken + ctrl+l: open log menu + g: reset naar deze commit enter: bekijk gecommite bestanden space: checkout commit - n: cre毛er nieuwe branch van commit T: tag commit - ctrl+r: reset cherry-picked (gekopieerde) commits selectie ctrl+y: kopieer commit bericht naar klembord o: open commit in browser b: view bisect options @@ -183,7 +183,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct w: commit veranderingen zonder pre-commit hook A: wijzig laatste commit C: commit veranderingen met de git editor - space: toggle staged d: bekijk 'veranderingen ongedaan maken' opties e: verander bestand o: open bestand @@ -200,6 +199,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct `: toggle bestandsboom weergave M: open external merge tool (git mergetool) ctrl+w: Toggle whether or not whitespace changes are shown in the diff view + space: toggle staged## Bestanden Paneel (Submodules) diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index 95e713826..afdcdebcd 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -123,30 +123,30 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Commity Panel (Commity)- ctrl+l: open log menu - s: 艣ci艣nij - r: zmie艅 nazw臋 commita - R: zmie艅 nazw臋 commita w edytorze - g: zresetuj do tego commita - f: napraw commit - F: utw贸rz commit naprawczy dla tego commita - S: sp艂aszcz wszystkie commity naprawcze powy偶ej zaznaczonych commit贸w (autosquash) - d: usu艅 commit - ctrl+j: przenie艣 commit 1 w d贸艂 - ctrl+k: przenie艣 commit 1 w g贸r臋 - e: edytuj commit - A: popraw commit zmianami z poczekalni - p: wybierz commit (podczas zmiany bazy) - t: odwr贸膰 commit c: kopiuj commit (przebieranie) ctrl+o: copy commit SHA to clipboard C: kopiuj zakres commit贸w (przebieranie) v: wklej commity (przebieranie) + n: create new branch off of commit + ctrl+r: reset cherry-picked (copied) commits selection + s: 艣ci艣nij + f: napraw commit + r: zmie艅 nazw臋 commita + R: zmie艅 nazw臋 commita w edytorze + d: usu艅 commit + e: edytuj commit + p: wybierz commit (podczas zmiany bazy) + F: utw贸rz commit naprawczy dla tego commita + S: sp艂aszcz wszystkie commity naprawcze powy偶ej zaznaczonych commit贸w (autosquash) + ctrl+j: przenie艣 commit 1 w d贸艂 + ctrl+k: przenie艣 commit 1 w g贸r臋 + A: popraw commit zmianami z poczekalni + t: odwr贸膰 commit + ctrl+l: open log menu + g: zresetuj do tego commita enter: przegl膮daj pliki commita space: checkout commit - n: create new branch off of commit T: tag commit - ctrl+r: reset cherry-picked (copied) commits selection ctrl+y: copy commit message to clipboard o: open commit in browser b: view bisect options @@ -183,7 +183,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct w: zatwierd藕 zmiany bez skryptu pre-commit A: Zmie艅 ostatni commit C: Zatwierd藕 zmiany u偶ywaj膮c edytora - space: prze艂膮cz stan poczekalni d: poka偶 opcje porzucania zmian e: edytuj plik o: otw贸rz plik @@ -200,6 +199,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct `: toggle file tree view M: open external merge tool (git mergetool) ctrl+w: Toggle whether or not whitespace changes are shown in the diff view + space: prze艂膮cz stan poczekalni## Pliki Panel (Submodules) diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index 42a4fd1c7..61b2c287f 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -123,30 +123,30 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## 鎻愪氦 闈㈡澘 (鎻愪氦)- ctrl+l: open log menu - s: 鍚戜笅鍘嬬缉 - r: 鏀瑰啓鎻愪氦 - R: 浣跨敤缂栬緫鍣ㄩ噸鍛藉悕鎻愪氦 - g: 閲嶇疆涓烘鎻愪氦 - f: 淇鎻愪氦锛坒ixup锛 - F: 涓烘鎻愪氦鍒涘缓淇 - S: 鍘嬬缉鍦ㄦ墍閫夋彁浜や箣涓婄殑鎵鏈夆渇ixup!鈥濇彁浜わ紙鑷姩鍘嬬缉锛 - d: 鍒犻櫎鎻愪氦 - ctrl+j: 涓嬬Щ鎻愪氦 - ctrl+k: 涓婄Щ鎻愪氦 - e: 缂栬緫鎻愪氦 - A: 鐢ㄥ凡鏆傚瓨鐨勬洿鏀规潵淇ˉ鎻愪氦 - p: 閫夋嫨鎻愪氦锛堝彉鍩鸿繃绋嬩腑锛 - t: 杩樺師鎻愪氦 c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 v: 绮樿创鎻愪氦锛堟嫞閫夛級 + n: 浠庢彁浜ゅ垱寤烘柊鍒嗘敮 + ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 + s: 鍚戜笅鍘嬬缉 + f: 淇鎻愪氦锛坒ixup锛 + r: 鏀瑰啓鎻愪氦 + R: 浣跨敤缂栬緫鍣ㄩ噸鍛藉悕鎻愪氦 + d: 鍒犻櫎鎻愪氦 + e: 缂栬緫鎻愪氦 + p: 閫夋嫨鎻愪氦锛堝彉鍩鸿繃绋嬩腑锛 + F: 涓烘鎻愪氦鍒涘缓淇 + S: 鍘嬬缉鍦ㄦ墍閫夋彁浜や箣涓婄殑鎵鏈夆渇ixup!鈥濇彁浜わ紙鑷姩鍘嬬缉锛 + ctrl+j: 涓嬬Щ鎻愪氦 + ctrl+k: 涓婄Щ鎻愪氦 + A: 鐢ㄥ凡鏆傚瓨鐨勬洿鏀规潵淇ˉ鎻愪氦 + t: 杩樺師鎻愪氦 + ctrl+l: open log menu + g: 閲嶇疆涓烘鎻愪氦 enter: 鏌ョ湅鎻愪氦鐨勬枃浠 space: 妫鍑烘彁浜 - n: 浠庢彁浜ゅ垱寤烘柊鍒嗘敮 T: 鏍囩鎻愪氦 - ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 ctrl+y: 灏嗘彁浜ゆ秷鎭鍒跺埌鍓创鏉 o: open commit in browser b: view bisect options @@ -183,7 +183,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct w: 鎻愪氦鏇存敼鑰屾棤闇棰勫厛鎻愪氦閽╁瓙 A: 淇ˉ鏈鍚庝竴娆℃彁浜 C: 鎻愪氦鏇存敼锛堜娇鐢ㄧ紪杈戝櫒缂栬緫鎻愪氦淇℃伅锛 - space: 鍒囨崲鏆傚瓨鐘舵 d: 鏌ョ湅'鏀惧純鏇存敼鈥橀夐」 e: 缂栬緫鏂囦欢 o: 鎵撳紑鏂囦欢 @@ -200,6 +199,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct `: 鍒囨崲鏂囦欢鏍戣鍥 M: 鎵撳紑鍚堝苟宸ュ叿 ctrl+w: 鍒囨崲鏄惁鍦ㄥ樊寮傝鍥句腑鏄剧ず绌虹櫧鏇存敼 + space: 鍒囨崲鏆傚瓨鐘舵## 鏂囦欢 闈㈡澘 (瀛愭ā鍧) diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index 546239df5..3d1b5efcf 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -17,13 +17,14 @@ import ( "github.com/jesseduffield/lazygit/pkg/app" "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/i18n" "github.com/jesseduffield/lazygit/pkg/integration" ) type bindingSection struct { title string - bindings []*gui.Binding + bindings []*types.Binding } func CommandToRun() string { @@ -113,7 +114,7 @@ func formatTitle(title string) string { return fmt.Sprintf("\n## %s\n\n", title) } -func formatBinding(binding *gui.Binding) string { +func formatBinding(binding *types.Binding) string { if binding.Alternative != "" { return fmt.Sprintf(" %s: %s (%s)\n", gui.GetKeyDisplay(binding.Key), binding.Description, binding.Alternative) } @@ -130,7 +131,7 @@ func getBindingSections(mApp *app.App) []*bindingSection { title string } - contextAndViewBindingMap := map[contextAndViewType][]*gui.Binding{} + contextAndViewBindingMap := map[contextAndViewType][]*types.Binding{} outer: for _, binding := range bindings { @@ -138,7 +139,7 @@ outer: key := contextAndViewType{subtitle: "", title: "navigation"} existing := contextAndViewBindingMap[key] if existing == nil { - contextAndViewBindingMap[key] = []*gui.Binding{binding} + contextAndViewBindingMap[key] = []*types.Binding{binding} } else { for _, navBinding := range contextAndViewBindingMap[key] { if navBinding.Description == binding.Description { @@ -162,7 +163,7 @@ outer: key := contextAndViewType{subtitle: context, title: binding.ViewName} existing := contextAndViewBindingMap[key] if existing == nil { - contextAndViewBindingMap[key] = []*gui.Binding{binding} + contextAndViewBindingMap[key] = []*types.Binding{binding} } else { contextAndViewBindingMap[key] = append(contextAndViewBindingMap[key], binding) } @@ -171,7 +172,7 @@ outer: type groupedBindingsType struct { contextAndView contextAndViewType - bindings []*gui.Binding + bindings []*types.Binding } groupedBindings := make([]groupedBindingsType, len(contextAndViewBindingMap)) @@ -227,7 +228,7 @@ outer: return bindingSections } -func addBinding(title string, bindingSections []*bindingSection, binding *gui.Binding) []*bindingSection { +func addBinding(title string, bindingSections []*bindingSection, binding *types.Binding) []*bindingSection { if binding.Description == "" && binding.Alternative == "" { return bindingSections } @@ -241,7 +242,7 @@ func addBinding(title string, bindingSections []*bindingSection, binding *gui.Bi section := &bindingSection{ title: title, - bindings: []*gui.Binding{binding}, + bindings: []*types.Binding{binding}, } return append(bindingSections, section) diff --git a/pkg/commands/git.go b/pkg/commands/git.go index f6812e254..3880e0dfc 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "strings" + "sync" "github.com/go-errors/errors" @@ -56,6 +57,7 @@ func NewGitCommand( cmn *common.Common, osCommand *oscommands.OSCommand, gitConfig git_config.IGitConfig, + syncMutex *sync.Mutex, ) (*GitCommand, error) { if err := navigateToRepoRootDirectory(os.Stat, os.Chdir); err != nil { return nil, err @@ -77,6 +79,7 @@ func NewGitCommand( gitConfig, dotGitDir, repo, + syncMutex, ), nil } @@ -86,6 +89,7 @@ func NewGitCommandAux( gitConfig git_config.IGitConfig, dotGitDir string, repo *gogit.Repository, + syncMutex *sync.Mutex, ) *GitCommand { cmd := NewGitCmdObjBuilder(cmn.Log, osCommand.Cmd) @@ -95,7 +99,7 @@ func NewGitCommandAux( // on the one struct. // common ones are: cmn, osCommand, dotGitDir, configCommands configCommands := git_commands.NewConfigCommands(cmn, gitConfig, repo) - gitCommon := git_commands.NewGitCommon(cmn, cmd, osCommand, dotGitDir, repo, configCommands) + gitCommon := git_commands.NewGitCommon(cmn, cmd, osCommand, dotGitDir, repo, configCommands, syncMutex) statusCommands := git_commands.NewStatusCommands(gitCommon) fileLoader := loaders.NewFileLoader(cmn, cmd, configCommands) diff --git a/pkg/commands/git_commands/common.go b/pkg/commands/git_commands/common.go index a045be75a..85f0d2118 100644 --- a/pkg/commands/git_commands/common.go +++ b/pkg/commands/git_commands/common.go @@ -1,6 +1,8 @@ package git_commands import ( + "sync" + gogit "github.com/jesseduffield/go-git/v5" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/common" @@ -13,6 +15,8 @@ type GitCommon struct { dotGitDir string repo *gogit.Repository config *ConfigCommands + // mutex for doing things like push/pull/fetch + syncMutex *sync.Mutex } func NewGitCommon( @@ -22,6 +26,7 @@ func NewGitCommon( dotGitDir string, repo *gogit.Repository, config *ConfigCommands, + syncMutex *sync.Mutex, ) *GitCommon { return &GitCommon{ Common: cmn, @@ -30,5 +35,6 @@ func NewGitCommon( dotGitDir: dotGitDir, repo: repo, config: config, + syncMutex: syncMutex, } } diff --git a/pkg/commands/git_commands/remote.go b/pkg/commands/git_commands/remote.go index 3116c764a..1245a8cf0 100644 --- a/pkg/commands/git_commands/remote.go +++ b/pkg/commands/git_commands/remote.go @@ -40,7 +40,7 @@ func (self *RemoteCommands) UpdateRemoteUrl(remoteName string, updatedUrl string func (self *RemoteCommands) DeleteRemoteBranch(remoteName string, branchName string) error { command := fmt.Sprintf("git push %s --delete %s", self.cmd.Quote(remoteName), self.cmd.Quote(branchName)) - return self.cmd.New(command).PromptOnCredentialRequest().Run() + return self.cmd.New(command).PromptOnCredentialRequest().WithMutex(self.syncMutex).Run() } // CheckRemoteBranchExists Returns remote branch diff --git a/pkg/commands/git_commands/sync.go b/pkg/commands/git_commands/sync.go index 8a6933522..fb1aa9648 100644 --- a/pkg/commands/git_commands/sync.go +++ b/pkg/commands/git_commands/sync.go @@ -47,7 +47,7 @@ func (self *SyncCommands) PushCmdObj(opts PushOpts) (oscommands.ICmdObj, error) cmdStr += " " + self.cmd.Quote(opts.UpstreamBranch) } - cmdObj := self.cmd.New(cmdStr).PromptOnCredentialRequest() + cmdObj := self.cmd.New(cmdStr).PromptOnCredentialRequest().WithMutex(self.syncMutex) return cmdObj, nil } @@ -83,7 +83,7 @@ func (self *SyncCommands) Fetch(opts FetchOptions) error { } else { cmdObj.PromptOnCredentialRequest() } - return cmdObj.Run() + return cmdObj.WithMutex(self.syncMutex).Run() } type PullOptions struct { @@ -108,15 +108,15 @@ func (self *SyncCommands) Pull(opts PullOptions) error { // setting GIT_SEQUENCE_EDITOR to ':' as a way of skipping it, in case the user // has 'pull.rebase = interactive' configured. - return self.cmd.New(cmdStr).AddEnvVars("GIT_SEQUENCE_EDITOR=:").PromptOnCredentialRequest().Run() + return self.cmd.New(cmdStr).AddEnvVars("GIT_SEQUENCE_EDITOR=:").PromptOnCredentialRequest().WithMutex(self.syncMutex).Run() } func (self *SyncCommands) FastForward(branchName string, remoteName string, remoteBranchName string) error { cmdStr := fmt.Sprintf("git fetch %s %s:%s", self.cmd.Quote(remoteName), self.cmd.Quote(remoteBranchName), self.cmd.Quote(branchName)) - return self.cmd.New(cmdStr).PromptOnCredentialRequest().Run() + return self.cmd.New(cmdStr).PromptOnCredentialRequest().WithMutex(self.syncMutex).Run() } func (self *SyncCommands) FetchRemote(remoteName string) error { cmdStr := fmt.Sprintf("git fetch %s", self.cmd.Quote(remoteName)) - return self.cmd.New(cmdStr).PromptOnCredentialRequest().Run() + return self.cmd.New(cmdStr).PromptOnCredentialRequest().WithMutex(self.syncMutex).Run() } diff --git a/pkg/commands/git_commands/tag.go b/pkg/commands/git_commands/tag.go index 94b0d8ac1..5abad0dc5 100644 --- a/pkg/commands/git_commands/tag.go +++ b/pkg/commands/git_commands/tag.go @@ -27,5 +27,5 @@ func (self *TagCommands) Delete(tagName string) error { } func (self *TagCommands) Push(remoteName string, tagName string) error { - return self.cmd.New(fmt.Sprintf("git push %s %s", self.cmd.Quote(remoteName), self.cmd.Quote(tagName))).PromptOnCredentialRequest().Run() + return self.cmd.New(fmt.Sprintf("git push %s %s", self.cmd.Quote(remoteName), self.cmd.Quote(tagName))).PromptOnCredentialRequest().WithMutex(self.syncMutex).Run() } diff --git a/pkg/commands/git_test.go b/pkg/commands/git_test.go index 684696a8c..77436130d 100644 --- a/pkg/commands/git_test.go +++ b/pkg/commands/git_test.go @@ -3,6 +3,7 @@ package commands import ( "fmt" "os" + "sync" "testing" "time" @@ -211,7 +212,12 @@ func TestNewGitCommand(t *testing.T) { s := s t.Run(s.testName, func(t *testing.T) { s.setup() - s.test(NewGitCommand(utils.NewDummyCommon(), oscommands.NewDummyOSCommand(), git_config.NewFakeGitConfig(nil))) + s.test( + NewGitCommand(utils.NewDummyCommon(), + oscommands.NewDummyOSCommand(), + git_config.NewFakeGitConfig(nil), + &sync.Mutex{}, + )) }) } } diff --git a/pkg/commands/oscommands/cmd_obj.go b/pkg/commands/oscommands/cmd_obj.go index 3e55359de..7960bfa99 100644 --- a/pkg/commands/oscommands/cmd_obj.go +++ b/pkg/commands/oscommands/cmd_obj.go @@ -2,6 +2,7 @@ package oscommands import ( "os/exec" + "sync" ) // A command object is a general way to represent a command to be run on the @@ -50,6 +51,9 @@ type ICmdObj interface { PromptOnCredentialRequest() ICmdObj FailOnCredentialRequest() ICmdObj + WithMutex(mutex *sync.Mutex) ICmdObj + Mutex() *sync.Mutex + GetCredentialStrategy() CredentialStrategy } @@ -70,6 +74,9 @@ type CmdObj struct { // if set to true, it means we might be asked to enter a username/password by this command. credentialStrategy CredentialStrategy + + // can be set so that we don't run certain commands simultaneously + mutex *sync.Mutex } type CredentialStrategy int @@ -132,6 +139,16 @@ func (self *CmdObj) IgnoreEmptyError() ICmdObj { return self } +func (self *CmdObj) Mutex() *sync.Mutex { + return self.mutex +} + +func (self *CmdObj) WithMutex(mutex *sync.Mutex) ICmdObj { + self.mutex = mutex + + return self +} + func (self *CmdObj) ShouldIgnoreEmptyError() bool { return self.ignoreEmptyError } diff --git a/pkg/commands/oscommands/cmd_obj_runner.go b/pkg/commands/oscommands/cmd_obj_runner.go index e1a38d80f..9522bc627 100644 --- a/pkg/commands/oscommands/cmd_obj_runner.go +++ b/pkg/commands/oscommands/cmd_obj_runner.go @@ -34,6 +34,11 @@ type cmdObjRunner struct { var _ ICmdObjRunner = &cmdObjRunner{} func (self *cmdObjRunner) Run(cmdObj ICmdObj) error { + if cmdObj.Mutex() != nil { + cmdObj.Mutex().Lock() + defer cmdObj.Mutex().Unlock() + } + if cmdObj.GetCredentialStrategy() != NONE { return self.runWithCredentialHandling(cmdObj) } @@ -42,17 +47,14 @@ func (self *cmdObjRunner) Run(cmdObj ICmdObj) error { return self.runAndStream(cmdObj) } - _, err := self.RunWithOutput(cmdObj) + _, err := self.RunWithOutputAux(cmdObj) return err } func (self *cmdObjRunner) RunWithOutput(cmdObj ICmdObj) (string, error) { - if cmdObj.ShouldStreamOutput() { - err := self.runAndStream(cmdObj) - // for now we're not capturing output, just because it would take a little more - // effort and there's currently no use case for it. Some commands call RunWithOutput - // but ignore the output, hence why we've got this check here. - return "", err + if cmdObj.Mutex() != nil { + cmdObj.Mutex().Lock() + defer cmdObj.Mutex().Unlock() } if cmdObj.GetCredentialStrategy() != NONE { @@ -63,6 +65,18 @@ func (self *cmdObjRunner) RunWithOutput(cmdObj ICmdObj) (string, error) { return "", err } + if cmdObj.ShouldStreamOutput() { + err := self.runAndStream(cmdObj) + // for now we're not capturing output, just because it would take a little more + // effort and there's currently no use case for it. Some commands call RunWithOutput + // but ignore the output, hence why we've got this check here. + return "", err + } + + return self.RunWithOutputAux(cmdObj) +} + +func (self *cmdObjRunner) RunWithOutputAux(cmdObj ICmdObj) (string, error) { self.log.WithField("command", cmdObj.ToString()).Debug("RunCommand") if cmdObj.ShouldLog() { @@ -77,6 +91,11 @@ func (self *cmdObjRunner) RunWithOutput(cmdObj ICmdObj) (string, error) { } func (self *cmdObjRunner) RunAndProcessLines(cmdObj ICmdObj, onLine func(line string) (bool, error)) error { + if cmdObj.Mutex() != nil { + cmdObj.Mutex().Lock() + defer cmdObj.Mutex().Unlock() + } + if cmdObj.GetCredentialStrategy() != NONE { return errors.New("cannot call RunAndProcessLines with credential strategy. If you're seeing this then a contributor to Lazygit has accidentally called this method! Please raise an issue") } diff --git a/pkg/gui/app_status_manager.go b/pkg/gui/app_status_manager.go index 825bb8801..4c32f79b5 100644 --- a/pkg/gui/app_status_manager.go +++ b/pkg/gui/app_status_manager.go @@ -83,7 +83,7 @@ func (m *statusManager) getStatusString() string { return topStatus.message } -func (gui *Gui) raiseToast(message string) { +func (gui *Gui) toast(message string) { gui.statusManager.addToastStatus(message) gui.renderAppStatus() @@ -119,7 +119,7 @@ func (gui *Gui) withWaitingStatus(message string, f func() error) error { if err := f(); err != nil { gui.OnUIThread(func() error { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) }) } }) diff --git a/pkg/gui/arrangement.go b/pkg/gui/arrangement.go index fa2e7f29d..944391d75 100644 --- a/pkg/gui/arrangement.go +++ b/pkg/gui/arrangement.go @@ -2,6 +2,7 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/gui/boxlayout" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -44,7 +45,7 @@ func (gui *Gui) getMidSectionWeights() (int, int) { currentWindow := gui.currentWindow() // we originally specified this as a ratio i.e. .20 would correspond to a weight of 1 against 4 - sidePanelWidthRatio := gui.UserConfig.Gui.SidePanelWidth + sidePanelWidthRatio := gui.c.UserConfig.Gui.SidePanelWidth // we could make this better by creating ratios like 2:3 rather than always 1:something mainSectionWeight := int(1/sidePanelWidthRatio) - 1 sideSectionWeight := 1 @@ -115,7 +116,7 @@ func (gui *Gui) splitMainPanelSideBySide() bool { return false } - mainPanelSplitMode := gui.UserConfig.Gui.MainPanelSplitMode + mainPanelSplitMode := gui.c.UserConfig.Gui.MainPanelSplitMode width, height := gui.g.Size() switch mainPanelSplitMode { @@ -143,7 +144,7 @@ func (gui *Gui) getExtrasWindowSize(screenHeight int) int { } else if screenHeight < 40 { baseSize = 1 } else { - baseSize = gui.UserConfig.Gui.CommandLogSize + baseSize = gui.c.UserConfig.Gui.CommandLogSize } frameSize := 2 @@ -259,7 +260,7 @@ func (gui *Gui) sidePanelChildren(width int, height int) []*boxlayout.Box { fullHeightBox("stash"), } } else if height >= 28 { - accordionMode := gui.UserConfig.Gui.ExpandFocusedSidePanel + accordionMode := gui.c.UserConfig.Gui.ExpandFocusedSidePanel accordionBox := func(defaultBox *boxlayout.Box) *boxlayout.Box { if accordionMode && defaultBox.Window == currentWindow { return &boxlayout.Box{ @@ -320,7 +321,7 @@ func (gui *Gui) currentSideWindowName() string { reversedIdx := len(gui.State.ContextManager.ContextStack) - 1 - idx context := gui.State.ContextManager.ContextStack[reversedIdx] - if context.GetKind() == SIDE_CONTEXT { + if context.GetKind() == types.SIDE_CONTEXT { return context.GetWindowName() } } diff --git a/pkg/gui/basic_context.go b/pkg/gui/basic_context.go index 1db80ee4a..1043cca89 100644 --- a/pkg/gui/basic_context.go +++ b/pkg/gui/basic_context.go @@ -1,22 +1,28 @@ package gui +import ( + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + type BasicContext struct { - OnFocus func(opts ...OnFocusOpts) error + OnFocus func(opts ...types.OnFocusOpts) error OnFocusLost func() error OnRender func() error // this is for pushing some content to the main view - OnRenderToMain func(opts ...OnFocusOpts) error - Kind ContextKind - Key ContextKey + OnRenderToMain func(opts ...types.OnFocusOpts) error + Kind types.ContextKind + Key types.ContextKey ViewName string WindowName string OnGetOptionsMap func() map[string]string - ParentContext Context + ParentContext types.Context // we can't know on the calling end whether a Context is actually a nil value without reflection, so we're storing this flag here to tell us. There has got to be a better way around this hasParent bool } +var _ types.Context = &BasicContext{} + func (self *BasicContext) GetOptionsMap() map[string]string { if self.OnGetOptionsMap != nil { return self.OnGetOptionsMap() @@ -24,12 +30,12 @@ func (self *BasicContext) GetOptionsMap() map[string]string { return nil } -func (self *BasicContext) SetParentContext(context Context) { +func (self *BasicContext) SetParentContext(context types.Context) { self.ParentContext = context self.hasParent = true } -func (self *BasicContext) GetParentContext() (Context, bool) { +func (self *BasicContext) GetParentContext() (types.Context, bool) { return self.ParentContext, self.hasParent } @@ -59,7 +65,7 @@ func (self *BasicContext) GetViewName() string { return self.ViewName } -func (self *BasicContext) HandleFocus(opts ...OnFocusOpts) error { +func (self *BasicContext) HandleFocus(opts ...types.OnFocusOpts) error { if self.OnFocus != nil { if err := self.OnFocus(opts...); err != nil { return err @@ -90,10 +96,10 @@ func (self *BasicContext) HandleRenderToMain() error { return nil } -func (self *BasicContext) GetKind() ContextKind { +func (self *BasicContext) GetKind() types.ContextKind { return self.Kind } -func (self *BasicContext) GetKey() ContextKey { +func (self *BasicContext) GetKey() types.ContextKey { return self.Key } diff --git a/pkg/gui/bisect.go b/pkg/gui/bisect.go deleted file mode 100644 index 5c46460ac..000000000 --- a/pkg/gui/bisect.go +++ /dev/null @@ -1,219 +0,0 @@ -package gui - -import ( - "fmt" - "strings" - - "github.com/jesseduffield/lazygit/pkg/commands/git_commands" - "github.com/jesseduffield/lazygit/pkg/commands/models" -) - -func (gui *Gui) handleOpenBisectMenu() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - // no shame in getting this directly rather than using the cached value - // given how cheap it is to obtain - info := gui.Git.Bisect.GetInfo() - commit := gui.getSelectedLocalCommit() - if info.Started() { - return gui.openMidBisectMenu(info, commit) - } else { - return gui.openStartBisectMenu(info, commit) - } -} - -func (gui *Gui) openMidBisectMenu(info *git_commands.BisectInfo, commit *models.Commit) error { - // if there is not yet a 'current' bisect commit, or if we have - // selected the current commit, we need to jump to the next 'current' commit - // after we perform a bisect action. The reason we don't unconditionally jump - // is that sometimes the user will want to go and mark a few commits as skipped - // in a row and they wouldn't want to be jumped back to the current bisect - // commit each time. - // Originally we were allowing the user to, from the bisect menu, select whether - // they were talking about the selected commit or the current bisect commit, - // and that was a bit confusing (and required extra keypresses). - selectCurrentAfter := info.GetCurrentSha() == "" || info.GetCurrentSha() == commit.Sha - // we need to wait to reselect if our bisect commits aren't ancestors of our 'start' - // ref, because we'll be reloading our commits in that case. - waitToReselect := selectCurrentAfter && !gui.Git.Bisect.ReachableFromStart(info) - - menuItems := []*menuItem{ - { - displayString: fmt.Sprintf(gui.Tr.Bisect.Mark, commit.ShortSha(), info.NewTerm()), - onPress: func() error { - gui.logAction(gui.Tr.Actions.BisectMark) - if err := gui.Git.Bisect.Mark(commit.Sha, info.NewTerm()); err != nil { - return gui.surfaceError(err) - } - - return gui.afterMark(selectCurrentAfter, waitToReselect) - }, - }, - { - displayString: fmt.Sprintf(gui.Tr.Bisect.Mark, commit.ShortSha(), info.OldTerm()), - onPress: func() error { - gui.logAction(gui.Tr.Actions.BisectMark) - if err := gui.Git.Bisect.Mark(commit.Sha, info.OldTerm()); err != nil { - return gui.surfaceError(err) - } - - return gui.afterMark(selectCurrentAfter, waitToReselect) - }, - }, - { - displayString: fmt.Sprintf(gui.Tr.Bisect.Skip, commit.ShortSha()), - onPress: func() error { - gui.logAction(gui.Tr.Actions.BisectSkip) - if err := gui.Git.Bisect.Skip(commit.Sha); err != nil { - return gui.surfaceError(err) - } - - return gui.afterMark(selectCurrentAfter, waitToReselect) - }, - }, - { - displayString: gui.Tr.Bisect.ResetOption, - onPress: func() error { - return gui.resetBisect() - }, - }, - } - - return gui.createMenu( - gui.Tr.Bisect.BisectMenuTitle, - menuItems, - createMenuOptions{showCancel: true}, - ) -} - -func (gui *Gui) openStartBisectMenu(info *git_commands.BisectInfo, commit *models.Commit) error { - return gui.createMenu( - gui.Tr.Bisect.BisectMenuTitle, - []*menuItem{ - { - displayString: fmt.Sprintf(gui.Tr.Bisect.MarkStart, commit.ShortSha(), info.NewTerm()), - onPress: func() error { - gui.logAction(gui.Tr.Actions.StartBisect) - if err := gui.Git.Bisect.Start(); err != nil { - return gui.surfaceError(err) - } - - if err := gui.Git.Bisect.Mark(commit.Sha, info.NewTerm()); err != nil { - return gui.surfaceError(err) - } - - return gui.postBisectCommandRefresh() - }, - }, - { - displayString: fmt.Sprintf(gui.Tr.Bisect.MarkStart, commit.ShortSha(), info.OldTerm()), - onPress: func() error { - gui.logAction(gui.Tr.Actions.StartBisect) - if err := gui.Git.Bisect.Start(); err != nil { - return gui.surfaceError(err) - } - - if err := gui.Git.Bisect.Mark(commit.Sha, info.OldTerm()); err != nil { - return gui.surfaceError(err) - } - - return gui.postBisectCommandRefresh() - }, - }, - }, - createMenuOptions{showCancel: true}, - ) -} - -func (gui *Gui) resetBisect() error { - return gui.ask(askOpts{ - title: gui.Tr.Bisect.ResetTitle, - prompt: gui.Tr.Bisect.ResetPrompt, - handleConfirm: func() error { - gui.logAction(gui.Tr.Actions.ResetBisect) - if err := gui.Git.Bisect.Reset(); err != nil { - return gui.surfaceError(err) - } - - return gui.postBisectCommandRefresh() - }, - }) -} - -func (gui *Gui) showBisectCompleteMessage(candidateShas []string) error { - prompt := gui.Tr.Bisect.CompletePrompt - if len(candidateShas) > 1 { - prompt = gui.Tr.Bisect.CompletePromptIndeterminate - } - - formattedCommits, err := gui.Git.Commit.GetCommitsOneline(candidateShas) - if err != nil { - return gui.surfaceError(err) - } - - return gui.ask(askOpts{ - title: gui.Tr.Bisect.CompleteTitle, - prompt: fmt.Sprintf(prompt, strings.TrimSpace(formattedCommits)), - handleConfirm: func() error { - gui.logAction(gui.Tr.Actions.ResetBisect) - if err := gui.Git.Bisect.Reset(); err != nil { - return gui.surfaceError(err) - } - - return gui.postBisectCommandRefresh() - }, - }) -} - -func (gui *Gui) afterMark(selectCurrent bool, waitToReselect bool) error { - done, candidateShas, err := gui.Git.Bisect.IsDone() - if err != nil { - return gui.surfaceError(err) - } - - if err := gui.afterBisectMarkRefresh(selectCurrent, waitToReselect); err != nil { - return gui.surfaceError(err) - } - - if done { - return gui.showBisectCompleteMessage(candidateShas) - } - - return nil -} - -func (gui *Gui) postBisectCommandRefresh() error { - return gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []RefreshableView{}}) -} - -func (gui *Gui) afterBisectMarkRefresh(selectCurrent bool, waitToReselect bool) error { - selectFn := func() { - if selectCurrent { - gui.selectCurrentBisectCommit() - } - } - - if waitToReselect { - return gui.refreshSidePanels(refreshOptions{mode: SYNC, scope: []RefreshableView{}, then: selectFn}) - } else { - selectFn() - - return gui.postBisectCommandRefresh() - } -} - -func (gui *Gui) selectCurrentBisectCommit() { - info := gui.Git.Bisect.GetInfo() - if info.GetCurrentSha() != "" { - // find index of commit with that sha, move cursor to that. - for i, commit := range gui.State.Commits { - if commit.Sha == info.GetCurrentSha() { - gui.State.Contexts.BranchCommits.GetPanelState().SetSelectedLineIdx(i) - _ = gui.State.Contexts.BranchCommits.HandleFocus() - break - } - } - } -} diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index dca0dc8f0..18094b297 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -7,6 +7,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -31,9 +32,9 @@ func (gui *Gui) branchesRenderToMain() error { var task updateTask branch := gui.getSelectedBranch() if branch == nil { - task = NewRenderStringTask(gui.Tr.NoBranchesThisRepo) + task = NewRenderStringTask(gui.c.Tr.NoBranchesThisRepo) } else { - cmdObj := gui.Git.Branch.GetGraphCmdObj(branch.Name) + cmdObj := gui.git.Branch.GetGraphCmdObj(branch.Name) task = NewRunPtyTask(cmdObj.GetCmd()) } @@ -56,21 +57,21 @@ func (gui *Gui) refreshBranches() { // which allows us to order them correctly. So if we're filtering we'll just // manually load all the reflog commits here var err error - reflogCommits, _, err = gui.Git.Loaders.ReflogCommits.GetReflogCommits(nil, "") + reflogCommits, _, err = gui.git.Loaders.ReflogCommits.GetReflogCommits(nil, "") if err != nil { - gui.Log.Error(err) + gui.c.Log.Error(err) } } - branches, err := gui.Git.Loaders.Branches.Load(reflogCommits) + branches, err := gui.git.Loaders.Branches.Load(reflogCommits) if err != nil { - _ = gui.PopupHandler.Error(err) + _ = gui.c.Error(err) } gui.State.Branches = branches - if err := gui.postRefreshUpdate(gui.State.Contexts.Branches); err != nil { - gui.Log.Error(err) + if err := gui.c.PostRefreshUpdate(gui.State.Contexts.Branches); err != nil { + gui.c.Log.Error(err) } gui.refreshStatus() @@ -83,11 +84,11 @@ func (gui *Gui) handleBranchPress() error { return nil } if gui.State.Panels.Branches.SelectedLineIdx == 0 { - return gui.PopupHandler.ErrorMsg(gui.Tr.AlreadyCheckedOutBranch) + return gui.c.ErrorMsg(gui.c.Tr.AlreadyCheckedOutBranch) } branch := gui.getSelectedBranch() - gui.logAction(gui.Tr.Actions.CheckoutBranch) - return gui.handleCheckoutRef(branch.Name, handleCheckoutRefOptions{}) + gui.c.LogAction(gui.c.Tr.Actions.CheckoutBranch) + return gui.refHelper.CheckoutRef(branch.Name, types.CheckoutRefOptions{}) } func (gui *Gui) handleCreatePullRequestPress() error { @@ -110,129 +111,64 @@ func (gui *Gui) handleCopyPullRequestURLPress() error { branch := gui.getSelectedBranch() - branchExistsOnRemote := gui.Git.Remote.CheckRemoteBranchExists(branch.Name) + branchExistsOnRemote := gui.git.Remote.CheckRemoteBranchExists(branch.Name) if !branchExistsOnRemote { - return gui.PopupHandler.Error(errors.New(gui.Tr.NoBranchOnRemote)) + return gui.c.Error(errors.New(gui.c.Tr.NoBranchOnRemote)) } url, err := hostingServiceMgr.GetPullRequestURL(branch.Name, "") if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } - gui.logAction(gui.Tr.Actions.CopyPullRequestURL) + gui.c.LogAction(gui.c.Tr.Actions.CopyPullRequestURL) if err := gui.OSCommand.CopyToClipboard(url); err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } - gui.raiseToast(gui.Tr.PullRequestURLCopiedToClipboard) + gui.c.Toast(gui.c.Tr.PullRequestURLCopiedToClipboard) return nil } func (gui *Gui) handleGitFetch() error { - return gui.PopupHandler.WithLoaderPanel(gui.Tr.FetchWait, func() error { + return gui.c.WithLoaderPanel(gui.c.Tr.FetchWait, func() error { if err := gui.fetch(); err != nil { - _ = gui.PopupHandler.Error(err) + _ = gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) }) } func (gui *Gui) handleForceCheckout() error { branch := gui.getSelectedBranch() - message := gui.Tr.SureForceCheckout - title := gui.Tr.ForceCheckoutBranch + message := gui.c.Tr.SureForceCheckout + title := gui.c.Tr.ForceCheckoutBranch - return gui.PopupHandler.Ask(popup.AskOpts{ + return gui.c.Ask(popup.AskOpts{ Title: title, Prompt: message, HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.ForceCheckoutBranch) - if err := gui.Git.Branch.Checkout(branch.Name, git_commands.CheckoutOptions{Force: true}); err != nil { - _ = gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.ForceCheckoutBranch) + if err := gui.git.Branch.Checkout(branch.Name, git_commands.CheckoutOptions{Force: true}); err != nil { + _ = gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) }, }) } -type handleCheckoutRefOptions struct { - WaitingStatus string - EnvVars []string - onRefNotFound func(ref string) error -} - -func (gui *Gui) handleCheckoutRef(ref string, options handleCheckoutRefOptions) error { - waitingStatus := options.WaitingStatus - if waitingStatus == "" { - waitingStatus = gui.Tr.CheckingOutStatus - } - - cmdOptions := git_commands.CheckoutOptions{Force: false, EnvVars: options.EnvVars} - - onSuccess := func() { - gui.State.Panels.Branches.SelectedLineIdx = 0 - gui.State.Panels.Commits.SelectedLineIdx = 0 - // loading a heap of commits is slow so we limit them whenever doing a reset - gui.State.Panels.Commits.LimitCommits = true - } - - return gui.PopupHandler.WithWaitingStatus(waitingStatus, func() error { - if err := gui.Git.Branch.Checkout(ref, cmdOptions); err != nil { - // note, this will only work for english-language git commands. If we force git to use english, and the error isn't this one, then the user will receive an english command they may not understand. I'm not sure what the best solution to this is. Running the command once in english and a second time in the native language is one option - - if options.onRefNotFound != nil && strings.Contains(err.Error(), "did not match any file(s) known to git") { - return options.onRefNotFound(ref) - } - - if strings.Contains(err.Error(), "Please commit your changes or stash them before you switch branch") { - // offer to autostash changes - return gui.PopupHandler.Ask(popup.AskOpts{ - - Title: gui.Tr.AutoStashTitle, - Prompt: gui.Tr.AutoStashPrompt, - HandleConfirm: func() error { - if err := gui.Git.Stash.Save(gui.Tr.StashPrefix + ref); err != nil { - return gui.PopupHandler.Error(err) - } - if err := gui.Git.Branch.Checkout(ref, cmdOptions); err != nil { - return gui.PopupHandler.Error(err) - } - - onSuccess() - if err := gui.Git.Stash.Pop(0); err != nil { - if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.BLOCK_UI}); err != nil { - return err - } - return gui.PopupHandler.Error(err) - } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.BLOCK_UI}) - }, - }) - } - - if err := gui.PopupHandler.Error(err); err != nil { - return err - } - } - onSuccess() - - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.BLOCK_UI}) - }) -} - func (gui *Gui) handleCheckoutByName() error { - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: gui.Tr.BranchName + ":", - FindSuggestionsFunc: gui.getRefsSuggestionsFunc(), + return gui.c.Prompt(popup.PromptOpts{ + Title: gui.c.Tr.BranchName + ":", + FindSuggestionsFunc: gui.suggestionsHelper.GetRefsSuggestionsFunc(), HandleConfirm: func(response string) error { - gui.logAction("Checkout branch") - return gui.handleCheckoutRef(response, handleCheckoutRefOptions{ - onRefNotFound: func(ref string) error { - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.BranchNotFoundTitle, - Prompt: fmt.Sprintf("%s %s%s", gui.Tr.BranchNotFoundPrompt, ref, "?"), + gui.c.LogAction("Checkout branch") + return gui.refHelper.CheckoutRef(response, types.CheckoutRefOptions{ + OnRefNotFound: func(ref string) error { + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.BranchNotFoundTitle, + Prompt: fmt.Sprintf("%s %s%s", gui.c.Tr.BranchNotFoundPrompt, ref, "?"), HandleConfirm: func() error { return gui.createNewBranchWithName(ref) }, @@ -257,12 +193,12 @@ func (gui *Gui) createNewBranchWithName(newBranchName string) error { return nil } - if err := gui.Git.Branch.New(newBranchName, branch.Name); err != nil { - return gui.PopupHandler.Error(err) + if err := gui.git.Branch.New(newBranchName, branch.Name); err != nil { + return gui.c.Error(err) } gui.State.Panels.Branches.SelectedLineIdx = 0 - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) } func (gui *Gui) handleDeleteBranch() error { @@ -276,18 +212,18 @@ func (gui *Gui) deleteBranch(force bool) error { } checkedOutBranch := gui.getCheckedOutBranch() if checkedOutBranch.Name == selectedBranch.Name { - return gui.PopupHandler.ErrorMsg(gui.Tr.CantDeleteCheckOutBranch) + return gui.c.ErrorMsg(gui.c.Tr.CantDeleteCheckOutBranch) } return gui.deleteNamedBranch(selectedBranch, force) } func (gui *Gui) deleteNamedBranch(selectedBranch *models.Branch, force bool) error { - title := gui.Tr.DeleteBranch + title := gui.c.Tr.DeleteBranch var templateStr string if force { - templateStr = gui.Tr.ForceDeleteBranchMessage + templateStr = gui.c.Tr.ForceDeleteBranchMessage } else { - templateStr = gui.Tr.DeleteBranchMessage + templateStr = gui.c.Tr.DeleteBranchMessage } message := utils.ResolvePlaceholderString( templateStr, @@ -296,59 +232,51 @@ func (gui *Gui) deleteNamedBranch(selectedBranch *models.Branch, force bool) err }, ) - return gui.PopupHandler.Ask(popup.AskOpts{ + return gui.c.Ask(popup.AskOpts{ Title: title, Prompt: message, HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.DeleteBranch) - if err := gui.Git.Branch.Delete(selectedBranch.Name, force); err != nil { + gui.c.LogAction(gui.c.Tr.Actions.DeleteBranch) + if err := gui.git.Branch.Delete(selectedBranch.Name, force); err != nil { errMessage := err.Error() if !force && strings.Contains(errMessage, "git branch -D ") { return gui.deleteNamedBranch(selectedBranch, true) } - return gui.PopupHandler.ErrorMsg(errMessage) + return gui.c.ErrorMsg(errMessage) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) }, }) } func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - if gui.Git.Branch.IsHeadDetached() { - return gui.PopupHandler.ErrorMsg("Cannot merge branch in detached head state. You might have checked out a commit directly or a remote branch, in which case you should checkout the local branch you want to be on") + if gui.git.Branch.IsHeadDetached() { + return gui.c.ErrorMsg("Cannot merge branch in detached head state. You might have checked out a commit directly or a remote branch, in which case you should checkout the local branch you want to be on") } checkedOutBranchName := gui.getCheckedOutBranch().Name if checkedOutBranchName == branchName { - return gui.PopupHandler.ErrorMsg(gui.Tr.CantMergeBranchIntoItself) + return gui.c.ErrorMsg(gui.c.Tr.CantMergeBranchIntoItself) } prompt := utils.ResolvePlaceholderString( - gui.Tr.ConfirmMerge, + gui.c.Tr.ConfirmMerge, map[string]string{ "checkedOutBranch": checkedOutBranchName, "selectedBranch": branchName, }, ) - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.MergingTitle, + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.MergingTitle, Prompt: prompt, HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.Merge) - err := gui.Git.Branch.Merge(branchName, git_commands.MergeOpts{}) - return gui.handleGenericMergeCommandResult(err) + gui.c.LogAction(gui.c.Tr.Actions.Merge) + err := gui.git.Branch.Merge(branchName, git_commands.MergeOpts{}) + return gui.checkMergeOrRebase(err) }, }) } func (gui *Gui) handleMerge() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - selectedBranchName := gui.getSelectedBranch().Name return gui.mergeBranchIntoCheckedOutBranch(selectedBranchName) } @@ -359,29 +287,25 @@ func (gui *Gui) handleRebaseOntoLocalBranch() error { } func (gui *Gui) handleRebaseOntoBranch(selectedBranchName string) error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - checkedOutBranch := gui.getCheckedOutBranch().Name if selectedBranchName == checkedOutBranch { - return gui.PopupHandler.ErrorMsg(gui.Tr.CantRebaseOntoSelf) + return gui.c.ErrorMsg(gui.c.Tr.CantRebaseOntoSelf) } prompt := utils.ResolvePlaceholderString( - gui.Tr.ConfirmRebase, + gui.c.Tr.ConfirmRebase, map[string]string{ "checkedOutBranch": checkedOutBranch, "selectedBranch": selectedBranchName, }, ) - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.RebasingTitle, + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.RebasingTitle, Prompt: prompt, HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.RebaseBranch) - err := gui.Git.Rebase.RebaseBranch(selectedBranchName) - return gui.handleGenericMergeCommandResult(err) + gui.c.LogAction(gui.c.Tr.Actions.RebaseBranch) + err := gui.git.Rebase.RebaseBranch(selectedBranchName) + return gui.checkMergeOrRebase(err) }, }) } @@ -393,35 +317,35 @@ func (gui *Gui) handleFastForward() error { } if !branch.IsTrackingRemote() { - return gui.PopupHandler.ErrorMsg(gui.Tr.FwdNoUpstream) + return gui.c.ErrorMsg(gui.c.Tr.FwdNoUpstream) } if !branch.RemoteBranchStoredLocally() { - return gui.PopupHandler.ErrorMsg(gui.Tr.FwdNoLocalUpstream) + return gui.c.ErrorMsg(gui.c.Tr.FwdNoLocalUpstream) } if branch.HasCommitsToPush() { - return gui.PopupHandler.ErrorMsg(gui.Tr.FwdCommitsToPush) + return gui.c.ErrorMsg(gui.c.Tr.FwdCommitsToPush) } - action := gui.Tr.Actions.FastForwardBranch + action := gui.c.Tr.Actions.FastForwardBranch message := utils.ResolvePlaceholderString( - gui.Tr.Fetching, + gui.c.Tr.Fetching, map[string]string{ "from": fmt.Sprintf("%s/%s", branch.UpstreamRemote, branch.UpstreamBranch), "to": branch.Name, }, ) - return gui.PopupHandler.WithLoaderPanel(message, func() error { + return gui.c.WithLoaderPanel(message, func() error { if gui.State.Panels.Branches.SelectedLineIdx == 0 { - _ = gui.pullWithLock(PullFilesOptions{action: action, FastForwardOnly: true}) + _ = gui.Controllers.Sync.PullAux(controllers.PullFilesOptions{Action: action, FastForwardOnly: true}) } else { - gui.logAction(action) - err := gui.Git.Sync.FastForward(branch.Name, branch.UpstreamRemote, branch.UpstreamBranch) + gui.c.LogAction(action) + err := gui.git.Sync.FastForward(branch.Name, branch.UpstreamRemote, branch.UpstreamBranch) if err != nil { - _ = gui.PopupHandler.Error(err) + _ = gui.c.Error(err) } - _ = gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) + _ = gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) } return nil @@ -434,7 +358,7 @@ func (gui *Gui) handleCreateResetToBranchMenu() error { return nil } - return gui.createResetMenu(branch.Name) + return gui.refHelper.CreateGitResetMenu(branch.Name) } func (gui *Gui) handleRenameBranch() error { @@ -444,13 +368,13 @@ func (gui *Gui) handleRenameBranch() error { } promptForNewName := func() error { - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: gui.Tr.NewBranchNamePrompt + " " + branch.Name + ":", + return gui.c.Prompt(popup.PromptOpts{ + Title: gui.c.Tr.NewBranchNamePrompt + " " + branch.Name + ":", InitialContent: branch.Name, HandleConfirm: func(newBranchName string) error { - gui.logAction(gui.Tr.Actions.RenameBranch) - if err := gui.Git.Branch.Rename(branch.Name, newBranchName); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.RenameBranch) + if err := gui.git.Branch.Rename(branch.Name, newBranchName); err != nil { + return gui.c.Error(err) } // need to find where the branch is now so that we can re-select it. That means we need to refetch the branches synchronously and then find our branch @@ -478,20 +402,13 @@ func (gui *Gui) handleRenameBranch() error { return promptForNewName() } - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.LcRenameBranch, - Prompt: gui.Tr.RenameBranchWarning, + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.LcRenameBranch, + Prompt: gui.c.Tr.RenameBranchWarning, HandleConfirm: promptForNewName, }) } -func (gui *Gui) currentBranch() *models.Branch { - if len(gui.State.Branches) == 0 { - return nil - } - return gui.State.Branches[0] -} - func (gui *Gui) handleNewBranchOffCurrentItem() error { context := gui.currentSideListContext() @@ -501,7 +418,7 @@ func (gui *Gui) handleNewBranchOffCurrentItem() error { } message := utils.ResolvePlaceholderString( - gui.Tr.NewBranchNameBranchOff, + gui.c.Tr.NewBranchNameBranchOff, map[string]string{ "branchName": item.Description(), }, @@ -513,12 +430,12 @@ func (gui *Gui) handleNewBranchOffCurrentItem() error { prefilledName = strings.SplitAfterN(item.ID(), "/", 2)[1] } - return gui.PopupHandler.Prompt(popup.PromptOpts{ + return gui.c.Prompt(popup.PromptOpts{ Title: message, InitialContent: prefilledName, HandleConfirm: func(response string) error { - gui.logAction(gui.Tr.Actions.CreateBranch) - if err := gui.Git.Branch.New(sanitizedBranchName(response), item.ID()); err != nil { + gui.c.LogAction(gui.c.Tr.Actions.CreateBranch) + if err := gui.git.Branch.New(sanitizedBranchName(response), item.ID()); err != nil { return err } @@ -529,14 +446,14 @@ func (gui *Gui) handleNewBranchOffCurrentItem() error { } if context.GetKey() != gui.State.Contexts.Branches.GetKey() { - if err := gui.pushContext(gui.State.Contexts.Branches); err != nil { + if err := gui.c.PushContext(gui.State.Contexts.Branches); err != nil { return err } } gui.State.Panels.Branches.SelectedLineIdx = 0 - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) }, }) } diff --git a/pkg/gui/cherry_picking.go b/pkg/gui/cherry_picking.go index 225fc3811..28554edce 100644 --- a/pkg/gui/cherry_picking.go +++ b/pkg/gui/cherry_picking.go @@ -3,12 +3,13 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) // you can only copy from one context at a time, because the order and position of commits matter -func (gui *Gui) resetCherryPickingIfNecessary(context Context) error { - oldContextKey := ContextKey(gui.State.Modes.CherryPicking.ContextKey) +func (gui *Gui) resetCherryPickingIfNecessary(context types.Context) error { + oldContextKey := types.ContextKey(gui.State.Modes.CherryPicking.ContextKey) if oldContextKey != context.GetKey() { // need to reset the cherry picking mode @@ -22,10 +23,6 @@ func (gui *Gui) resetCherryPickingIfNecessary(context Context) error { } func (gui *Gui) handleCopyCommit() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - // get currently selected commit, add the sha to state. context := gui.currentSideListContext() if context == nil { @@ -80,7 +77,7 @@ func (gui *Gui) commitsListForContext() []*models.Commit { case SUB_COMMITS_CONTEXT_KEY: return gui.State.SubCommits default: - gui.Log.Errorf("no commit list for context %s", context.GetKey()) + gui.c.Log.Errorf("no commit list for context %s", context.GetKey()) return nil } } @@ -102,10 +99,6 @@ func (gui *Gui) addCommitToCherryPickedCommits(index int) { } func (gui *Gui) handleCopyCommitRange() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - // get currently selected commit, add the sha to state. context := gui.currentSideListContext() if context == nil { @@ -142,38 +135,34 @@ func (gui *Gui) handleCopyCommitRange() error { // HandlePasteCommits begins a cherry-pick rebase with the commits the user has copied func (gui *Gui) HandlePasteCommits() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.CherryPick, - Prompt: gui.Tr.SureCherryPick, + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.CherryPick, + Prompt: gui.c.Tr.SureCherryPick, HandleConfirm: func() error { - return gui.PopupHandler.WithWaitingStatus(gui.Tr.CherryPickingStatus, func() error { - gui.logAction(gui.Tr.Actions.CherryPick) - err := gui.Git.Rebase.CherryPickCommits(gui.State.Modes.CherryPicking.CherryPickedCommits) - return gui.handleGenericMergeCommandResult(err) + return gui.c.WithWaitingStatus(gui.c.Tr.CherryPickingStatus, func() error { + gui.c.LogAction(gui.c.Tr.Actions.CherryPick) + err := gui.git.Rebase.CherryPickCommits(gui.State.Modes.CherryPicking.CherryPickedCommits) + return gui.checkMergeOrRebase(err) }) }, }) } func (gui *Gui) exitCherryPickingMode() error { - contextKey := ContextKey(gui.State.Modes.CherryPicking.ContextKey) + contextKey := types.ContextKey(gui.State.Modes.CherryPicking.ContextKey) gui.State.Modes.CherryPicking.ContextKey = "" gui.State.Modes.CherryPicking.CherryPickedCommits = nil if contextKey == "" { - gui.Log.Warn("context key blank when trying to exit cherry picking mode") + gui.c.Log.Warn("context key blank when trying to exit cherry picking mode") return nil } return gui.rerenderContextViewIfPresent(contextKey) } -func (gui *Gui) rerenderContextViewIfPresent(contextKey ContextKey) error { +func (gui *Gui) rerenderContextViewIfPresent(contextKey types.ContextKey) error { if contextKey == "" { return nil } @@ -184,11 +173,11 @@ func (gui *Gui) rerenderContextViewIfPresent(contextKey ContextKey) error { view, err := gui.g.View(viewName) if err != nil { - gui.Log.Error(err) + gui.c.Log.Error(err) return nil } - if ContextKey(view.Context) == contextKey { + if types.ContextKey(view.Context) == contextKey { if err := context.HandleRender(); err != nil { return err } diff --git a/pkg/gui/command_log_panel.go b/pkg/gui/command_log_panel.go index aa46a4d18..409fa0023 100644 --- a/pkg/gui/command_log_panel.go +++ b/pkg/gui/command_log_panel.go @@ -22,7 +22,7 @@ import ( // So we call logAction to log the 'Stage File' part and then we call logCommand to log the command itself. // We pass logCommand to our OSCommand struct so that it can handle logging commands // for us. -func (gui *Gui) logAction(action string) { +func (gui *Gui) LogAction(action string) { if gui.Views.Extras == nil { return } @@ -32,7 +32,7 @@ func (gui *Gui) logAction(action string) { fmt.Fprint(gui.Views.Extras, "\n"+style.FgYellow.Sprint(action)) } -func (gui *Gui) logCommand(cmdStr string, commandLine bool) { +func (gui *Gui) LogCommand(cmdStr string, commandLine bool) { if gui.Views.Extras == nil { return } @@ -52,23 +52,23 @@ func (gui *Gui) logCommand(cmdStr string, commandLine bool) { func (gui *Gui) printCommandLogHeader() { introStr := fmt.Sprintf( - gui.Tr.CommandLogHeader, - gui.getKeyDisplay(gui.UserConfig.Keybinding.Universal.ExtrasMenu), + gui.c.Tr.CommandLogHeader, + gui.getKeyDisplay(gui.c.UserConfig.Keybinding.Universal.ExtrasMenu), ) fmt.Fprintln(gui.Views.Extras, style.FgCyan.Sprint(introStr)) - if gui.UserConfig.Gui.ShowRandomTip { + if gui.c.UserConfig.Gui.ShowRandomTip { fmt.Fprintf( gui.Views.Extras, "%s: %s", - style.FgYellow.Sprint(gui.Tr.RandomTip), + style.FgYellow.Sprint(gui.c.Tr.RandomTip), style.FgGreen.Sprint(gui.getRandomTip()), ) } } func (gui *Gui) getRandomTip() string { - config := gui.UserConfig.Keybinding + config := gui.c.UserConfig.Keybinding formattedKey := func(key string) string { return gui.getKeyDisplay(key) diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index 1941802c2..abae8196f 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -3,6 +3,7 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/patch" + "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -47,7 +48,7 @@ func (gui *Gui) commitFilesRenderToMain() error { to := gui.State.CommitFileTreeViewModel.GetParent() from, reverse := gui.getFromAndReverseArgsForDiff(to) - cmdObj := gui.Git.WorkingTree.ShowFileDiffCmdObj(from, to, reverse, node.GetPath(), false) + cmdObj := gui.git.WorkingTree.ShowFileDiffCmdObj(from, to, reverse, node.GetPath(), false) task := NewRunPtyTask(cmdObj.GetCmd()) return gui.refreshMainViews(refreshMainOpts{ @@ -65,12 +66,12 @@ func (gui *Gui) handleCheckoutCommitFile() error { return nil } - gui.logAction(gui.Tr.Actions.CheckoutFile) - if err := gui.Git.WorkingTree.CheckoutFile(gui.State.CommitFileTreeViewModel.GetParent(), node.GetPath()); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.CheckoutFile) + if err := gui.git.WorkingTree.CheckoutFile(gui.State.CommitFileTreeViewModel.GetParent(), node.GetPath()); err != nil { + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) } func (gui *Gui) handleDiscardOldFileChange() error { @@ -80,19 +81,19 @@ func (gui *Gui) handleDiscardOldFileChange() error { fileName := gui.getSelectedCommitFileName() - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.DiscardFileChangesTitle, - Prompt: gui.Tr.DiscardFileChangesPrompt, + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.DiscardFileChangesTitle, + Prompt: gui.c.Tr.DiscardFileChangesPrompt, HandleConfirm: func() error { - return gui.PopupHandler.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { - gui.logAction(gui.Tr.Actions.DiscardOldFileChange) - if err := gui.Git.Rebase.DiscardOldFileChanges(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, fileName); err != nil { - if err := gui.handleGenericMergeCommandResult(err); err != nil { + return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { + gui.c.LogAction(gui.c.Tr.Actions.DiscardOldFileChange) + if err := gui.git.Rebase.DiscardOldFileChanges(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, fileName); err != nil { + if err := gui.checkMergeOrRebase(err); err != nil { return err } } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.BLOCK_UI}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI}) }) }, }) @@ -109,14 +110,14 @@ func (gui *Gui) refreshCommitFilesView() error { to := gui.State.Panels.CommitFiles.refName from, reverse := gui.getFromAndReverseArgsForDiff(to) - files, err := gui.Git.Loaders.CommitFiles.GetFilesInDiff(from, to, reverse) + files, err := gui.git.Loaders.CommitFiles.GetFilesInDiff(from, to, reverse) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } gui.State.CommitFileTreeViewModel.SetParent(to) gui.State.CommitFileTreeViewModel.SetFiles(files) - return gui.postRefreshUpdate(gui.State.Contexts.CommitFiles) + return gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles) } func (gui *Gui) handleOpenOldCommitFile() error { @@ -125,7 +126,7 @@ func (gui *Gui) handleOpenOldCommitFile() error { return nil } - return gui.openFile(node.GetPath()) + return gui.fileHelper.OpenFile(node.GetPath()) } func (gui *Gui) handleEditCommitFile() error { @@ -135,10 +136,10 @@ func (gui *Gui) handleEditCommitFile() error { } if node.File == nil { - return gui.PopupHandler.ErrorMsg(gui.Tr.ErrCannotEditDirectory) + return gui.c.ErrorMsg(gui.c.Tr.ErrCannotEditDirectory) } - return gui.editFile(node.GetPath()) + return gui.fileHelper.EditFile(node.GetPath()) } func (gui *Gui) handleToggleFileForPatch() error { @@ -148,7 +149,7 @@ func (gui *Gui) handleToggleFileForPatch() error { } toggleTheFile := func() error { - if !gui.Git.Patch.PatchManager.Active() { + if !gui.git.Patch.PatchManager.Active() { if err := gui.startPatchManager(); err != nil { return err } @@ -157,34 +158,34 @@ func (gui *Gui) handleToggleFileForPatch() error { // if there is any file that hasn't been fully added we'll fully add everything, // otherwise we'll remove everything adding := node.AnyFile(func(file *models.CommitFile) bool { - return gui.Git.Patch.PatchManager.GetFileStatus(file.Name, gui.State.CommitFileTreeViewModel.GetParent()) != patch.WHOLE + return gui.git.Patch.PatchManager.GetFileStatus(file.Name, gui.State.CommitFileTreeViewModel.GetParent()) != patch.WHOLE }) err := node.ForEachFile(func(file *models.CommitFile) error { if adding { - return gui.Git.Patch.PatchManager.AddFileWhole(file.Name) + return gui.git.Patch.PatchManager.AddFileWhole(file.Name) } else { - return gui.Git.Patch.PatchManager.RemoveFile(file.Name) + return gui.git.Patch.PatchManager.RemoveFile(file.Name) } }) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } - if gui.Git.Patch.PatchManager.IsEmpty() { - gui.Git.Patch.PatchManager.Reset() + if gui.git.Patch.PatchManager.IsEmpty() { + gui.git.Patch.PatchManager.Reset() } - return gui.postRefreshUpdate(gui.State.Contexts.CommitFiles) + return gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles) } - if gui.Git.Patch.PatchManager.Active() && gui.Git.Patch.PatchManager.To != gui.State.CommitFileTreeViewModel.GetParent() { - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.DiscardPatch, - Prompt: gui.Tr.DiscardPatchConfirm, + if gui.git.Patch.PatchManager.Active() && gui.git.Patch.PatchManager.To != gui.State.CommitFileTreeViewModel.GetParent() { + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.DiscardPatch, + Prompt: gui.c.Tr.DiscardPatchConfirm, HandleConfirm: func() error { - gui.Git.Patch.PatchManager.Reset() + gui.git.Patch.PatchManager.Reset() return toggleTheFile() }, }) @@ -199,15 +200,15 @@ func (gui *Gui) startPatchManager() error { to := gui.State.Panels.CommitFiles.refName from, reverse := gui.getFromAndReverseArgsForDiff(to) - gui.Git.Patch.PatchManager.Start(from, to, reverse, canRebase) + gui.git.Patch.PatchManager.Start(from, to, reverse, canRebase) return nil } func (gui *Gui) handleEnterCommitFile() error { - return gui.enterCommitFile(OnFocusOpts{ClickedViewName: "", ClickedViewLineIdx: -1}) + return gui.enterCommitFile(types.OnFocusOpts{ClickedViewName: "", ClickedViewLineIdx: -1}) } -func (gui *Gui) enterCommitFile(opts OnFocusOpts) error { +func (gui *Gui) enterCommitFile(opts types.OnFocusOpts) error { node := gui.getSelectedCommitFileNode() if node == nil { return nil @@ -218,21 +219,21 @@ func (gui *Gui) enterCommitFile(opts OnFocusOpts) error { } enterTheFile := func() error { - if !gui.Git.Patch.PatchManager.Active() { + if !gui.git.Patch.PatchManager.Active() { if err := gui.startPatchManager(); err != nil { return err } } - return gui.pushContext(gui.State.Contexts.PatchBuilding, opts) + return gui.c.PushContext(gui.State.Contexts.PatchBuilding, opts) } - if gui.Git.Patch.PatchManager.Active() && gui.Git.Patch.PatchManager.To != gui.State.CommitFileTreeViewModel.GetParent() { - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.DiscardPatch, - Prompt: gui.Tr.DiscardPatchConfirm, + if gui.git.Patch.PatchManager.Active() && gui.git.Patch.PatchManager.To != gui.State.CommitFileTreeViewModel.GetParent() { + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.DiscardPatch, + Prompt: gui.c.Tr.DiscardPatchConfirm, HandleConfirm: func() error { - gui.Git.Patch.PatchManager.Reset() + gui.git.Patch.PatchManager.Reset() return enterTheFile() }, }) @@ -249,29 +250,29 @@ func (gui *Gui) handleToggleCommitFileDirCollapsed() error { gui.State.CommitFileTreeViewModel.ToggleCollapsed(node.GetPath()) - if err := gui.postRefreshUpdate(gui.State.Contexts.CommitFiles); err != nil { - gui.Log.Error(err) + if err := gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles); err != nil { + gui.c.Log.Error(err) } return nil } -func (gui *Gui) switchToCommitFilesContext(refName string, canRebase bool, context Context, windowName string) error { +func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesContextOpts) error { // sometimes the commitFiles view is already shown in another window, so we need to ensure that window // no longer considers the commitFiles view as its main view. gui.resetWindowForView(gui.Views.CommitFiles) gui.State.Panels.CommitFiles.SelectedLineIdx = 0 - gui.State.Panels.CommitFiles.refName = refName - gui.State.Panels.CommitFiles.canRebase = canRebase - gui.State.Contexts.CommitFiles.SetParentContext(context) - gui.State.Contexts.CommitFiles.SetWindowName(windowName) + gui.State.Panels.CommitFiles.refName = opts.RefName + gui.State.Panels.CommitFiles.canRebase = opts.CanRebase + gui.State.Contexts.CommitFiles.SetParentContext(opts.Context) + gui.State.Contexts.CommitFiles.SetWindowName(opts.WindowName) if err := gui.refreshCommitFilesView(); err != nil { return err } - return gui.pushContext(gui.State.Contexts.CommitFiles) + return gui.c.PushContext(gui.State.Contexts.CommitFiles) } // NOTE: this is very similar to handleToggleFileTreeView, could be DRY'd with generics @@ -289,12 +290,5 @@ func (gui *Gui) handleToggleCommitFileTreeView() error { } } - if err := gui.State.Contexts.CommitFiles.HandleRender(); err != nil { - return err - } - if err := gui.State.Contexts.CommitFiles.HandleFocus(); err != nil { - return err - } - - return nil + return gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles) } diff --git a/pkg/gui/commit_message_panel.go b/pkg/gui/commit_message_panel.go index feed1aecc..b59111fe2 100644 --- a/pkg/gui/commit_message_panel.go +++ b/pkg/gui/commit_message_panel.go @@ -12,14 +12,14 @@ func (gui *Gui) handleCommitConfirm() error { message := strings.TrimSpace(gui.Views.CommitMessage.TextArea.GetContent()) gui.State.failedCommitMessage = message if message == "" { - return gui.PopupHandler.ErrorMsg(gui.Tr.CommitWithoutMessageErr) + return gui.c.ErrorMsg(gui.c.Tr.CommitWithoutMessageErr) } - cmdObj := gui.Git.Commit.CommitCmdObj(message) - gui.logAction(gui.Tr.Actions.Commit) + cmdObj := gui.git.Commit.CommitCmdObj(message) + gui.c.LogAction(gui.c.Tr.Actions.Commit) _ = gui.returnFromContext() - return gui.withGpgHandling(cmdObj, gui.Tr.CommittingStatus, func() error { + return gui.withGpgHandling(cmdObj, gui.c.Tr.CommittingStatus, func() error { gui.Views.CommitMessage.ClearTextArea() gui.State.failedCommitMessage = "" return nil @@ -32,14 +32,16 @@ func (gui *Gui) handleCommitClose() error { func (gui *Gui) handleCommitMessageFocused() error { message := utils.ResolvePlaceholderString( - gui.Tr.CommitMessageConfirm, + gui.c.Tr.CommitMessageConfirm, map[string]string{ - "keyBindClose": gui.getKeyDisplay(gui.UserConfig.Keybinding.Universal.Return), - "keyBindConfirm": gui.getKeyDisplay(gui.UserConfig.Keybinding.Universal.Confirm), - "keyBindNewLine": gui.getKeyDisplay(gui.UserConfig.Keybinding.Universal.AppendNewline), + "keyBindClose": gui.getKeyDisplay(gui.c.UserConfig.Keybinding.Universal.Return), + "keyBindConfirm": gui.getKeyDisplay(gui.c.UserConfig.Keybinding.Universal.Confirm), + "keyBindNewLine": gui.getKeyDisplay(gui.c.UserConfig.Keybinding.Universal.AppendNewline), }, ) + gui.RenderCommitLength() + return gui.renderString(gui.Views.Options, message) } @@ -49,7 +51,7 @@ func (gui *Gui) getBufferLength(view *gocui.View) string { // RenderCommitLength is a function. func (gui *Gui) RenderCommitLength() { - if !gui.UserConfig.Gui.CommitLength.Show { + if !gui.c.UserConfig.Gui.CommitLength.Show { return } diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index 342596964..6f80ee5c3 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -1,13 +1,10 @@ package gui import ( - "fmt" "sync" "github.com/jesseduffield/lazygit/pkg/commands/loaders" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/popup" - "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -31,7 +28,7 @@ func (gui *Gui) onCommitFocus() error { state.LimitCommits = false go utils.Safe(func() { if err := gui.refreshCommitsWithLimit(); err != nil { - _ = gui.PopupHandler.Error(err) + _ = gui.c.Error(err) } }) } @@ -45,9 +42,9 @@ func (gui *Gui) branchCommitsRenderToMain() error { var task updateTask commit := gui.getSelectedLocalCommit() if commit == nil { - task = NewRenderStringTask(gui.Tr.NoCommitsThisBranch) + task = NewRenderStringTask(gui.c.Tr.NoCommitsThisBranch) } else { - cmdObj := gui.Git.Commit.ShowCmdObj(commit.Sha, gui.State.Modes.Filtering.GetPath()) + cmdObj := gui.git.Commit.ShowCmdObj(commit.Sha, gui.State.Modes.Filtering.GetPath()) task = NewRunPtyTask(cmdObj.GetCmd()) } @@ -118,7 +115,7 @@ func (gui *Gui) refreshCommitsWithLimit() error { gui.Mutexes.BranchCommitsMutex.Lock() defer gui.Mutexes.BranchCommitsMutex.Unlock() - commits, err := gui.Git.Loaders.Commits.GetCommits( + commits, err := gui.git.Loaders.Commits.GetCommits( loaders.GetCommitsOptions{ Limit: gui.State.Panels.Commits.LimitCommits, FilterPath: gui.State.Modes.Filtering.GetPath(), @@ -132,11 +129,11 @@ func (gui *Gui) refreshCommitsWithLimit() error { } gui.State.Commits = commits - return gui.postRefreshUpdate(gui.State.Contexts.BranchCommits) + return gui.c.PostRefreshUpdate(gui.State.Contexts.BranchCommits) } func (gui *Gui) refForLog() string { - bisectInfo := gui.Git.Bisect.GetInfo() + bisectInfo := gui.git.Bisect.GetInfo() gui.State.BisectInfo = bisectInfo if !bisectInfo.Started() { @@ -144,7 +141,7 @@ func (gui *Gui) refForLog() string { } // need to see if our bisect's current commit is reachable from our 'new' ref. - if bisectInfo.Bisecting() && !gui.Git.Bisect.ReachableFromStart(bisectInfo) { + if bisectInfo.Bisecting() && !gui.git.Bisect.ReachableFromStart(bisectInfo) { return bisectInfo.GetNewSha() } @@ -155,691 +152,11 @@ func (gui *Gui) refreshRebaseCommits() error { gui.Mutexes.BranchCommitsMutex.Lock() defer gui.Mutexes.BranchCommitsMutex.Unlock() - updatedCommits, err := gui.Git.Loaders.Commits.MergeRebasingCommits(gui.State.Commits) + updatedCommits, err := gui.git.Loaders.Commits.MergeRebasingCommits(gui.State.Commits) if err != nil { return err } gui.State.Commits = updatedCommits - return gui.postRefreshUpdate(gui.State.Contexts.BranchCommits) -} - -// specific functions - -func (gui *Gui) handleCommitSquashDown() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - if len(gui.State.Commits) <= 1 { - return gui.PopupHandler.ErrorMsg(gui.Tr.YouNoCommitsToSquash) - } - - applied, err := gui.handleMidRebaseCommand("squash") - if err != nil { - return err - } - if applied { - return nil - } - - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.Squash, - Prompt: gui.Tr.SureSquashThisCommit, - HandleConfirm: func() error { - return gui.PopupHandler.WithWaitingStatus(gui.Tr.SquashingStatus, func() error { - gui.logAction(gui.Tr.Actions.SquashCommitDown) - err := gui.Git.Rebase.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, "squash") - return gui.handleGenericMergeCommandResult(err) - }) - }, - }) -} - -func (gui *Gui) handleCommitFixup() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - if len(gui.State.Commits) <= 1 { - return gui.PopupHandler.ErrorMsg(gui.Tr.YouNoCommitsToSquash) - } - - applied, err := gui.handleMidRebaseCommand("fixup") - if err != nil { - return err - } - if applied { - return nil - } - - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.Fixup, - Prompt: gui.Tr.SureFixupThisCommit, - HandleConfirm: func() error { - return gui.PopupHandler.WithWaitingStatus(gui.Tr.FixingStatus, func() error { - gui.logAction(gui.Tr.Actions.FixupCommit) - err := gui.Git.Rebase.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, "fixup") - return gui.handleGenericMergeCommandResult(err) - }) - }, - }) -} - -func (gui *Gui) handleRewordCommit() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - applied, err := gui.handleMidRebaseCommand("reword") - if err != nil { - return err - } - if applied { - return nil - } - - commit := gui.getSelectedLocalCommit() - if commit == nil { - return nil - } - - message, err := gui.Git.Commit.GetCommitMessage(commit.Sha) - if err != nil { - return gui.PopupHandler.Error(err) - } - - // TODO: use the commit message panel here - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: gui.Tr.LcRewordCommit, - InitialContent: message, - HandleConfirm: func(response string) error { - gui.logAction(gui.Tr.Actions.RewordCommit) - if err := gui.Git.Rebase.RewordCommit(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, response); err != nil { - return gui.PopupHandler.Error(err) - } - - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) - }, - }) -} - -func (gui *Gui) handleRewordCommitEditor() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - applied, err := gui.handleMidRebaseCommand("reword") - if err != nil { - return err - } - if applied { - return nil - } - - gui.logAction(gui.Tr.Actions.RewordCommit) - subProcess, err := gui.Git.Rebase.RewordCommitInEditor(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx) - if err != nil { - return gui.PopupHandler.Error(err) - } - if subProcess != nil { - return gui.runSubprocessWithSuspenseAndRefresh(subProcess) - } - - return nil -} - -// handleMidRebaseCommand sees if the selected commit is in fact a rebasing -// commit meaning you are trying to edit the todo file rather than actually -// begin a rebase. It then updates the todo file with that action -func (gui *Gui) handleMidRebaseCommand(action string) (bool, error) { - selectedCommit := gui.State.Commits[gui.State.Panels.Commits.SelectedLineIdx] - if selectedCommit.Status != "rebasing" { - return false, nil - } - - // for now we do not support setting 'reword' because it requires an editor - // and that means we either unconditionally wait around for the subprocess to ask for - // our input or we set a lazygit client as the EDITOR env variable and have it - // request us to edit the commit message when prompted. - if action == "reword" { - return true, gui.PopupHandler.ErrorMsg(gui.Tr.LcRewordNotSupported) - } - - gui.logAction("Update rebase TODO") - gui.logCommand( - fmt.Sprintf("Updating rebase action of commit %s to '%s'", selectedCommit.ShortSha(), action), - false, - ) - - if err := gui.Git.Rebase.EditRebaseTodo(gui.State.Panels.Commits.SelectedLineIdx, action); err != nil { - return false, gui.PopupHandler.Error(err) - } - - return true, gui.refreshRebaseCommits() -} - -func (gui *Gui) handleCommitDelete() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - applied, err := gui.handleMidRebaseCommand("drop") - if err != nil { - return err - } - if applied { - return nil - } - - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.DeleteCommitTitle, - Prompt: gui.Tr.DeleteCommitPrompt, - HandleConfirm: func() error { - return gui.PopupHandler.WithWaitingStatus(gui.Tr.DeletingStatus, func() error { - gui.logAction(gui.Tr.Actions.DropCommit) - err := gui.Git.Rebase.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, "drop") - return gui.handleGenericMergeCommandResult(err) - }) - }, - }) -} - -func (gui *Gui) handleCommitMoveDown() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - index := gui.State.Panels.Commits.SelectedLineIdx - selectedCommit := gui.State.Commits[index] - if selectedCommit.Status == "rebasing" { - if gui.State.Commits[index+1].Status != "rebasing" { - return nil - } - - // logging directly here because MoveTodoDown doesn't have enough information - // to provide a useful log - gui.logAction(gui.Tr.Actions.MoveCommitDown) - gui.logCommand(fmt.Sprintf("Moving commit %s down", selectedCommit.ShortSha()), false) - - if err := gui.Git.Rebase.MoveTodoDown(index); err != nil { - return gui.PopupHandler.Error(err) - } - gui.State.Panels.Commits.SelectedLineIdx++ - return gui.refreshRebaseCommits() - } - - return gui.PopupHandler.WithWaitingStatus(gui.Tr.MovingStatus, func() error { - gui.logAction(gui.Tr.Actions.MoveCommitDown) - err := gui.Git.Rebase.MoveCommitDown(gui.State.Commits, index) - if err == nil { - gui.State.Panels.Commits.SelectedLineIdx++ - } - return gui.handleGenericMergeCommandResult(err) - }) -} - -func (gui *Gui) handleCommitMoveUp() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - index := gui.State.Panels.Commits.SelectedLineIdx - if index == 0 { - return nil - } - - selectedCommit := gui.State.Commits[index] - if selectedCommit.Status == "rebasing" { - // logging directly here because MoveTodoDown doesn't have enough information - // to provide a useful log - gui.logAction(gui.Tr.Actions.MoveCommitUp) - gui.logCommand( - fmt.Sprintf("Moving commit %s up", selectedCommit.ShortSha()), - false, - ) - - if err := gui.Git.Rebase.MoveTodoDown(index - 1); err != nil { - return gui.PopupHandler.Error(err) - } - gui.State.Panels.Commits.SelectedLineIdx-- - return gui.refreshRebaseCommits() - } - - return gui.PopupHandler.WithWaitingStatus(gui.Tr.MovingStatus, func() error { - gui.logAction(gui.Tr.Actions.MoveCommitUp) - err := gui.Git.Rebase.MoveCommitDown(gui.State.Commits, index-1) - if err == nil { - gui.State.Panels.Commits.SelectedLineIdx-- - } - return gui.handleGenericMergeCommandResult(err) - }) -} - -func (gui *Gui) handleCommitEdit() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - applied, err := gui.handleMidRebaseCommand("edit") - if err != nil { - return err - } - if applied { - return nil - } - - return gui.PopupHandler.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { - gui.logAction(gui.Tr.Actions.EditCommit) - err = gui.Git.Rebase.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, "edit") - return gui.handleGenericMergeCommandResult(err) - }) -} - -func (gui *Gui) handleCommitAmendTo() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.AmendCommitTitle, - Prompt: gui.Tr.AmendCommitPrompt, - HandleConfirm: func() error { - return gui.PopupHandler.WithWaitingStatus(gui.Tr.AmendingStatus, func() error { - gui.logAction(gui.Tr.Actions.AmendCommit) - err := gui.Git.Rebase.AmendTo(gui.State.Commits[gui.State.Panels.Commits.SelectedLineIdx].Sha) - return gui.handleGenericMergeCommandResult(err) - }) - }, - }) -} - -func (gui *Gui) handleCommitPick() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - applied, err := gui.handleMidRebaseCommand("pick") - if err != nil { - return err - } - if applied { - return nil - } - - // at this point we aren't actually rebasing so we will interpret this as an - // attempt to pull. We might revoke this later after enabling configurable keybindings - return gui.handlePullFiles() -} - -func (gui *Gui) handleCommitRevert() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - commit := gui.getSelectedLocalCommit() - if commit.IsMerge() { - return gui.createRevertMergeCommitMenu(commit) - } else { - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.Actions.RevertCommit, - Prompt: utils.ResolvePlaceholderString( - gui.Tr.ConfirmRevertCommit, - map[string]string{ - "selectedCommit": commit.ShortSha(), - }), - HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.RevertCommit) - if err := gui.Git.Commit.Revert(commit.Sha); err != nil { - return gui.PopupHandler.Error(err) - } - return gui.afterRevertCommit() - }, - }) - } -} - -func (gui *Gui) createRevertMergeCommitMenu(commit *models.Commit) error { - menuItems := make([]*popup.MenuItem, len(commit.Parents)) - for i, parentSha := range commit.Parents { - i := i - message, err := gui.Git.Commit.GetCommitMessageFirstLine(parentSha) - if err != nil { - return gui.PopupHandler.Error(err) - } - - menuItems[i] = &popup.MenuItem{ - DisplayString: fmt.Sprintf("%s: %s", utils.SafeTruncate(parentSha, 8), message), - OnPress: func() error { - parentNumber := i + 1 - gui.logAction(gui.Tr.Actions.RevertCommit) - if err := gui.Git.Commit.RevertMerge(commit.Sha, parentNumber); err != nil { - return gui.PopupHandler.Error(err) - } - return gui.afterRevertCommit() - }, - } - } - - return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: gui.Tr.SelectParentCommitForMerge, Items: menuItems}) -} - -func (gui *Gui) afterRevertCommit() error { - gui.State.Panels.Commits.SelectedLineIdx++ - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.BLOCK_UI, Scope: []types.RefreshableView{types.COMMITS, types.BRANCHES}}) -} - -func (gui *Gui) handleViewCommitFiles() error { - commit := gui.getSelectedLocalCommit() - if commit == nil { - return nil - } - - return gui.switchToCommitFilesContext(commit.Sha, true, gui.State.Contexts.BranchCommits, "commits") -} - -func (gui *Gui) handleCreateFixupCommit() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - commit := gui.getSelectedLocalCommit() - if commit == nil { - return nil - } - - prompt := utils.ResolvePlaceholderString( - gui.Tr.SureCreateFixupCommit, - map[string]string{ - "commit": commit.Sha, - }, - ) - - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.CreateFixupCommit, - Prompt: prompt, - HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.CreateFixupCommit) - if err := gui.Git.Commit.CreateFixupCommit(commit.Sha); err != nil { - return gui.PopupHandler.Error(err) - } - - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) - }, - }) -} - -func (gui *Gui) handleSquashAllAboveFixupCommits() error { - if ok, err := gui.validateNotInFilterMode(); err != nil || !ok { - return err - } - - commit := gui.getSelectedLocalCommit() - if commit == nil { - return nil - } - - prompt := utils.ResolvePlaceholderString( - gui.Tr.SureSquashAboveCommits, - map[string]string{ - "commit": commit.Sha, - }, - ) - - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.SquashAboveCommits, - Prompt: prompt, - HandleConfirm: func() error { - return gui.PopupHandler.WithWaitingStatus(gui.Tr.SquashingStatus, func() error { - gui.logAction(gui.Tr.Actions.SquashAllAboveFixupCommits) - err := gui.Git.Rebase.SquashAllAboveFixupCommits(commit.Sha) - return gui.handleGenericMergeCommandResult(err) - }) - }, - }) -} - -func (gui *Gui) handleTagCommit() error { - commit := gui.getSelectedLocalCommit() - if commit == nil { - return nil - } - - return gui.createTagMenu(commit.Sha) -} - -func (gui *Gui) createTagMenu(commitSha string) error { - return gui.PopupHandler.Menu(popup.CreateMenuOptions{ - Title: gui.Tr.TagMenuTitle, - Items: []*popup.MenuItem{ - { - DisplayString: gui.Tr.LcLightweightTag, - OnPress: func() error { - return gui.handleCreateLightweightTag(commitSha) - }, - }, - { - DisplayString: gui.Tr.LcAnnotatedTag, - OnPress: func() error { - return gui.handleCreateAnnotatedTag(commitSha) - }, - }, - }, - }) -} - -func (gui *Gui) afterTagCreate() error { - gui.State.Panels.Tags.SelectedLineIdx = 0 // Set to the top - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}}) -} - -func (gui *Gui) handleCreateAnnotatedTag(commitSha string) error { - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: gui.Tr.TagNameTitle, - HandleConfirm: func(tagName string) error { - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: gui.Tr.TagMessageTitle, - HandleConfirm: func(msg string) error { - gui.logAction(gui.Tr.Actions.CreateAnnotatedTag) - if err := gui.Git.Tag.CreateAnnotated(tagName, commitSha, msg); err != nil { - return gui.PopupHandler.Error(err) - } - return gui.afterTagCreate() - }, - }) - }, - }) -} - -func (gui *Gui) handleCreateLightweightTag(commitSha string) error { - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: gui.Tr.TagNameTitle, - HandleConfirm: func(tagName string) error { - gui.logAction(gui.Tr.Actions.CreateLightweightTag) - if err := gui.Git.Tag.CreateLightweight(tagName, commitSha); err != nil { - return gui.PopupHandler.Error(err) - } - return gui.afterTagCreate() - }, - }) -} - -func (gui *Gui) handleCheckoutCommit() error { - commit := gui.getSelectedLocalCommit() - if commit == nil { - return nil - } - - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.LcCheckoutCommit, - Prompt: gui.Tr.SureCheckoutThisCommit, - HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.CheckoutCommit) - return gui.handleCheckoutRef(commit.Sha, handleCheckoutRefOptions{}) - }, - }) -} - -func (gui *Gui) handleCreateCommitResetMenu() error { - commit := gui.getSelectedLocalCommit() - if commit == nil { - return gui.PopupHandler.ErrorMsg(gui.Tr.NoCommitsThisBranch) - } - - return gui.createResetMenu(commit.Sha) -} - -func (gui *Gui) handleOpenSearchForCommitsPanel(string) error { - // we usually lazyload these commits but now that we're searching we need to load them now - if gui.State.Panels.Commits.LimitCommits { - gui.State.Panels.Commits.LimitCommits = false - if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS}}); err != nil { - return err - } - } - - return gui.handleOpenSearch("commits") -} - -func (gui *Gui) handleGotoBottomForCommitsPanel() error { - // we usually lazyload these commits but now that we're searching we need to load them now - if gui.State.Panels.Commits.LimitCommits { - gui.State.Panels.Commits.LimitCommits = false - if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}); err != nil { - return err - } - } - - for _, context := range gui.getListContexts() { - if context.GetViewName() == "commits" { - return context.handleGotoBottom() - } - } - - return nil -} - -func (gui *Gui) handleCopySelectedCommitMessageToClipboard() error { - commit := gui.getSelectedLocalCommit() - if commit == nil { - return nil - } - - message, err := gui.Git.Commit.GetCommitMessage(commit.Sha) - if err != nil { - return gui.PopupHandler.Error(err) - } - - gui.logAction(gui.Tr.Actions.CopyCommitMessageToClipboard) - if err := gui.OSCommand.CopyToClipboard(message); err != nil { - return gui.PopupHandler.Error(err) - } - - gui.raiseToast(gui.Tr.CommitMessageCopiedToClipboard) - - return nil -} - -func (gui *Gui) handleOpenLogMenu() error { - return gui.PopupHandler.Menu(popup.CreateMenuOptions{ - Title: gui.Tr.LogMenuTitle, - Items: []*popup.MenuItem{ - { - DisplayString: gui.Tr.ToggleShowGitGraphAll, - OnPress: func() error { - gui.ShowWholeGitGraph = !gui.ShowWholeGitGraph - - if gui.ShowWholeGitGraph { - gui.State.Panels.Commits.LimitCommits = false - } - - return gui.PopupHandler.WithWaitingStatus(gui.Tr.LcLoadingCommits, func() error { - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}) - }) - }, - }, - { - DisplayString: gui.Tr.ShowGitGraph, - OpensMenu: true, - OnPress: func() error { - onPress := func(value string) func() error { - return func() error { - gui.UserConfig.Git.Log.ShowGraph = value - gui.render() - return nil - } - } - return gui.PopupHandler.Menu(popup.CreateMenuOptions{ - Title: gui.Tr.LogMenuTitle, - Items: []*popup.MenuItem{ - { - DisplayString: "always", - OnPress: onPress("always"), - }, - { - DisplayString: "never", - OnPress: onPress("never"), - }, - { - DisplayString: "when maximised", - OnPress: onPress("when-maximised"), - }, - }, - }) - }, - }, - { - DisplayString: gui.Tr.SortCommits, - OpensMenu: true, - OnPress: func() error { - onPress := func(value string) func() error { - return func() error { - gui.UserConfig.Git.Log.Order = value - return gui.PopupHandler.WithWaitingStatus(gui.Tr.LcLoadingCommits, func() error { - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}) - }) - } - } - - return gui.PopupHandler.Menu(popup.CreateMenuOptions{ - Title: gui.Tr.LogMenuTitle, - Items: []*popup.MenuItem{ - { - DisplayString: "topological (topo-order)", - OnPress: onPress("topo-order"), - }, - { - DisplayString: "date-order", - OnPress: onPress("date-order"), - }, - { - DisplayString: "author-date-order", - OnPress: onPress("author-date-order"), - }, - }, - }) - }, - }, - }, - }) -} - -func (gui *Gui) handleOpenCommitInBrowser() error { - commit := gui.getSelectedLocalCommit() - if commit == nil { - return nil - } - - hostingServiceMgr := gui.getHostingServiceMgr() - - url, err := hostingServiceMgr.GetCommitURL(commit.Sha) - if err != nil { - return gui.PopupHandler.Error(err) - } - - gui.logAction(gui.Tr.Actions.OpenCommitInBrowser) - if err := gui.OSCommand.OpenLink(url); err != nil { - return gui.PopupHandler.Error(err) - } - - return nil + return gui.c.PostRefreshUpdate(gui.State.Contexts.BranchCommits) } diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index 0d5457101..1d865348f 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -19,7 +19,7 @@ func (gui *Gui) wrappedConfirmationFunction(handlersManageFocus bool, function f if function != nil { if err := function(); err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } } @@ -35,7 +35,7 @@ func (gui *Gui) wrappedPromptConfirmationFunction(handlersManageFocus bool, func if function != nil { if err := function(getResponse()); err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } } @@ -132,7 +132,7 @@ func (gui *Gui) prepareConfirmationPanel( suggestionsView.FgColor = theme.GocuiDefaultTextColor gui.setSuggestions(findSuggestionsFunc("")) suggestionsView.Visible = true - suggestionsView.Title = fmt.Sprintf(gui.Tr.SuggestionsTitle, gui.UserConfig.Keybinding.Universal.TogglePanel) + suggestionsView.Title = fmt.Sprintf(gui.c.Tr.SuggestionsTitle, gui.c.UserConfig.Keybinding.Universal.TogglePanel) } return nil @@ -171,12 +171,12 @@ func (gui *Gui) createPopupPanel(opts popup.CreatePopupPanelOpts) error { return err } - return gui.pushContext(gui.State.Contexts.Confirmation) + return gui.c.PushContext(gui.State.Contexts.Confirmation) } func (gui *Gui) setKeyBindings(opts popup.CreatePopupPanelOpts) error { actions := utils.ResolvePlaceholderString( - gui.Tr.CloseConfirm, + gui.c.Tr.CloseConfirm, map[string]string{ "keyBindClose": "esc", "keyBindConfirm": "enter", @@ -197,7 +197,7 @@ func (gui *Gui) setKeyBindings(opts popup.CreatePopupPanelOpts) error { handler func() error } - keybindingConfig := gui.UserConfig.Keybinding + keybindingConfig := gui.c.UserConfig.Keybinding onSuggestionConfirm := gui.wrappedPromptConfirmationFunction( opts.HandlersManageFocus, opts.HandleConfirmPrompt, @@ -262,7 +262,7 @@ func (gui *Gui) setKeyBindings(opts popup.CreatePopupPanelOpts) error { } func (gui *Gui) clearConfirmationViewKeyBindings() { - keybindingConfig := gui.UserConfig.Keybinding + keybindingConfig := gui.c.UserConfig.Keybinding _ = gui.g.DeleteKeybinding("confirmation", gui.getKey(keybindingConfig.Universal.Confirm), gocui.ModNone) _ = gui.g.DeleteKeybinding("confirmation", gui.getKey(keybindingConfig.Universal.ConfirmAlt1), gocui.ModNone) _ = gui.g.DeleteKeybinding("confirmation", gui.getKey(keybindingConfig.Universal.Return), gocui.ModNone) @@ -276,3 +276,10 @@ func (gui *Gui) wrappedHandler(f func() error) func(g *gocui.Gui, v *gocui.View) return f() } } + +func (gui *Gui) refreshSuggestions() { + gui.suggestionsAsyncHandler.Do(func() func() { + suggestions := gui.findSuggestions(gui.c.GetPromptInput()) + return func() { gui.setSuggestions(suggestions) } + }) +} diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 7aa9a1046..f92c73e26 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -5,44 +5,13 @@ import ( "fmt" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) -type ContextKind int - -const ( - SIDE_CONTEXT ContextKind = iota - MAIN_CONTEXT - TEMPORARY_POPUP - PERSISTENT_POPUP - EXTRAS_CONTEXT -) - -type OnFocusOpts struct { - ClickedViewName string - ClickedViewLineIdx int -} - -type Context interface { - HandleFocus(opts ...OnFocusOpts) error - HandleFocusLost() error - HandleRender() error - HandleRenderToMain() error - GetKind() ContextKind - GetViewName() string - GetWindowName() string - SetWindowName(string) - GetKey() ContextKey - SetParentContext(Context) - - // we return a bool here to tell us whether or not the returned value just wraps a nil - GetParentContext() (Context, bool) - GetOptionsMap() map[string]string -} - func (gui *Gui) popupViewNames() []string { result := []string{} for _, context := range gui.allContexts() { - if context.GetKind() == PERSISTENT_POPUP || context.GetKind() == TEMPORARY_POPUP { + if context.GetKind() == types.PERSISTENT_POPUP || context.GetKind() == types.TEMPORARY_POPUP { result = append(result, context.GetViewName()) } } @@ -50,7 +19,7 @@ func (gui *Gui) popupViewNames() []string { return result } -func (gui *Gui) currentContextKeyIgnoringPopups() ContextKey { +func (gui *Gui) currentContextKeyIgnoringPopups() types.ContextKey { gui.State.ContextManager.RLock() defer gui.State.ContextManager.RUnlock() @@ -60,7 +29,7 @@ func (gui *Gui) currentContextKeyIgnoringPopups() ContextKey { reversedIndex := len(stack) - 1 - i context := stack[reversedIndex] kind := stack[reversedIndex].GetKind() - if kind != TEMPORARY_POPUP && kind != PERSISTENT_POPUP { + if kind != types.TEMPORARY_POPUP && kind != types.PERSISTENT_POPUP { return context.GetKey() } } @@ -70,12 +39,12 @@ func (gui *Gui) currentContextKeyIgnoringPopups() ContextKey { // use replaceContext when you don't want to return to the original context upon // hitting escape: you want to go that context's parent instead. -func (gui *Gui) replaceContext(c Context) error { +func (gui *Gui) replaceContext(c types.Context) error { gui.State.ContextManager.Lock() defer gui.State.ContextManager.Unlock() if len(gui.State.ContextManager.ContextStack) == 0 { - gui.State.ContextManager.ContextStack = []Context{c} + gui.State.ContextManager.ContextStack = []types.Context{c} } else { // replace the last item with the given item gui.State.ContextManager.ContextStack = append(gui.State.ContextManager.ContextStack[0:len(gui.State.ContextManager.ContextStack)-1], c) @@ -84,7 +53,7 @@ func (gui *Gui) replaceContext(c Context) error { return gui.activateContext(c) } -func (gui *Gui) pushContext(c Context, opts ...OnFocusOpts) error { +func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { // using triple dot but you should only ever pass one of these opt structs if len(opts) > 1 { return errors.New("cannot pass multiple opts to pushContext") @@ -94,7 +63,7 @@ func (gui *Gui) pushContext(c Context, opts ...OnFocusOpts) error { // push onto stack // if we are switching to a side context, remove all other contexts in the stack - if c.GetKind() == SIDE_CONTEXT { + if c.GetKind() == types.SIDE_CONTEXT { for _, stackContext := range gui.State.ContextManager.ContextStack { if stackContext.GetKey() != c.GetKey() { if err := gui.deactivateContext(stackContext); err != nil { @@ -103,7 +72,7 @@ func (gui *Gui) pushContext(c Context, opts ...OnFocusOpts) error { } } } - gui.State.ContextManager.ContextStack = []Context{c} + gui.State.ContextManager.ContextStack = []types.Context{c} } else if len(gui.State.ContextManager.ContextStack) == 0 || gui.currentContextWithoutLock().GetKey() != c.GetKey() { // Do not append if the one at the end is the same context (e.g. opening a menu from a menu) // In that case we'll just close the menu entirely when the user hits escape. @@ -123,7 +92,7 @@ func (gui *Gui) pushContext(c Context, opts ...OnFocusOpts) error { // want to switch to: you only know the view that you want to switch to. It will // look up the context currently active for that view and switch to that context func (gui *Gui) pushContextWithView(viewName string) error { - return gui.pushContext(gui.State.ViewContextMap[viewName]) + return gui.c.PushContext(gui.State.ViewContextMap[viewName]) } func (gui *Gui) returnFromContext() error { @@ -151,7 +120,7 @@ func (gui *Gui) returnFromContext() error { return gui.activateContext(newContext) } -func (gui *Gui) deactivateContext(c Context) error { +func (gui *Gui) deactivateContext(c types.Context) error { view, _ := gui.g.View(c.GetViewName()) if view != nil && view.IsSearching() { @@ -161,7 +130,7 @@ func (gui *Gui) deactivateContext(c Context) error { } // if we are the kind of context that is sent to back upon deactivation, we should do that - if view != nil && (c.GetKind() == TEMPORARY_POPUP || c.GetKind() == PERSISTENT_POPUP || c.GetKey() == COMMIT_FILES_CONTEXT_KEY) { + if view != nil && (c.GetKind() == types.TEMPORARY_POPUP || c.GetKind() == types.PERSISTENT_POPUP || c.GetKey() == COMMIT_FILES_CONTEXT_KEY) { view.Visible = false } @@ -175,13 +144,13 @@ func (gui *Gui) deactivateContext(c Context) error { // postRefreshUpdate is to be called on a context after the state that it depends on has been refreshed // if the context's view is set to another context we do nothing. // if the context's view is the current view we trigger a focus; re-selecting the current item. -func (gui *Gui) postRefreshUpdate(c Context) error { +func (gui *Gui) postRefreshUpdate(c types.Context) error { v, err := gui.g.View(c.GetViewName()) if err != nil { return nil } - if ContextKey(v.Context) != c.GetKey() { + if types.ContextKey(v.Context) != c.GetKey() { return nil } @@ -198,13 +167,13 @@ func (gui *Gui) postRefreshUpdate(c Context) error { return nil } -func (gui *Gui) activateContext(c Context, opts ...OnFocusOpts) error { +func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) error { viewName := c.GetViewName() v, err := gui.g.View(viewName) if err != nil { return err } - originalViewContextKey := ContextKey(v.Context) + originalViewContextKey := types.ContextKey(v.Context) // ensure that any other window for which this view was active is now set to the default for that window. gui.setViewAsActiveForWindow(v) @@ -260,14 +229,14 @@ func (gui *Gui) activateContext(c Context, opts ...OnFocusOpts) error { // return result // } -func (gui *Gui) currentContext() Context { +func (gui *Gui) currentContext() types.Context { gui.State.ContextManager.RLock() defer gui.State.ContextManager.RUnlock() return gui.currentContextWithoutLock() } -func (gui *Gui) currentContextWithoutLock() Context { +func (gui *Gui) currentContextWithoutLock() types.Context { if len(gui.State.ContextManager.ContextStack) == 0 { return gui.defaultSideContext() } @@ -277,16 +246,16 @@ func (gui *Gui) currentContextWithoutLock() Context { // the status panel is not yet a list context (and may never be), so this method is not // quite the same as currentSideContext() -func (gui *Gui) currentSideListContext() IListContext { +func (gui *Gui) currentSideListContext() types.IListContext { context := gui.currentSideContext() - listContext, ok := context.(IListContext) + listContext, ok := context.(types.IListContext) if !ok { return nil } return listContext } -func (gui *Gui) currentSideContext() Context { +func (gui *Gui) currentSideContext() types.Context { gui.State.ContextManager.RLock() defer gui.State.ContextManager.RUnlock() @@ -297,11 +266,11 @@ func (gui *Gui) currentSideContext() Context { return gui.defaultSideContext() } - // find the first context in the stack with the type of SIDE_CONTEXT + // find the first context in the stack with the type of types.SIDE_CONTEXT for i := range stack { context := stack[len(stack)-1-i] - if context.GetKind() == SIDE_CONTEXT { + if context.GetKind() == types.SIDE_CONTEXT { return context } } @@ -310,7 +279,7 @@ func (gui *Gui) currentSideContext() Context { } // static as opposed to popup -func (gui *Gui) currentStaticContext() Context { +func (gui *Gui) currentStaticContext() types.Context { gui.State.ContextManager.RLock() defer gui.State.ContextManager.RUnlock() @@ -324,7 +293,7 @@ func (gui *Gui) currentStaticContext() Context { for i := range stack { context := stack[len(stack)-1-i] - if context.GetKind() != TEMPORARY_POPUP && context.GetKind() != PERSISTENT_POPUP { + if context.GetKind() != types.TEMPORARY_POPUP && context.GetKind() != types.PERSISTENT_POPUP { return context } } @@ -332,7 +301,7 @@ func (gui *Gui) currentStaticContext() Context { return gui.defaultSideContext() } -func (gui *Gui) defaultSideContext() Context { +func (gui *Gui) defaultSideContext() types.Context { if gui.State.Modes.Filtering.Active() { return gui.State.Contexts.BranchCommits } else { @@ -407,7 +376,7 @@ func (gui *Gui) onViewFocusLost(oldView *gocui.View, newView *gocui.View) error // which currently just means a context that affects both the main and secondary views // other views can have their context changed directly but this function helps // keep the main and secondary views in sync -func (gui *Gui) changeMainViewsContext(contextKey ContextKey) { +func (gui *Gui) changeMainViewsContext(contextKey types.ContextKey) { if gui.State.MainContext == contextKey { return } @@ -432,13 +401,13 @@ func (gui *Gui) viewTabNames(viewName string) []string { result := make([]string, len(tabContexts)) for i, tabContext := range tabContexts { - result[i] = tabContext.tab + result[i] = tabContext.Tab } return result } -func (gui *Gui) setViewTabForContext(c Context) { +func (gui *Gui) setViewTabForContext(c types.Context) { // search for the context in our map and if we find it, set the tab for the corresponding view tabContexts, ok := gui.State.ViewTabContextMap[c.GetViewName()] if !ok { @@ -446,12 +415,12 @@ func (gui *Gui) setViewTabForContext(c Context) { } for tabIndex, tabContext := range tabContexts { - for _, context := range tabContext.contexts { + for _, context := range tabContext.Contexts { if context.GetKey() == c.GetKey() { // get the view, set the tab v, err := gui.g.View(c.GetViewName()) if err != nil { - gui.Log.Error(err) + gui.c.Log.Error(err) return } v.TabIndex = tabIndex @@ -461,12 +430,7 @@ func (gui *Gui) setViewTabForContext(c Context) { } } -type tabContext struct { - tab string - contexts []Context -} - -func (gui *Gui) mustContextForContextKey(contextKey ContextKey) Context { +func (gui *Gui) mustContextForContextKey(contextKey types.ContextKey) types.Context { context, ok := gui.contextForContextKey(contextKey) if !ok { @@ -476,7 +440,7 @@ func (gui *Gui) mustContextForContextKey(contextKey ContextKey) Context { return context } -func (gui *Gui) contextForContextKey(contextKey ContextKey) (Context, bool) { +func (gui *Gui) contextForContextKey(contextKey types.ContextKey) (types.Context, bool) { for _, context := range gui.allContexts() { if context.GetKey() == contextKey { return context, true @@ -487,7 +451,7 @@ func (gui *Gui) contextForContextKey(contextKey ContextKey) (Context, bool) { } func (gui *Gui) rerenderView(view *gocui.View) error { - contextKey := ContextKey(view.Context) + contextKey := types.ContextKey(view.Context) context := gui.mustContextForContextKey(contextKey) return context.HandleRender() diff --git a/pkg/gui/context/context.go b/pkg/gui/context/context.go new file mode 100644 index 000000000..67de237ed --- /dev/null +++ b/pkg/gui/context/context.go @@ -0,0 +1,98 @@ +package context + +import "github.com/jesseduffield/lazygit/pkg/gui/types" + +type ContextTree struct { + Status types.Context + Files types.IListContext + Submodules types.IListContext + Menu types.IListContext + Branches types.IListContext + Remotes types.IListContext + RemoteBranches types.IListContext + Tags types.IListContext + BranchCommits types.IListContext + CommitFiles types.IListContext + ReflogCommits types.IListContext + SubCommits types.IListContext + Stash types.IListContext + Suggestions types.IListContext + Normal types.Context + Staging types.Context + PatchBuilding types.Context + Merging types.Context + Credentials types.Context + Confirmation types.Context + CommitMessage types.Context + Search types.Context + CommandLog types.Context +} + +func (tree ContextTree) InitialViewContextMap() map[string]types.Context { + return map[string]types.Context{ + "status": tree.Status, + "files": tree.Files, + "branches": tree.Branches, + "commits": tree.BranchCommits, + "commitFiles": tree.CommitFiles, + "stash": tree.Stash, + "menu": tree.Menu, + "confirmation": tree.Confirmation, + "credentials": tree.Credentials, + "commitMessage": tree.CommitMessage, + "main": tree.Normal, + "secondary": tree.Normal, + "extras": tree.CommandLog, + } +} + +type TabContext struct { + Tab string + Contexts []types.Context +} + +func (tree ContextTree) InitialViewTabContextMap() map[string][]TabContext { + return map[string][]TabContext{ + "branches": { + { + Tab: "Local Branches", + Contexts: []types.Context{tree.Branches}, + }, + { + Tab: "Remotes", + Contexts: []types.Context{ + tree.Remotes, + tree.RemoteBranches, + }, + }, + { + Tab: "Tags", + Contexts: []types.Context{tree.Tags}, + }, + }, + "commits": { + { + Tab: "Commits", + Contexts: []types.Context{tree.BranchCommits}, + }, + { + Tab: "Reflog", + Contexts: []types.Context{ + tree.ReflogCommits, + }, + }, + }, + "files": { + { + Tab: "Files", + Contexts: []types.Context{tree.Files}, + }, + { + Tab: "Submodules", + Contexts: []types.Context{ + tree.Submodules, + }, + }, + }, + } +} diff --git a/pkg/gui/context_config.go b/pkg/gui/context_config.go index e884d32bd..b3e94e15f 100644 --- a/pkg/gui/context_config.go +++ b/pkg/gui/context_config.go @@ -1,34 +1,37 @@ package gui -type ContextKey string - -const ( - STATUS_CONTEXT_KEY ContextKey = "status" - FILES_CONTEXT_KEY ContextKey = "files" - LOCAL_BRANCHES_CONTEXT_KEY ContextKey = "localBranches" - REMOTES_CONTEXT_KEY ContextKey = "remotes" - REMOTE_BRANCHES_CONTEXT_KEY ContextKey = "remoteBranches" - TAGS_CONTEXT_KEY ContextKey = "tags" - BRANCH_COMMITS_CONTEXT_KEY ContextKey = "commits" - REFLOG_COMMITS_CONTEXT_KEY ContextKey = "reflogCommits" - SUB_COMMITS_CONTEXT_KEY ContextKey = "subCommits" - COMMIT_FILES_CONTEXT_KEY ContextKey = "commitFiles" - STASH_CONTEXT_KEY ContextKey = "stash" - MAIN_NORMAL_CONTEXT_KEY ContextKey = "normal" - MAIN_MERGING_CONTEXT_KEY ContextKey = "merging" - MAIN_PATCH_BUILDING_CONTEXT_KEY ContextKey = "patchBuilding" - MAIN_STAGING_CONTEXT_KEY ContextKey = "staging" - MENU_CONTEXT_KEY ContextKey = "menu" - CREDENTIALS_CONTEXT_KEY ContextKey = "credentials" - CONFIRMATION_CONTEXT_KEY ContextKey = "confirmation" - SEARCH_CONTEXT_KEY ContextKey = "search" - COMMIT_MESSAGE_CONTEXT_KEY ContextKey = "commitMessage" - SUBMODULES_CONTEXT_KEY ContextKey = "submodules" - SUGGESTIONS_CONTEXT_KEY ContextKey = "suggestions" - COMMAND_LOG_CONTEXT_KEY ContextKey = "cmdLog" +import ( + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) -var allContextKeys = []ContextKey{ +const ( + STATUS_CONTEXT_KEY types.ContextKey = "status" + FILES_CONTEXT_KEY types.ContextKey = "files" + LOCAL_BRANCHES_CONTEXT_KEY types.ContextKey = "localBranches" + REMOTES_CONTEXT_KEY types.ContextKey = "remotes" + REMOTE_BRANCHES_CONTEXT_KEY types.ContextKey = "remoteBranches" + TAGS_CONTEXT_KEY types.ContextKey = "tags" + BRANCH_COMMITS_CONTEXT_KEY types.ContextKey = "commits" + REFLOG_COMMITS_CONTEXT_KEY types.ContextKey = "reflogCommits" + SUB_COMMITS_CONTEXT_KEY types.ContextKey = "subCommits" + COMMIT_FILES_CONTEXT_KEY types.ContextKey = "commitFiles" + STASH_CONTEXT_KEY types.ContextKey = "stash" + MAIN_NORMAL_CONTEXT_KEY types.ContextKey = "normal" + MAIN_MERGING_CONTEXT_KEY types.ContextKey = "merging" + MAIN_PATCH_BUILDING_CONTEXT_KEY types.ContextKey = "patchBuilding" + MAIN_STAGING_CONTEXT_KEY types.ContextKey = "staging" + MENU_CONTEXT_KEY types.ContextKey = "menu" + CREDENTIALS_CONTEXT_KEY types.ContextKey = "credentials" + CONFIRMATION_CONTEXT_KEY types.ContextKey = "confirmation" + SEARCH_CONTEXT_KEY types.ContextKey = "search" + COMMIT_MESSAGE_CONTEXT_KEY types.ContextKey = "commitMessage" + SUBMODULES_CONTEXT_KEY types.ContextKey = "submodules" + SUGGESTIONS_CONTEXT_KEY types.ContextKey = "suggestions" + COMMAND_LOG_CONTEXT_KEY types.ContextKey = "cmdLog" +) + +var AllContextKeys = []types.ContextKey{ STATUS_CONTEXT_KEY, FILES_CONTEXT_KEY, LOCAL_BRANCHES_CONTEXT_KEY, @@ -54,34 +57,8 @@ var allContextKeys = []ContextKey{ COMMAND_LOG_CONTEXT_KEY, } -type ContextTree struct { - Status Context - Files IListContext - Submodules IListContext - Menu IListContext - Branches IListContext - Remotes IListContext - RemoteBranches IListContext - Tags IListContext - BranchCommits IListContext - CommitFiles IListContext - ReflogCommits IListContext - SubCommits IListContext - Stash IListContext - Suggestions IListContext - Normal Context - Staging Context - PatchBuilding Context - Merging Context - Credentials Context - Confirmation Context - CommitMessage Context - Search Context - CommandLog Context -} - -func (gui *Gui) allContexts() []Context { - return []Context{ +func (gui *Gui) allContexts() []types.Context { + return []types.Context{ gui.State.Contexts.Status, gui.State.Contexts.Files, gui.State.Contexts.Submodules, @@ -107,11 +84,11 @@ func (gui *Gui) allContexts() []Context { } } -func (gui *Gui) contextTree() ContextTree { - return ContextTree{ +func (gui *Gui) contextTree() context.ContextTree { + return context.ContextTree{ Status: &BasicContext{ OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain), - Kind: SIDE_CONTEXT, + Kind: types.SIDE_CONTEXT, ViewName: "status", Key: STATUS_CONTEXT_KEY, }, @@ -128,15 +105,15 @@ func (gui *Gui) contextTree() ContextTree { Tags: gui.tagsListContext(), Stash: gui.stashListContext(), Normal: &BasicContext{ - OnFocus: func(opts ...OnFocusOpts) error { + OnFocus: func(opts ...types.OnFocusOpts) error { return nil // TODO: should we do something here? We should allow for scrolling the panel }, - Kind: MAIN_CONTEXT, + Kind: types.MAIN_CONTEXT, ViewName: "main", Key: MAIN_NORMAL_CONTEXT_KEY, }, Staging: &BasicContext{ - OnFocus: func(opts ...OnFocusOpts) error { + OnFocus: func(opts ...types.OnFocusOpts) error { forceSecondaryFocused := false selectedLineIdx := -1 if len(opts) > 0 && opts[0].ClickedViewName != "" { @@ -149,12 +126,12 @@ func (gui *Gui) contextTree() ContextTree { } return gui.onStagingFocus(forceSecondaryFocused, selectedLineIdx) }, - Kind: MAIN_CONTEXT, + Kind: types.MAIN_CONTEXT, ViewName: "main", Key: MAIN_STAGING_CONTEXT_KEY, }, PatchBuilding: &BasicContext{ - OnFocus: func(opts ...OnFocusOpts) error { + OnFocus: func(opts ...types.OnFocusOpts) error { selectedLineIdx := -1 if len(opts) > 0 && (opts[0].ClickedViewName == "main" || opts[0].ClickedViewName == "secondary") { selectedLineIdx = opts[0].ClickedViewLineIdx @@ -162,7 +139,7 @@ func (gui *Gui) contextTree() ContextTree { return gui.onPatchBuildingFocus(selectedLineIdx) }, - Kind: MAIN_CONTEXT, + Kind: types.MAIN_CONTEXT, ViewName: "main", Key: MAIN_PATCH_BUILDING_CONTEXT_KEY, }, @@ -175,30 +152,30 @@ func (gui *Gui) contextTree() ContextTree { }, Credentials: &BasicContext{ OnFocus: OnFocusWrapper(gui.handleAskFocused), - Kind: PERSISTENT_POPUP, + Kind: types.PERSISTENT_POPUP, ViewName: "credentials", Key: CREDENTIALS_CONTEXT_KEY, }, Confirmation: &BasicContext{ OnFocus: OnFocusWrapper(gui.handleAskFocused), - Kind: TEMPORARY_POPUP, + Kind: types.TEMPORARY_POPUP, ViewName: "confirmation", Key: CONFIRMATION_CONTEXT_KEY, }, Suggestions: gui.suggestionsListContext(), CommitMessage: &BasicContext{ OnFocus: OnFocusWrapper(gui.handleCommitMessageFocused), - Kind: PERSISTENT_POPUP, + Kind: types.PERSISTENT_POPUP, ViewName: "commitMessage", Key: COMMIT_MESSAGE_CONTEXT_KEY, }, Search: &BasicContext{ - Kind: PERSISTENT_POPUP, + Kind: types.PERSISTENT_POPUP, ViewName: "search", Key: SEARCH_CONTEXT_KEY, }, CommandLog: &BasicContext{ - Kind: EXTRAS_CONTEXT, + Kind: types.EXTRAS_CONTEXT, ViewName: "extras", Key: COMMAND_LOG_CONTEXT_KEY, OnGetOptionsMap: gui.getMergingOptions, @@ -212,72 +189,8 @@ func (gui *Gui) contextTree() ContextTree { // using this wrapper for when an onFocus function doesn't care about any potential // props that could be passed -func OnFocusWrapper(f func() error) func(opts ...OnFocusOpts) error { - return func(opts ...OnFocusOpts) error { +func OnFocusWrapper(f func() error) func(opts ...types.OnFocusOpts) error { + return func(opts ...types.OnFocusOpts) error { return f() } } - -func (tree ContextTree) initialViewContextMap() map[string]Context { - return map[string]Context{ - "status": tree.Status, - "files": tree.Files, - "branches": tree.Branches, - "commits": tree.BranchCommits, - "commitFiles": tree.CommitFiles, - "stash": tree.Stash, - "menu": tree.Menu, - "confirmation": tree.Confirmation, - "credentials": tree.Credentials, - "commitMessage": tree.CommitMessage, - "main": tree.Normal, - "secondary": tree.Normal, - "extras": tree.CommandLog, - } -} - -func (tree ContextTree) initialViewTabContextMap() map[string][]tabContext { - return map[string][]tabContext{ - "branches": { - { - tab: "Local Branches", - contexts: []Context{tree.Branches}, - }, - { - tab: "Remotes", - contexts: []Context{ - tree.Remotes, - tree.RemoteBranches, - }, - }, - { - tab: "Tags", - contexts: []Context{tree.Tags}, - }, - }, - "commits": { - { - tab: "Commits", - contexts: []Context{tree.BranchCommits}, - }, - { - tab: "Reflog", - contexts: []Context{ - tree.ReflogCommits, - }, - }, - }, - "files": { - { - tab: "Files", - contexts: []Context{tree.Files}, - }, - { - tab: "Submodules", - contexts: []Context{ - tree.Submodules, - }, - }, - }, - } -} diff --git a/pkg/gui/controllers/bisect_controller.go b/pkg/gui/controllers/bisect_controller.go new file mode 100644 index 000000000..674e79f76 --- /dev/null +++ b/pkg/gui/controllers/bisect_controller.go @@ -0,0 +1,273 @@ +package controllers + +import ( + "fmt" + "strings" + + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type BisectController struct { + c *ControllerCommon + context types.IListContext + git *commands.GitCommand + + getSelectedLocalCommit func() *models.Commit + getCommits func() []*models.Commit +} + +var _ types.IController = &BisectController{} + +func NewBisectController( + c *ControllerCommon, + context types.IListContext, + git *commands.GitCommand, + + getSelectedLocalCommit func() *models.Commit, + getCommits func() []*models.Commit, +) *BisectController { + return &BisectController{ + c: c, + context: context, + git: git, + + getSelectedLocalCommit: getSelectedLocalCommit, + getCommits: getCommits, + } +} + +func (self *BisectController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { + bindings := []*types.Binding{ + { + Key: getKey(config.Commits.ViewBisectOptions), + Handler: guards.OutsideFilterMode(self.checkSelected(self.openMenu)), + Description: self.c.Tr.LcViewBisectOptions, + OpensMenu: true, + }, + } + + return bindings +} + +func (self *BisectController) openMenu(commit *models.Commit) error { + // no shame in getting this directly rather than using the cached value + // given how cheap it is to obtain + info := self.git.Bisect.GetInfo() + if info.Started() { + return self.openMidBisectMenu(info, commit) + } else { + return self.openStartBisectMenu(info, commit) + } +} + +func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, commit *models.Commit) error { + // if there is not yet a 'current' bisect commit, or if we have + // selected the current commit, we need to jump to the next 'current' commit + // after we perform a bisect action. The reason we don't unconditionally jump + // is that sometimes the user will want to go and mark a few commits as skipped + // in a row and they wouldn't want to be jumped back to the current bisect + // commit each time. + // Originally we were allowing the user to, from the bisect menu, select whether + // they were talking about the selected commit or the current bisect commit, + // and that was a bit confusing (and required extra keypresses). + selectCurrentAfter := info.GetCurrentSha() == "" || info.GetCurrentSha() == commit.Sha + // we need to wait to reselect if our bisect commits aren't ancestors of our 'start' + // ref, because we'll be reloading our commits in that case. + waitToReselect := selectCurrentAfter && !self.git.Bisect.ReachableFromStart(info) + + menuItems := []*popup.MenuItem{ + { + DisplayString: fmt.Sprintf(self.c.Tr.Bisect.Mark, commit.ShortSha(), info.NewTerm()), + OnPress: func() error { + self.c.LogAction(self.c.Tr.Actions.BisectMark) + if err := self.git.Bisect.Mark(commit.Sha, info.NewTerm()); err != nil { + return self.c.Error(err) + } + + return self.afterMark(selectCurrentAfter, waitToReselect) + }, + }, + { + DisplayString: fmt.Sprintf(self.c.Tr.Bisect.Mark, commit.ShortSha(), info.OldTerm()), + OnPress: func() error { + self.c.LogAction(self.c.Tr.Actions.BisectMark) + if err := self.git.Bisect.Mark(commit.Sha, info.OldTerm()); err != nil { + return self.c.Error(err) + } + + return self.afterMark(selectCurrentAfter, waitToReselect) + }, + }, + { + DisplayString: fmt.Sprintf(self.c.Tr.Bisect.Skip, commit.ShortSha()), + OnPress: func() error { + self.c.LogAction(self.c.Tr.Actions.BisectSkip) + if err := self.git.Bisect.Skip(commit.Sha); err != nil { + return self.c.Error(err) + } + + return self.afterMark(selectCurrentAfter, waitToReselect) + }, + }, + { + DisplayString: self.c.Tr.Bisect.ResetOption, + OnPress: func() error { + return self.Reset() + }, + }, + } + + return self.c.Menu(popup.CreateMenuOptions{ + Title: self.c.Tr.Bisect.BisectMenuTitle, + Items: menuItems, + }) +} + +func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo, commit *models.Commit) error { + return self.c.Menu(popup.CreateMenuOptions{ + Title: self.c.Tr.Bisect.BisectMenuTitle, + Items: []*popup.MenuItem{ + { + DisplayString: fmt.Sprintf(self.c.Tr.Bisect.MarkStart, commit.ShortSha(), info.NewTerm()), + OnPress: func() error { + self.c.LogAction(self.c.Tr.Actions.StartBisect) + if err := self.git.Bisect.Start(); err != nil { + return self.c.Error(err) + } + + if err := self.git.Bisect.Mark(commit.Sha, info.NewTerm()); err != nil { + return self.c.Error(err) + } + + return self.postBisectCommandRefresh() + }, + }, + { + DisplayString: fmt.Sprintf(self.c.Tr.Bisect.MarkStart, commit.ShortSha(), info.OldTerm()), + OnPress: func() error { + self.c.LogAction(self.c.Tr.Actions.StartBisect) + if err := self.git.Bisect.Start(); err != nil { + return self.c.Error(err) + } + + if err := self.git.Bisect.Mark(commit.Sha, info.OldTerm()); err != nil { + return self.c.Error(err) + } + + return self.postBisectCommandRefresh() + }, + }, + }, + }) +} + +func (self *BisectController) Reset() error { + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.Bisect.ResetTitle, + Prompt: self.c.Tr.Bisect.ResetPrompt, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.ResetBisect) + if err := self.git.Bisect.Reset(); err != nil { + return self.c.Error(err) + } + + return self.postBisectCommandRefresh() + }, + }) +} + +func (self *BisectController) showBisectCompleteMessage(candidateShas []string) error { + prompt := self.c.Tr.Bisect.CompletePrompt + if len(candidateShas) > 1 { + prompt = self.c.Tr.Bisect.CompletePromptIndeterminate + } + + formattedCommits, err := self.git.Commit.GetCommitsOneline(candidateShas) + if err != nil { + return self.c.Error(err) + } + + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.Bisect.CompleteTitle, + Prompt: fmt.Sprintf(prompt, strings.TrimSpace(formattedCommits)), + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.ResetBisect) + if err := self.git.Bisect.Reset(); err != nil { + return self.c.Error(err) + } + + return self.postBisectCommandRefresh() + }, + }) +} + +func (self *BisectController) afterMark(selectCurrent bool, waitToReselect bool) error { + done, candidateShas, err := self.git.Bisect.IsDone() + if err != nil { + return self.c.Error(err) + } + + if err := self.afterBisectMarkRefresh(selectCurrent, waitToReselect); err != nil { + return self.c.Error(err) + } + + if done { + return self.showBisectCompleteMessage(candidateShas) + } + + return nil +} + +func (self *BisectController) postBisectCommandRefresh() error { + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{}}) +} + +func (self *BisectController) afterBisectMarkRefresh(selectCurrent bool, waitToReselect bool) error { + selectFn := func() { + if selectCurrent { + self.selectCurrentBisectCommit() + } + } + + if waitToReselect { + return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{}, Then: selectFn}) + } else { + selectFn() + + return self.postBisectCommandRefresh() + } +} + +func (self *BisectController) selectCurrentBisectCommit() { + info := self.git.Bisect.GetInfo() + if info.GetCurrentSha() != "" { + // find index of commit with that sha, move cursor to that. + for i, commit := range self.getCommits() { + if commit.Sha == info.GetCurrentSha() { + self.context.GetPanelState().SetSelectedLineIdx(i) + _ = self.context.HandleFocus() + break + } + } + } +} + +func (self *BisectController) checkSelected(callback func(*models.Commit) error) func() error { + return func() error { + commit := self.getSelectedLocalCommit() + if commit == nil { + return nil + } + + return callback(commit) + } +} + +func (self *BisectController) Context() types.Context { + return self.context +} diff --git a/pkg/gui/controllers/controller_common.go b/pkg/gui/controllers/controller_common.go new file mode 100644 index 000000000..013439945 --- /dev/null +++ b/pkg/gui/controllers/controller_common.go @@ -0,0 +1,10 @@ +package controllers + +import "github.com/jesseduffield/lazygit/pkg/common" + +// if Go let me do private struct embedding of structs with public fields (which it should) +// I would just do that. But alas. +type ControllerCommon struct { + *common.Common + IGuiCommon +} diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go new file mode 100644 index 000000000..10d378f9f --- /dev/null +++ b/pkg/gui/controllers/files_controller.go @@ -0,0 +1,737 @@ +package controllers + +import ( + "fmt" + "regexp" + "strings" + + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/filetree" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +type FilesController struct { + // I've said publicly that I'm against single-letter variable names but in this + // case I would actually prefer a _zero_ letter variable name in the form of + // struct embedding, but Go does not allow hiding public fields in an embedded struct + // to the client + c *ControllerCommon + context types.IListContext + git *commands.GitCommand + os *oscommands.OSCommand + + getSelectedFileNode func() *filetree.FileNode + allContexts context.ContextTree + fileTreeViewModel *filetree.FileTreeViewModel + enterSubmodule func(submodule *models.SubmoduleConfig) error + getSubmodules func() []*models.SubmoduleConfig + setCommitMessage func(message string) + getCheckedOutBranch func() *models.Branch + withGpgHandling func(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error + getFailedCommitMessage func() string + getCommits func() []*models.Commit + getSelectedPath func() string + switchToMergeFn func(path string) error + suggestionsHelper ISuggestionsHelper + refHelper IRefHelper + fileHelper IFileHelper + workingTreeHelper IWorkingTreeHelper +} + +var _ types.IController = &FilesController{} + +func NewFilesController( + c *ControllerCommon, + context types.IListContext, + git *commands.GitCommand, + os *oscommands.OSCommand, + getSelectedFileNode func() *filetree.FileNode, + allContexts context.ContextTree, + fileTreeViewModel *filetree.FileTreeViewModel, + enterSubmodule func(submodule *models.SubmoduleConfig) error, + getSubmodules func() []*models.SubmoduleConfig, + setCommitMessage func(message string), + withGpgHandling func(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error, + getFailedCommitMessage func() string, + getCommits func() []*models.Commit, + getSelectedPath func() string, + switchToMergeFn func(path string) error, + suggestionsHelper ISuggestionsHelper, + refHelper IRefHelper, + fileHelper IFileHelper, + workingTreeHelper IWorkingTreeHelper, +) *FilesController { + return &FilesController{ + c: c, + context: context, + git: git, + os: os, + getSelectedFileNode: getSelectedFileNode, + allContexts: allContexts, + fileTreeViewModel: fileTreeViewModel, + enterSubmodule: enterSubmodule, + getSubmodules: getSubmodules, + setCommitMessage: setCommitMessage, + withGpgHandling: withGpgHandling, + getFailedCommitMessage: getFailedCommitMessage, + getCommits: getCommits, + getSelectedPath: getSelectedPath, + switchToMergeFn: switchToMergeFn, + suggestionsHelper: suggestionsHelper, + refHelper: refHelper, + fileHelper: fileHelper, + workingTreeHelper: workingTreeHelper, + } +} + +func (self *FilesController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { + bindings := []*types.Binding{ + { + Key: getKey(config.Universal.Select), + Handler: self.checkSelectedFileNode(self.press), + Description: self.c.Tr.LcToggleStaged, + }, + { + Key: gocui.MouseLeft, + Handler: func() error { return self.context.HandleClick(self.checkSelectedFileNode(self.press)) }, + }, + { + Key: getKey(""), // TODO: softcode + Handler: self.handleStatusFilterPressed, + Description: self.c.Tr.LcFileFilter, + }, + { + Key: getKey(config.Files.CommitChanges), + Handler: self.HandleCommitPress, + Description: self.c.Tr.CommitChanges, + }, + { + Key: getKey(config.Files.CommitChangesWithoutHook), + Handler: self.HandleWIPCommitPress, + Description: self.c.Tr.LcCommitChangesWithoutHook, + }, + { + Key: getKey(config.Files.AmendLastCommit), + Handler: self.handleAmendCommitPress, + Description: self.c.Tr.AmendLastCommit, + }, + { + Key: getKey(config.Files.CommitChangesWithEditor), + Handler: self.HandleCommitEditorPress, + Description: self.c.Tr.CommitChangesWithEditor, + }, + { + Key: getKey(config.Universal.Edit), + Handler: self.edit, + Description: self.c.Tr.LcEditFile, + }, + { + Key: getKey(config.Universal.OpenFile), + Handler: self.Open, + Description: self.c.Tr.LcOpenFile, + }, + { + Key: getKey(config.Files.IgnoreFile), + Handler: self.ignore, + Description: self.c.Tr.LcIgnoreFile, + }, + { + Key: getKey(config.Files.RefreshFiles), + Handler: self.refresh, + Description: self.c.Tr.LcRefreshFiles, + }, + { + Key: getKey(config.Files.StashAllChanges), + Handler: self.stash, + Description: self.c.Tr.LcStashAllChanges, + }, + { + Key: getKey(config.Files.ViewStashOptions), + Handler: self.createStashMenu, + Description: self.c.Tr.LcViewStashOptions, + OpensMenu: true, + }, + { + Key: getKey(config.Files.ToggleStagedAll), + Handler: self.stageAll, + Description: self.c.Tr.LcToggleStagedAll, + }, + { + Key: getKey(config.Universal.GoInto), + Handler: self.enter, + Description: self.c.Tr.FileEnter, + }, + { + ViewName: "", + Key: getKey(config.Universal.ExecuteCustomCommand), + Handler: self.handleCustomCommand, + Description: self.c.Tr.LcExecuteCustomCommand, + }, + { + Key: getKey(config.Commits.ViewResetOptions), + Handler: self.createResetMenu, + Description: self.c.Tr.LcViewResetToUpstreamOptions, + OpensMenu: true, + }, + { + Key: getKey(config.Files.ToggleTreeView), + Handler: self.toggleTreeView, + Description: self.c.Tr.LcToggleTreeView, + }, + { + Key: getKey(config.Files.OpenMergeTool), + Handler: self.OpenMergeTool, + Description: self.c.Tr.LcOpenMergeTool, + }, + } + + return append(bindings, self.context.Keybindings(getKey, config, guards)...) +} + +func (self *FilesController) press(node *filetree.FileNode) error { + if node.IsLeaf() { + file := node.File + + if file.HasInlineMergeConflicts { + return self.c.PushContext(self.allContexts.Merging) + } + + if file.HasUnstagedChanges { + self.c.LogAction(self.c.Tr.Actions.StageFile) + if err := self.git.WorkingTree.StageFile(file.Name); err != nil { + return self.c.Error(err) + } + } else { + self.c.LogAction(self.c.Tr.Actions.UnstageFile) + if err := self.git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil { + return self.c.Error(err) + } + } + } else { + // if any files within have inline merge conflicts we can't stage or unstage, + // or it'll end up with those >>>>>> lines actually staged + if node.GetHasInlineMergeConflicts() { + return self.c.ErrorMsg(self.c.Tr.ErrStageDirWithInlineMergeConflicts) + } + + if node.GetHasUnstagedChanges() { + self.c.LogAction(self.c.Tr.Actions.StageFile) + if err := self.git.WorkingTree.StageFile(node.Path); err != nil { + return self.c.Error(err) + } + } else { + // pretty sure it doesn't matter that we're always passing true here + self.c.LogAction(self.c.Tr.Actions.UnstageFile) + if err := self.git.WorkingTree.UnStageFile([]string{node.Path}, true); err != nil { + return self.c.Error(err) + } + } + } + + if err := self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}); err != nil { + return err + } + + return self.context.HandleFocus() +} + +func (self *FilesController) checkSelectedFileNode(callback func(*filetree.FileNode) error) func() error { + return func() error { + node := self.getSelectedFileNode() + if node == nil { + return nil + } + + return callback(node) + } +} + +func (self *FilesController) checkSelectedFile(callback func(*models.File) error) func() error { + return func() error { + file := self.getSelectedFile() + if file == nil { + return nil + } + + return callback(file) + } +} + +func (self *FilesController) Context() types.Context { + return self.context +} + +func (self *FilesController) getSelectedFile() *models.File { + node := self.getSelectedFileNode() + if node == nil { + return nil + } + return node.File +} + +func (self *FilesController) enter() error { + return self.EnterFile(types.OnFocusOpts{ClickedViewName: "", ClickedViewLineIdx: -1}) +} + +func (self *FilesController) EnterFile(opts types.OnFocusOpts) error { + node := self.getSelectedFileNode() + if node == nil { + return nil + } + + if node.File == nil { + return self.handleToggleDirCollapsed() + } + + file := node.File + + submoduleConfigs := self.getSubmodules() + if file.IsSubmodule(submoduleConfigs) { + submoduleConfig := file.SubmoduleConfig(submoduleConfigs) + return self.enterSubmodule(submoduleConfig) + } + + if file.HasInlineMergeConflicts { + return self.switchToMerge() + } + if file.HasMergeConflicts { + return self.c.ErrorMsg(self.c.Tr.FileStagingRequirements) + } + + return self.c.PushContext(self.allContexts.Staging, opts) +} + +func (self *FilesController) allFilesStaged() bool { + for _, file := range self.fileTreeViewModel.GetAllFiles() { + if file.HasUnstagedChanges { + return false + } + } + return true +} + +func (self *FilesController) stageAll() error { + var err error + if self.allFilesStaged() { + self.c.LogAction(self.c.Tr.Actions.UnstageAllFiles) + err = self.git.WorkingTree.UnstageAll() + } else { + self.c.LogAction(self.c.Tr.Actions.StageAllFiles) + err = self.git.WorkingTree.StageAll() + } + if err != nil { + _ = self.c.Error(err) + } + + if err := self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}); err != nil { + return err + } + + return self.allContexts.Files.HandleFocus() +} + +func (self *FilesController) ignore() error { + node := self.getSelectedFileNode() + if node == nil { + return nil + } + + if node.GetPath() == ".gitignore" { + return self.c.ErrorMsg("Cannot ignore .gitignore") + } + + unstageFiles := func() error { + return node.ForEachFile(func(file *models.File) error { + if file.HasStagedChanges { + if err := self.git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil { + return err + } + } + + return nil + }) + } + + if node.GetIsTracked() { + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.IgnoreTracked, + Prompt: self.c.Tr.IgnoreTrackedPrompt, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.IgnoreFile) + // not 100% sure if this is necessary but I'll assume it is + if err := unstageFiles(); err != nil { + return err + } + + if err := self.git.WorkingTree.RemoveTrackedFiles(node.GetPath()); err != nil { + return err + } + + if err := self.git.WorkingTree.Ignore(node.GetPath()); err != nil { + return err + } + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}) + }, + }) + } + + self.c.LogAction(self.c.Tr.Actions.IgnoreFile) + + if err := unstageFiles(); err != nil { + return err + } + + if err := self.git.WorkingTree.Ignore(node.GetPath()); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}) +} + +func (self *FilesController) HandleWIPCommitPress() error { + skipHookPrefix := self.c.UserConfig.Git.SkipHookPrefix + if skipHookPrefix == "" { + return self.c.ErrorMsg(self.c.Tr.SkipHookPrefixNotConfigured) + } + + self.setCommitMessage(skipHookPrefix) + + return self.HandleCommitPress() +} + +func (self *FilesController) commitPrefixConfigForRepo() *config.CommitPrefixConfig { + cfg, ok := self.c.UserConfig.Git.CommitPrefixes[utils.GetCurrentRepoName()] + if !ok { + return nil + } + + return &cfg +} + +func (self *FilesController) prepareFilesForCommit() error { + noStagedFiles := !self.workingTreeHelper.AnyStagedFiles() + if noStagedFiles && self.c.UserConfig.Gui.SkipNoStagedFilesWarning { + self.c.LogAction(self.c.Tr.Actions.StageAllFiles) + err := self.git.WorkingTree.StageAll() + if err != nil { + return err + } + + return self.syncRefresh() + } + + return nil +} + +// for when you need to refetch files before continuing an action. Runs synchronously. +func (self *FilesController) syncRefresh() error { + return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}}) +} + +func (self *FilesController) refresh() error { + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}) +} + +func (self *FilesController) HandleCommitPress() error { + if err := self.prepareFilesForCommit(); err != nil { + return self.c.Error(err) + } + + if self.fileTreeViewModel.GetItemsLength() == 0 { + return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle) + } + + if !self.workingTreeHelper.AnyStagedFiles() { + return self.promptToStageAllAndRetry(self.HandleCommitPress) + } + + failedCommitMessage := self.getFailedCommitMessage() + if len(failedCommitMessage) > 0 { + self.setCommitMessage(failedCommitMessage) + } else { + commitPrefixConfig := self.commitPrefixConfigForRepo() + if commitPrefixConfig != nil { + prefixPattern := commitPrefixConfig.Pattern + prefixReplace := commitPrefixConfig.Replace + rgx, err := regexp.Compile(prefixPattern) + if err != nil { + return self.c.ErrorMsg(fmt.Sprintf("%s: %s", self.c.Tr.LcCommitPrefixPatternError, err.Error())) + } + prefix := rgx.ReplaceAllString(self.getCheckedOutBranch().Name, prefixReplace) + self.setCommitMessage(prefix) + } + } + + if err := self.c.PushContext(self.allContexts.CommitMessage); err != nil { + return err + } + + return nil +} + +func (self *FilesController) promptToStageAllAndRetry(retry func() error) error { + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.NoFilesStagedTitle, + Prompt: self.c.Tr.NoFilesStagedPrompt, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.StageAllFiles) + if err := self.git.WorkingTree.StageAll(); err != nil { + return self.c.Error(err) + } + if err := self.syncRefresh(); err != nil { + return self.c.Error(err) + } + + return retry() + }, + }) +} + +func (self *FilesController) handleAmendCommitPress() error { + if self.fileTreeViewModel.GetItemsLength() == 0 { + return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle) + } + + if !self.workingTreeHelper.AnyStagedFiles() { + return self.promptToStageAllAndRetry(self.handleAmendCommitPress) + } + + if len(self.getCommits()) == 0 { + return self.c.ErrorMsg(self.c.Tr.NoCommitToAmend) + } + + return self.c.Ask(popup.AskOpts{ + Title: strings.Title(self.c.Tr.AmendLastCommit), + Prompt: self.c.Tr.SureToAmend, + HandleConfirm: func() error { + cmdObj := self.git.Commit.AmendHeadCmdObj() + self.c.LogAction(self.c.Tr.Actions.AmendCommit) + return self.withGpgHandling(cmdObj, self.c.Tr.AmendingStatus, nil) + }, + }) +} + +// HandleCommitEditorPress - handle when the user wants to commit changes via +// their editor rather than via the popup panel +func (self *FilesController) HandleCommitEditorPress() error { + if self.fileTreeViewModel.GetItemsLength() == 0 { + return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle) + } + + if !self.workingTreeHelper.AnyStagedFiles() { + return self.promptToStageAllAndRetry(self.HandleCommitEditorPress) + } + + self.c.LogAction(self.c.Tr.Actions.Commit) + return self.c.RunSubprocessAndRefresh( + self.git.Commit.CommitEditorCmdObj(), + ) +} + +func (self *FilesController) handleStatusFilterPressed() error { + return self.c.Menu(popup.CreateMenuOptions{ + Title: self.c.Tr.FilteringMenuTitle, + Items: []*popup.MenuItem{ + { + DisplayString: self.c.Tr.FilterStagedFiles, + OnPress: func() error { + return self.setStatusFiltering(filetree.DisplayStaged) + }, + }, + { + DisplayString: self.c.Tr.FilterUnstagedFiles, + OnPress: func() error { + return self.setStatusFiltering(filetree.DisplayUnstaged) + }, + }, + { + DisplayString: self.c.Tr.ResetCommitFilterState, + OnPress: func() error { + return self.setStatusFiltering(filetree.DisplayAll) + }, + }, + }, + }) +} + +func (self *FilesController) setStatusFiltering(filter filetree.FileTreeDisplayFilter) error { + self.fileTreeViewModel.SetFilter(filter) + return self.c.PostRefreshUpdate(self.context) +} + +func (self *FilesController) edit() error { + node := self.getSelectedFileNode() + if node == nil { + return nil + } + + if node.File == nil { + return self.c.ErrorMsg(self.c.Tr.ErrCannotEditDirectory) + } + + return self.fileHelper.EditFile(node.GetPath()) +} + +func (self *FilesController) Open() error { + node := self.getSelectedFileNode() + if node == nil { + return nil + } + + return self.fileHelper.OpenFile(node.GetPath()) +} + +func (self *FilesController) switchToMerge() error { + file := self.getSelectedFile() + if file == nil { + return nil + } + + self.switchToMergeFn(path) +} + +func (self *FilesController) handleCustomCommand() error { + return self.c.Prompt(popup.PromptOpts{ + Title: self.c.Tr.CustomCommand, + FindSuggestionsFunc: self.suggestionsHelper.GetCustomCommandsHistorySuggestionsFunc(), + HandleConfirm: func(command string) error { + self.c.GetAppState().CustomCommandsHistory = utils.Limit( + utils.Uniq( + append(self.c.GetAppState().CustomCommandsHistory, command), + ), + 1000, + ) + + err := self.c.SaveAppState() + if err != nil { + self.c.Log.Error(err) + } + + self.c.LogAction(self.c.Tr.Actions.CustomCommand) + return self.c.RunSubprocessAndRefresh( + self.os.Cmd.NewShell(command), + ) + }, + }) +} + +func (self *FilesController) createStashMenu() error { + return self.c.Menu(popup.CreateMenuOptions{ + Title: self.c.Tr.LcStashOptions, + Items: []*popup.MenuItem{ + { + DisplayString: self.c.Tr.LcStashAllChanges, + OnPress: func() error { + self.c.LogAction(self.c.Tr.Actions.StashAllChanges) + return self.handleStashSave(self.git.Stash.Save) + }, + }, + { + DisplayString: self.c.Tr.LcStashStagedChanges, + OnPress: func() error { + self.c.LogAction(self.c.Tr.Actions.StashStagedChanges) + return self.handleStashSave(self.git.Stash.SaveStagedChanges) + }, + }, + }, + }) +} + +func (self *FilesController) stash() error { + return self.handleStashSave(self.git.Stash.Save) +} + +func (self *FilesController) createResetMenu() error { + return self.refHelper.CreateGitResetMenu("@{upstream}") +} + +func (self *FilesController) handleToggleDirCollapsed() error { + node := self.getSelectedFileNode() + if node == nil { + return nil + } + + self.fileTreeViewModel.ToggleCollapsed(node.GetPath()) + + if err := self.c.PostRefreshUpdate(self.allContexts.Files); err != nil { + self.c.Log.Error(err) + } + + return nil +} + +func (self *FilesController) toggleTreeView() error { + // get path of currently selected file + path := self.getSelectedPath() + + self.fileTreeViewModel.ToggleShowTree() + + // find that same node in the new format and move the cursor to it + if path != "" { + self.fileTreeViewModel.ExpandToPath(path) + index, found := self.fileTreeViewModel.GetIndexForPath(path) + if found { + self.context.GetPanelState().SetSelectedLineIdx(index) + } + } + + return self.c.PostRefreshUpdate(self.context) +} + +func (self *FilesController) OpenMergeTool() error { + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.MergeToolTitle, + Prompt: self.c.Tr.MergeToolPrompt, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.OpenMergeTool) + return self.c.RunSubprocessAndRefresh( + self.git.WorkingTree.OpenMergeToolCmdObj(), + ) + }, + }) +} + +func (self *FilesController) ResetSubmodule(submodule *models.SubmoduleConfig) error { + return self.c.WithWaitingStatus(self.c.Tr.LcResettingSubmoduleStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.ResetSubmodule) + + file := self.workingTreeHelper.FileForSubmodule(submodule) + if file != nil { + if err := self.git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil { + return self.c.Error(err) + } + } + + if err := self.git.Submodule.Stash(submodule); err != nil { + return self.c.Error(err) + } + if err := self.git.Submodule.Reset(submodule); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.SUBMODULES}}) + }) +} + +func (self *FilesController) handleStashSave(stashFunc func(message string) error) error { + if !self.workingTreeHelper.IsWorkingTreeDirty() { + return self.c.ErrorMsg(self.c.Tr.NoTrackedStagedFilesStash) + } + + return self.c.Prompt(popup.PromptOpts{ + Title: self.c.Tr.StashChanges, + HandleConfirm: func(stashComment string) error { + if err := stashFunc(stashComment); err != nil { + return self.c.Error(err) + } + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}}) + }, + }) +} diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go new file mode 100644 index 000000000..1d79bd2dd --- /dev/null +++ b/pkg/gui/controllers/local_commits_controller.go @@ -0,0 +1,783 @@ +package controllers + +import ( + "fmt" + + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/hosting_service" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +type ( + CheckoutRefFn func(refName string, opts types.CheckoutRefOptions) error + CreateGitResetMenuFn func(refName string) error + SwitchToCommitFilesContextFn func(SwitchToCommitFilesContextOpts) error + CreateTagMenuFn func(commitSha string) error + GetHostingServiceMgrFn func() *hosting_service.HostingServiceMgr + PullFilesFn func() error + CheckMergeOrRebase func(error) error + OpenSearchFn func(viewName string) error +) + +type LocalCommitsController struct { + c *ControllerCommon + context types.IListContext + os *oscommands.OSCommand + git *commands.GitCommand + refHelper IRefHelper + + getSelectedLocalCommit func() *models.Commit + getCommits func() []*models.Commit + getSelectedLocalCommitIdx func() int + checkMergeOrRebase CheckMergeOrRebase + pullFiles PullFilesFn + createTagMenu CreateTagMenuFn + getHostingServiceMgr GetHostingServiceMgrFn + switchToCommitFilesContext SwitchToCommitFilesContextFn + openSearch OpenSearchFn + getLimitCommits func() bool + setLimitCommits func(bool) + getShowWholeGitGraph func() bool + setShowWholeGitGraph func(bool) +} + +var _ types.IController = &LocalCommitsController{} + +func NewLocalCommitsController( + c *ControllerCommon, + context types.IListContext, + os *oscommands.OSCommand, + git *commands.GitCommand, + refHelper IRefHelper, + getSelectedLocalCommit func() *models.Commit, + getCommits func() []*models.Commit, + getSelectedLocalCommitIdx func() int, + checkMergeOrRebase CheckMergeOrRebase, + pullFiles PullFilesFn, + createTagMenu CreateTagMenuFn, + getHostingServiceMgr GetHostingServiceMgrFn, + switchToCommitFilesContext SwitchToCommitFilesContextFn, + openSearch OpenSearchFn, + getLimitCommits func() bool, + setLimitCommits func(bool), + getShowWholeGitGraph func() bool, + setShowWholeGitGraph func(bool), +) *LocalCommitsController { + return &LocalCommitsController{ + c: c, + context: context, + os: os, + git: git, + refHelper: refHelper, + getSelectedLocalCommit: getSelectedLocalCommit, + getCommits: getCommits, + getSelectedLocalCommitIdx: getSelectedLocalCommitIdx, + checkMergeOrRebase: checkMergeOrRebase, + pullFiles: pullFiles, + createTagMenu: createTagMenu, + getHostingServiceMgr: getHostingServiceMgr, + switchToCommitFilesContext: switchToCommitFilesContext, + openSearch: openSearch, + getLimitCommits: getLimitCommits, + setLimitCommits: setLimitCommits, + getShowWholeGitGraph: getShowWholeGitGraph, + setShowWholeGitGraph: setShowWholeGitGraph, + } +} + +func (self *LocalCommitsController) Keybindings( + getKey func(key string) interface{}, + config config.KeybindingConfig, + guards types.KeybindingGuards, +) []*types.Binding { + outsideFilterModeBindings := []*types.Binding{ + { + Key: getKey(config.Commits.SquashDown), + Handler: self.squashDown, + Description: self.c.Tr.LcSquashDown, + }, + { + Key: getKey(config.Commits.MarkCommitAsFixup), + Handler: self.fixup, + Description: self.c.Tr.LcFixupCommit, + }, + { + Key: getKey(config.Commits.RenameCommit), + Handler: self.checkSelected(self.reword), + Description: self.c.Tr.LcRewordCommit, + }, + { + Key: getKey(config.Commits.RenameCommitWithEditor), + Handler: self.rewordEditor, + Description: self.c.Tr.LcRenameCommitEditor, + }, + { + Key: getKey(config.Universal.Remove), + Handler: self.drop, + Description: self.c.Tr.LcDeleteCommit, + }, + { + Key: getKey(config.Universal.Edit), + Handler: self.edit, + Description: self.c.Tr.LcEditCommit, + }, + { + Key: getKey(config.Commits.PickCommit), + Handler: self.pick, + Description: self.c.Tr.LcPickCommit, + }, + { + Key: getKey(config.Commits.CreateFixupCommit), + Handler: self.checkSelected(self.handleCreateFixupCommit), + Description: self.c.Tr.LcCreateFixupCommit, + }, + { + Key: getKey(config.Commits.SquashAboveCommits), + Handler: self.checkSelected(self.handleSquashAllAboveFixupCommits), + Description: self.c.Tr.LcSquashAboveCommits, + }, + { + Key: getKey(config.Commits.MoveDownCommit), + Handler: self.handleCommitMoveDown, + Description: self.c.Tr.LcMoveDownCommit, + }, + { + Key: getKey(config.Commits.MoveUpCommit), + Handler: self.handleCommitMoveUp, + Description: self.c.Tr.LcMoveUpCommit, + }, + { + Key: getKey(config.Commits.AmendToCommit), + Handler: self.handleCommitAmendTo, + Description: self.c.Tr.LcAmendToCommit, + }, + { + Key: getKey(config.Commits.RevertCommit), + Handler: self.checkSelected(self.handleCommitRevert), + Description: self.c.Tr.LcRevertCommit, + }, + // overriding these navigation keybindings because we might need to load + // more commits on demand + { + Key: getKey(config.Universal.StartSearch), + Handler: func() error { return self.handleOpenSearch("commits") }, + Description: self.c.Tr.LcStartSearch, + Tag: "navigation", + }, + { + Key: getKey(config.Universal.GotoBottom), + Handler: self.gotoBottom, + Description: self.c.Tr.LcGotoBottom, + Tag: "navigation", + }, + { + Key: gocui.MouseLeft, + Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, + }, + } + + for _, binding := range outsideFilterModeBindings { + binding.Handler = guards.OutsideFilterMode(binding.Handler) + } + + bindings := append(outsideFilterModeBindings, []*types.Binding{ + { + Key: getKey(config.Commits.OpenLogMenu), + Handler: self.handleOpenLogMenu, + Description: self.c.Tr.LcOpenLogMenu, + OpensMenu: true, + }, + { + Key: getKey(config.Commits.ViewResetOptions), + Handler: self.checkSelected(self.handleCreateCommitResetMenu), + Description: self.c.Tr.LcResetToThisCommit, + }, + { + Key: getKey(config.Universal.GoInto), + Handler: self.checkSelected(self.enter), + Description: self.c.Tr.LcViewCommitFiles, + }, + { + Key: getKey(config.Commits.CheckoutCommit), + Handler: self.checkSelected(self.handleCheckoutCommit), + Description: self.c.Tr.LcCheckoutCommit, + }, + { + Key: getKey(config.Commits.TagCommit), + Handler: self.checkSelected(self.handleTagCommit), + Description: self.c.Tr.LcTagCommit, + }, + { + Key: getKey(config.Commits.CopyCommitMessageToClipboard), + Handler: self.checkSelected(self.handleCopySelectedCommitMessageToClipboard), + Description: self.c.Tr.LcCopyCommitMessageToClipboard, + }, + { + Key: getKey(config.Commits.OpenInBrowser), + Handler: self.checkSelected(self.handleOpenCommitInBrowser), + Description: self.c.Tr.LcOpenCommitInBrowser, + }, + }...) + + return append(bindings, self.context.Keybindings(getKey, config, guards)...) +} + +func (self *LocalCommitsController) squashDown() error { + if len(self.getCommits()) <= 1 { + return self.c.ErrorMsg(self.c.Tr.YouNoCommitsToSquash) + } + + applied, err := self.handleMidRebaseCommand("squash") + if err != nil { + return err + } + if applied { + return nil + } + + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.Squash, + Prompt: self.c.Tr.SureSquashThisCommit, + HandleConfirm: func() error { + return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.SquashCommitDown) + return self.interactiveRebase("squash") + }) + }, + }) +} + +func (self *LocalCommitsController) fixup() error { + if len(self.getCommits()) <= 1 { + return self.c.ErrorMsg(self.c.Tr.YouNoCommitsToSquash) + } + + applied, err := self.handleMidRebaseCommand("fixup") + if err != nil { + return err + } + if applied { + return nil + } + + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.Fixup, + Prompt: self.c.Tr.SureFixupThisCommit, + HandleConfirm: func() error { + return self.c.WithWaitingStatus(self.c.Tr.FixingStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.FixupCommit) + return self.interactiveRebase("fixup") + }) + }, + }) +} + +func (self *LocalCommitsController) reword(commit *models.Commit) error { + applied, err := self.handleMidRebaseCommand("reword") + if err != nil { + return err + } + if applied { + return nil + } + + message, err := self.git.Commit.GetCommitMessage(commit.Sha) + if err != nil { + return self.c.Error(err) + } + + // TODO: use the commit message panel here + return self.c.Prompt(popup.PromptOpts{ + Title: self.c.Tr.LcRewordCommit, + InitialContent: message, + HandleConfirm: func(response string) error { + self.c.LogAction(self.c.Tr.Actions.RewordCommit) + if err := self.git.Rebase.RewordCommit(self.getCommits(), self.getSelectedLocalCommitIdx(), response); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + }, + }) +} + +func (self *LocalCommitsController) rewordEditor() error { + applied, err := self.handleMidRebaseCommand("reword") + if err != nil { + return err + } + if applied { + return nil + } + + self.c.LogAction(self.c.Tr.Actions.RewordCommit) + subProcess, err := self.git.Rebase.RewordCommitInEditor( + self.getCommits(), self.getSelectedLocalCommitIdx(), + ) + if err != nil { + return self.c.Error(err) + } + if subProcess != nil { + return self.c.RunSubprocessAndRefresh(subProcess) + } + + return nil +} + +func (self *LocalCommitsController) drop() error { + applied, err := self.handleMidRebaseCommand("drop") + if err != nil { + return err + } + if applied { + return nil + } + + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.DeleteCommitTitle, + Prompt: self.c.Tr.DeleteCommitPrompt, + HandleConfirm: func() error { + return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.DropCommit) + return self.interactiveRebase("drop") + }) + }, + }) +} + +func (self *LocalCommitsController) edit() error { + applied, err := self.handleMidRebaseCommand("edit") + if err != nil { + return err + } + if applied { + return nil + } + + return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.EditCommit) + return self.interactiveRebase("edit") + }) +} + +func (self *LocalCommitsController) pick() error { + applied, err := self.handleMidRebaseCommand("pick") + if err != nil { + return err + } + if applied { + return nil + } + + // at this point we aren't actually rebasing so we will interpret this as an + // attempt to pull. We might revoke this later after enabling configurable keybindings + return self.pullFiles() +} + +func (self *LocalCommitsController) interactiveRebase(action string) error { + err := self.git.Rebase.InteractiveRebase(self.getCommits(), self.getSelectedLocalCommitIdx(), action) + return self.checkMergeOrRebase(err) +} + +// handleMidRebaseCommand sees if the selected commit is in fact a rebasing +// commit meaning you are trying to edit the todo file rather than actually +// begin a rebase. It then updates the todo file with that action +func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool, error) { + selectedCommit := self.getSelectedLocalCommit() + if selectedCommit.Status != "rebasing" { + return false, nil + } + + // for now we do not support setting 'reword' because it requires an editor + // and that means we either unconditionally wait around for the subprocess to ask for + // our input or we set a lazygit client as the EDITOR env variable and have it + // request us to edit the commit message when prompted. + if action == "reword" { + return true, self.c.ErrorMsg(self.c.Tr.LcRewordNotSupported) + } + + self.c.LogAction("Update rebase TODO") + self.c.LogCommand( + fmt.Sprintf("Updating rebase action of commit %s to '%s'", selectedCommit.ShortSha(), action), + false, + ) + + if err := self.git.Rebase.EditRebaseTodo( + self.getSelectedLocalCommitIdx(), action, + ); err != nil { + return false, self.c.Error(err) + } + + return true, self.c.Refresh(types.RefreshOptions{ + Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS}, + }) +} + +func (self *LocalCommitsController) handleCommitMoveDown() error { + index := self.context.GetPanelState().GetSelectedLineIdx() + commits := self.getCommits() + selectedCommit := self.getCommits()[index] + if selectedCommit.Status == "rebasing" { + if commits[index+1].Status != "rebasing" { + return nil + } + + // logging directly here because MoveTodoDown doesn't have enough information + // to provide a useful log + self.c.LogAction(self.c.Tr.Actions.MoveCommitDown) + self.c.LogCommand(fmt.Sprintf("Moving commit %s down", selectedCommit.ShortSha()), false) + + if err := self.git.Rebase.MoveTodoDown(index); err != nil { + return self.c.Error(err) + } + self.context.HandleNextLine() + return self.c.Refresh(types.RefreshOptions{ + Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS}, + }) + } + + return self.c.WithWaitingStatus(self.c.Tr.MovingStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.MoveCommitDown) + err := self.git.Rebase.MoveCommitDown(self.getCommits(), index) + if err == nil { + self.context.HandleNextLine() + } + return self.checkMergeOrRebase(err) + }) +} + +func (self *LocalCommitsController) handleCommitMoveUp() error { + index := self.context.GetPanelState().GetSelectedLineIdx() + if index == 0 { + return nil + } + + selectedCommit := self.getCommits()[index] + if selectedCommit.Status == "rebasing" { + // logging directly here because MoveTodoDown doesn't have enough information + // to provide a useful log + self.c.LogAction(self.c.Tr.Actions.MoveCommitUp) + self.c.LogCommand( + fmt.Sprintf("Moving commit %s up", selectedCommit.ShortSha()), + false, + ) + + if err := self.git.Rebase.MoveTodoDown(index - 1); err != nil { + return self.c.Error(err) + } + self.context.HandlePrevLine() + return self.c.Refresh(types.RefreshOptions{ + Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS}, + }) + } + + return self.c.WithWaitingStatus(self.c.Tr.MovingStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.MoveCommitUp) + err := self.git.Rebase.MoveCommitDown(self.getCommits(), index-1) + if err == nil { + self.context.HandlePrevLine() + } + return self.checkMergeOrRebase(err) + }) +} + +func (self *LocalCommitsController) handleCommitAmendTo() error { + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.AmendCommitTitle, + Prompt: self.c.Tr.AmendCommitPrompt, + HandleConfirm: func() error { + return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.AmendCommit) + err := self.git.Rebase.AmendTo(self.getSelectedLocalCommit().Sha) + return self.checkMergeOrRebase(err) + }) + }, + }) +} + +func (self *LocalCommitsController) handleCommitRevert(commit *models.Commit) error { + if commit.IsMerge() { + return self.createRevertMergeCommitMenu(commit) + } else { + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.Actions.RevertCommit, + Prompt: utils.ResolvePlaceholderString( + self.c.Tr.ConfirmRevertCommit, + map[string]string{ + "selectedCommit": commit.ShortSha(), + }), + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.RevertCommit) + if err := self.git.Commit.Revert(commit.Sha); err != nil { + return self.c.Error(err) + } + return self.afterRevertCommit() + }, + }) + } +} + +func (self *LocalCommitsController) createRevertMergeCommitMenu(commit *models.Commit) error { + menuItems := make([]*popup.MenuItem, len(commit.Parents)) + for i, parentSha := range commit.Parents { + i := i + message, err := self.git.Commit.GetCommitMessageFirstLine(parentSha) + if err != nil { + return self.c.Error(err) + } + + menuItems[i] = &popup.MenuItem{ + DisplayString: fmt.Sprintf("%s: %s", utils.SafeTruncate(parentSha, 8), message), + OnPress: func() error { + parentNumber := i + 1 + self.c.LogAction(self.c.Tr.Actions.RevertCommit) + if err := self.git.Commit.RevertMerge(commit.Sha, parentNumber); err != nil { + return self.c.Error(err) + } + return self.afterRevertCommit() + }, + } + } + + return self.c.Menu(popup.CreateMenuOptions{Title: self.c.Tr.SelectParentCommitForMerge, Items: menuItems}) +} + +func (self *LocalCommitsController) afterRevertCommit() error { + self.context.HandleNextLine() + return self.c.Refresh(types.RefreshOptions{ + Mode: types.BLOCK_UI, Scope: []types.RefreshableView{types.COMMITS, types.BRANCHES}, + }) +} + +func (self *LocalCommitsController) enter(commit *models.Commit) error { + return self.switchToCommitFilesContext(SwitchToCommitFilesContextOpts{ + RefName: commit.Sha, + CanRebase: true, + Context: self.context, + WindowName: "commits", + }) +} + +func (self *LocalCommitsController) handleCreateFixupCommit(commit *models.Commit) error { + prompt := utils.ResolvePlaceholderString( + self.c.Tr.SureCreateFixupCommit, + map[string]string{ + "commit": commit.Sha, + }, + ) + + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.CreateFixupCommit, + Prompt: prompt, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.CreateFixupCommit) + if err := self.git.Commit.CreateFixupCommit(commit.Sha); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + }, + }) +} + +func (self *LocalCommitsController) handleSquashAllAboveFixupCommits(commit *models.Commit) error { + prompt := utils.ResolvePlaceholderString( + self.c.Tr.SureSquashAboveCommits, + map[string]string{ + "commit": commit.Sha, + }, + ) + + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.SquashAboveCommits, + Prompt: prompt, + HandleConfirm: func() error { + return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.SquashAllAboveFixupCommits) + err := self.git.Rebase.SquashAllAboveFixupCommits(commit.Sha) + return self.checkMergeOrRebase(err) + }) + }, + }) +} + +func (self *LocalCommitsController) handleTagCommit(commit *models.Commit) error { + return self.createTagMenu(commit.Sha) +} + +func (self *LocalCommitsController) handleCheckoutCommit(commit *models.Commit) error { + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.LcCheckoutCommit, + Prompt: self.c.Tr.SureCheckoutThisCommit, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.CheckoutCommit) + return self.refHelper.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) + }, + }) +} + +func (self *LocalCommitsController) handleCreateCommitResetMenu(commit *models.Commit) error { + return self.refHelper.CreateGitResetMenu(commit.Sha) +} + +func (self *LocalCommitsController) handleOpenSearch(string) error { + // we usually lazyload these commits but now that we're searching we need to load them now + if self.getLimitCommits() { + self.setLimitCommits(false) + if err := self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS}}); err != nil { + return err + } + } + + return self.openSearch("commits") +} + +func (self *LocalCommitsController) gotoBottom() error { + // we usually lazyload these commits but now that we're jumping to the bottom we need to load them now + if self.getLimitCommits() { + self.setLimitCommits(false) + if err := self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}); err != nil { + return err + } + } + + self.context.HandleGotoBottom() + + return nil +} + +func (self *LocalCommitsController) handleCopySelectedCommitMessageToClipboard(commit *models.Commit) error { + message, err := self.git.Commit.GetCommitMessage(commit.Sha) + if err != nil { + return self.c.Error(err) + } + + self.c.LogAction(self.c.Tr.Actions.CopyCommitMessageToClipboard) + if err := self.os.CopyToClipboard(message); err != nil { + return self.c.Error(err) + } + + self.c.Toast(self.c.Tr.CommitMessageCopiedToClipboard) + + return nil +} + +func (self *LocalCommitsController) handleOpenLogMenu() error { + return self.c.Menu(popup.CreateMenuOptions{ + Title: self.c.Tr.LogMenuTitle, + Items: []*popup.MenuItem{ + { + DisplayString: self.c.Tr.ToggleShowGitGraphAll, + OnPress: func() error { + self.setShowWholeGitGraph(!self.getShowWholeGitGraph()) + + if self.getShowWholeGitGraph() { + self.setLimitCommits(false) + } + + return self.c.WithWaitingStatus(self.c.Tr.LcLoadingCommits, func() error { + return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}) + }) + }, + }, + { + DisplayString: self.c.Tr.ShowGitGraph, + OpensMenu: true, + OnPress: func() error { + onPress := func(value string) func() error { + return func() error { + self.c.UserConfig.Git.Log.ShowGraph = value + return nil + } + } + return self.c.Menu(popup.CreateMenuOptions{ + Title: self.c.Tr.LogMenuTitle, + Items: []*popup.MenuItem{ + { + DisplayString: "always", + OnPress: onPress("always"), + }, + { + DisplayString: "never", + OnPress: onPress("never"), + }, + { + DisplayString: "when maximised", + OnPress: onPress("when-maximised"), + }, + }, + }) + }, + }, + { + DisplayString: self.c.Tr.SortCommits, + OpensMenu: true, + OnPress: func() error { + onPress := func(value string) func() error { + return func() error { + self.c.UserConfig.Git.Log.Order = value + return self.c.WithWaitingStatus(self.c.Tr.LcLoadingCommits, func() error { + return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}) + }) + } + } + + return self.c.Menu(popup.CreateMenuOptions{ + Title: self.c.Tr.LogMenuTitle, + Items: []*popup.MenuItem{ + { + DisplayString: "topological (topo-order)", + OnPress: onPress("topo-order"), + }, + { + DisplayString: "date-order", + OnPress: onPress("date-order"), + }, + { + DisplayString: "author-date-order", + OnPress: onPress("author-date-order"), + }, + }, + }) + }, + }, + }, + }) +} + +func (self *LocalCommitsController) handleOpenCommitInBrowser(commit *models.Commit) error { + hostingServiceMgr := self.getHostingServiceMgr() + + url, err := hostingServiceMgr.GetCommitURL(commit.Sha) + if err != nil { + return self.c.Error(err) + } + + self.c.LogAction(self.c.Tr.Actions.OpenCommitInBrowser) + if err := self.os.OpenLink(url); err != nil { + return self.c.Error(err) + } + + return nil +} + +func (self *LocalCommitsController) checkSelected(callback func(*models.Commit) error) func() error { + return func() error { + commit := self.getSelectedLocalCommit() + if commit == nil { + return nil + } + + return callback(commit) + } +} + +func (self *LocalCommitsController) Context() types.Context { + return self.context +} diff --git a/pkg/gui/controllers/menu_controller.go b/pkg/gui/controllers/menu_controller.go new file mode 100644 index 000000000..329cab1f6 --- /dev/null +++ b/pkg/gui/controllers/menu_controller.go @@ -0,0 +1,70 @@ +package controllers + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type MenuController struct { + c *ControllerCommon + context types.IListContext + + getSelectedMenuItem func() *popup.MenuItem +} + +var _ types.IController = &MenuController{} + +func NewMenuController( + c *ControllerCommon, + context types.IListContext, + getSelectedMenuItem func() *popup.MenuItem, +) *MenuController { + return &MenuController{ + c: c, + context: context, + getSelectedMenuItem: getSelectedMenuItem, + } +} + +func (self *MenuController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { + bindings := []*types.Binding{ + { + Key: getKey(config.Universal.Select), + Handler: self.press, + }, + { + Key: getKey(config.Universal.Confirm), + Handler: self.press, + }, + { + Key: getKey(config.Universal.ConfirmAlt1), + Handler: self.press, + }, + { + Key: gocui.MouseLeft, + Handler: func() error { return self.context.HandleClick(self.press) }, + }, + } + + return append(bindings, self.context.Keybindings(getKey, config, guards)...) +} + +func (self *MenuController) press() error { + selectedItem := self.getSelectedMenuItem() + + if err := self.c.PopContext(); err != nil { + return err + } + + if err := selectedItem.OnPress(); err != nil { + return err + } + + return nil +} + +func (self *MenuController) Context() types.Context { + return self.context +} diff --git a/pkg/gui/controllers/remotes_controller.go b/pkg/gui/controllers/remotes_controller.go new file mode 100644 index 000000000..f37c8efef --- /dev/null +++ b/pkg/gui/controllers/remotes_controller.go @@ -0,0 +1,204 @@ +package controllers + +import ( + "sync" + + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +type RemotesController struct { + c *ControllerCommon + context types.IListContext + git *commands.GitCommand + + getSelectedRemote func() *models.Remote + setRemoteBranches func([]*models.RemoteBranch) + allContexts context.ContextTree + fetchMutex *sync.Mutex +} + +var _ types.IController = &RemotesController{} + +func NewRemotesController( + c *ControllerCommon, + context types.IListContext, + git *commands.GitCommand, + allContexts context.ContextTree, + getSelectedRemote func() *models.Remote, + setRemoteBranches func([]*models.RemoteBranch), + fetchMutex *sync.Mutex, +) *RemotesController { + return &RemotesController{ + c: c, + git: git, + allContexts: allContexts, + context: context, + getSelectedRemote: getSelectedRemote, + setRemoteBranches: setRemoteBranches, + fetchMutex: fetchMutex, + } +} + +func (self *RemotesController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { + bindings := []*types.Binding{ + { + Key: getKey(config.Universal.GoInto), + Handler: self.checkSelected(self.enter), + }, + { + Key: gocui.MouseLeft, + Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, + }, + { + Key: getKey(config.Branches.FetchRemote), + Handler: self.checkSelected(self.fetch), + Description: self.c.Tr.LcFetchRemote, + }, + { + Key: getKey(config.Universal.New), + Handler: self.add, + Description: self.c.Tr.LcAddNewRemote, + }, + { + Key: getKey(config.Universal.Remove), + Handler: self.checkSelected(self.remove), + Description: self.c.Tr.LcRemoveRemote, + }, + { + Key: getKey(config.Universal.Edit), + Handler: self.checkSelected(self.edit), + Description: self.c.Tr.LcEditRemote, + }, + } + + return append(bindings, self.context.Keybindings(getKey, config, guards)...) +} + +func (self *RemotesController) enter(remote *models.Remote) error { + // naive implementation: get the branches from the remote and render them to the list, change the context + self.setRemoteBranches(remote.Branches) + + newSelectedLine := 0 + if len(remote.Branches) == 0 { + newSelectedLine = -1 + } + self.allContexts.RemoteBranches.GetPanelState().SetSelectedLineIdx(newSelectedLine) + + return self.c.PushContext(self.allContexts.RemoteBranches) +} + +func (self *RemotesController) add() error { + return self.c.Prompt(popup.PromptOpts{ + Title: self.c.Tr.LcNewRemoteName, + HandleConfirm: func(remoteName string) error { + return self.c.Prompt(popup.PromptOpts{ + Title: self.c.Tr.LcNewRemoteUrl, + HandleConfirm: func(remoteUrl string) error { + self.c.LogAction(self.c.Tr.Actions.AddRemote) + if err := self.git.Remote.AddRemote(remoteName, remoteUrl); err != nil { + return err + } + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.REMOTES}}) + }, + }) + }, + }) +} + +func (self *RemotesController) remove(remote *models.Remote) error { + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.LcRemoveRemote, + Prompt: self.c.Tr.LcRemoveRemotePrompt + " '" + remote.Name + "'?", + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.RemoveRemote) + if err := self.git.Remote.RemoveRemote(remote.Name); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) + }, + }) +} + +func (self *RemotesController) edit(remote *models.Remote) error { + editNameMessage := utils.ResolvePlaceholderString( + self.c.Tr.LcEditRemoteName, + map[string]string{ + "remoteName": remote.Name, + }, + ) + + return self.c.Prompt(popup.PromptOpts{ + Title: editNameMessage, + InitialContent: remote.Name, + HandleConfirm: func(updatedRemoteName string) error { + if updatedRemoteName != remote.Name { + self.c.LogAction(self.c.Tr.Actions.UpdateRemote) + if err := self.git.Remote.RenameRemote(remote.Name, updatedRemoteName); err != nil { + return self.c.Error(err) + } + } + + editUrlMessage := utils.ResolvePlaceholderString( + self.c.Tr.LcEditRemoteUrl, + map[string]string{ + "remoteName": updatedRemoteName, + }, + ) + + urls := remote.Urls + url := "" + if len(urls) > 0 { + url = urls[0] + } + + return self.c.Prompt(popup.PromptOpts{ + Title: editUrlMessage, + InitialContent: url, + HandleConfirm: func(updatedRemoteUrl string) error { + self.c.LogAction(self.c.Tr.Actions.UpdateRemote) + if err := self.git.Remote.UpdateRemoteUrl(updatedRemoteName, updatedRemoteUrl); err != nil { + return self.c.Error(err) + } + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) + }, + }) + }, + }) +} + +func (self *RemotesController) fetch(remote *models.Remote) error { + return self.c.WithWaitingStatus(self.c.Tr.FetchingRemoteStatus, func() error { + self.fetchMutex.Lock() + defer self.fetchMutex.Unlock() + + err := self.git.Sync.FetchRemote(remote.Name) + if err != nil { + _ = self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) + }) +} + +func (self *RemotesController) checkSelected(callback func(*models.Remote) error) func() error { + return func() error { + file := self.getSelectedRemote() + if file == nil { + return nil + } + + return callback(file) + } +} + +func (self *RemotesController) Context() types.Context { + return self.context +} diff --git a/pkg/gui/controllers/submodules_controller.go b/pkg/gui/controllers/submodules_controller.go index e5eaf98a0..a380154ae 100644 --- a/pkg/gui/controllers/submodules_controller.go +++ b/pkg/gui/controllers/submodules_controller.go @@ -5,65 +5,57 @@ import ( "path/filepath" "strings" + "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" ) -// if Go let me do private struct embedding of structs with public fields (which it should) -// I would just do that. But alas. -type ControllerCommon struct { - *common.Common - IGuiCommon +type SubmodulesController struct { + c *ControllerCommon + context types.IListContext + git *commands.GitCommand + + enterSubmodule func(submodule *models.SubmoduleConfig) error + getSelectedSubmodule func() *models.SubmoduleConfig } -type SubmodulesController struct { - // I've said publicly that I'm against single-letter variable names but in this - // case I would actually prefer a _zero_ letter variable name in the form of - // struct embedding, but Go does not allow hiding public fields in an embedded struct - // to the client - c *ControllerCommon - enterSubmoduleFn func(submodule *models.SubmoduleConfig) error - getSelectedSubmodule func() *models.SubmoduleConfig - git *commands.GitCommand - submodules []*models.SubmoduleConfig -} +var _ types.IController = &SubmodulesController{} func NewSubmodulesController( c *ControllerCommon, - enterSubmoduleFn func(submodule *models.SubmoduleConfig) error, + context types.IListContext, git *commands.GitCommand, - submodules []*models.SubmoduleConfig, + enterSubmodule func(submodule *models.SubmoduleConfig) error, getSelectedSubmodule func() *models.SubmoduleConfig, ) *SubmodulesController { return &SubmodulesController{ c: c, - enterSubmoduleFn: enterSubmoduleFn, + context: context, git: git, - submodules: submodules, + enterSubmodule: enterSubmodule, getSelectedSubmodule: getSelectedSubmodule, } } -func (self *SubmodulesController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig) []*types.Binding { - return []*types.Binding{ +func (self *SubmodulesController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { + bindings := []*types.Binding{ { Key: getKey(config.Universal.GoInto), - Handler: self.forSubmodule(self.enter), + Handler: self.checkSelected(self.enter), Description: self.c.Tr.LcEnterSubmodule, }, { Key: getKey(config.Universal.Remove), - Handler: self.forSubmodule(self.remove), + Handler: self.checkSelected(self.remove), Description: self.c.Tr.LcRemoveSubmodule, }, { Key: getKey(config.Submodules.Update), - Handler: self.forSubmodule(self.update), + Handler: self.checkSelected(self.update), Description: self.c.Tr.LcSubmoduleUpdate, }, { @@ -73,12 +65,12 @@ func (self *SubmodulesController) Keybindings(getKey func(key string) interface{ }, { Key: getKey(config.Universal.Edit), - Handler: self.forSubmodule(self.editURL), + Handler: self.checkSelected(self.editURL), Description: self.c.Tr.LcEditSubmoduleUrl, }, { Key: getKey(config.Submodules.Init), - Handler: self.forSubmodule(self.init), + Handler: self.checkSelected(self.init), Description: self.c.Tr.LcInitSubmodule, }, { @@ -87,11 +79,17 @@ func (self *SubmodulesController) Keybindings(getKey func(key string) interface{ Description: self.c.Tr.LcViewBulkSubmoduleOptions, OpensMenu: true, }, + { + Key: gocui.MouseLeft, + Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, + }, } + + return append(bindings, self.context.Keybindings(getKey, config, guards)...) } func (self *SubmodulesController) enter(submodule *models.SubmoduleConfig) error { - return self.enterSubmoduleFn(submodule) + return self.enterSubmodule(submodule) } func (self *SubmodulesController) add() error { @@ -231,7 +229,7 @@ func (self *SubmodulesController) remove(submodule *models.SubmoduleConfig) erro }) } -func (self *SubmodulesController) forSubmodule(callback func(*models.SubmoduleConfig) error) func() error { +func (self *SubmodulesController) checkSelected(callback func(*models.SubmoduleConfig) error) func() error { return func() error { submodule := self.getSelectedSubmodule() if submodule == nil { @@ -241,3 +239,7 @@ func (self *SubmodulesController) forSubmodule(callback func(*models.SubmoduleCo return callback(submodule) } } + +func (self *SubmodulesController) Context() types.Context { + return self.context +} diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go new file mode 100644 index 000000000..a2fda53a1 --- /dev/null +++ b/pkg/gui/controllers/sync_controller.go @@ -0,0 +1,253 @@ +package controllers + +import ( + "fmt" + "strings" + + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type SyncController struct { + // I've said publicly that I'm against single-letter variable names but in this + // case I would actually prefer a _zero_ letter variable name in the form of + // struct embedding, but Go does not allow hiding public fields in an embedded struct + // to the client + c *ControllerCommon + git *commands.GitCommand + + getCheckedOutBranch func() *models.Branch + suggestionsHelper ISuggestionsHelper + getSuggestedRemote func() string + checkMergeOrRebase func(error) error +} + +var _ types.IController = &SyncController{} + +func NewSyncController( + c *ControllerCommon, + git *commands.GitCommand, + getCheckedOutBranch func() *models.Branch, + suggestionsHelper ISuggestionsHelper, + getSuggestedRemote func() string, + checkMergeOrRebase func(error) error, +) *SyncController { + return &SyncController{ + c: c, + git: git, + + getCheckedOutBranch: getCheckedOutBranch, + suggestionsHelper: suggestionsHelper, + getSuggestedRemote: getSuggestedRemote, + checkMergeOrRebase: checkMergeOrRebase, + } +} + +func (self *SyncController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { + bindings := []*types.Binding{ + { + Key: getKey(config.Universal.PushFiles), + Handler: guards.NoPopupPanel(self.HandlePush), + Description: self.c.Tr.LcPush, + }, + { + Key: getKey(config.Universal.PullFiles), + Handler: guards.NoPopupPanel(self.HandlePull), + Description: self.c.Tr.LcPull, + }, + } + + return bindings +} + +func (self *SyncController) Context() types.Context { + return nil +} + +func (self *SyncController) HandlePush() error { + return self.branchCheckedOut(self.push)() +} + +func (self *SyncController) HandlePull() error { + return self.branchCheckedOut(self.pull)() +} + +func (self *SyncController) branchCheckedOut(f func(*models.Branch) error) func() error { + return func() error { + currentBranch := self.getCheckedOutBranch() + if currentBranch == nil { + // need to wait for branches to refresh + return nil + } + + return f(currentBranch) + } +} + +func (self *SyncController) push(currentBranch *models.Branch) error { + // if we have pullables we'll ask if the user wants to force push + if currentBranch.IsTrackingRemote() { + opts := pushOpts{ + force: false, + upstreamRemote: currentBranch.UpstreamRemote, + upstreamBranch: currentBranch.UpstreamBranch, + } + if currentBranch.HasCommitsToPull() { + opts.force = true + return self.requestToForcePush(opts) + } else { + return self.pushAux(opts) + } + } else { + if self.git.Config.GetPushToCurrent() { + return self.pushAux(pushOpts{setUpstream: true}) + } else { + return self.promptForUpstream(currentBranch, func(upstream string) error { + var upstreamBranch, upstreamRemote string + split := strings.Split(upstream, " ") + if len(split) == 2 { + upstreamRemote = split[0] + upstreamBranch = split[1] + } else { + upstreamRemote = upstream + upstreamBranch = "" + } + + return self.pushAux(pushOpts{ + force: false, + upstreamRemote: upstreamRemote, + upstreamBranch: upstreamBranch, + setUpstream: true, + }) + }) + } + } +} + +func (self *SyncController) pull(currentBranch *models.Branch) error { + action := self.c.Tr.Actions.Pull + + // if we have no upstream branch we need to set that first + if !currentBranch.IsTrackingRemote() { + return self.promptForUpstream(currentBranch, func(upstream string) error { + var upstreamBranch, upstreamRemote string + split := strings.Split(upstream, " ") + if len(split) != 2 { + return self.c.ErrorMsg(self.c.Tr.InvalidUpstream) + } + + upstreamRemote = split[0] + upstreamBranch = split[1] + + if err := self.git.Branch.SetCurrentBranchUpstream(upstreamRemote, upstreamBranch); err != nil { + errorMessage := err.Error() + if strings.Contains(errorMessage, "does not exist") { + errorMessage = fmt.Sprintf("upstream branch %s not found.\nIf you expect it to exist, you should fetch (with 'f').\nOtherwise, you should push (with 'shift+P')", upstream) + } + return self.c.ErrorMsg(errorMessage) + } + return self.PullAux(PullFilesOptions{UpstreamRemote: upstreamRemote, UpstreamBranch: upstreamBranch, Action: action}) + }) + } + + return self.PullAux(PullFilesOptions{UpstreamRemote: currentBranch.UpstreamRemote, UpstreamBranch: currentBranch.UpstreamBranch, Action: action}) +} + +func (self *SyncController) promptForUpstream(currentBranch *models.Branch, onConfirm func(string) error) error { + suggestedRemote := self.getSuggestedRemote() + + return self.c.Prompt(popup.PromptOpts{ + Title: self.c.Tr.EnterUpstream, + InitialContent: suggestedRemote + " " + currentBranch.Name, + FindSuggestionsFunc: self.suggestionsHelper.GetRemoteBranchesSuggestionsFunc(" "), + HandleConfirm: onConfirm, + }) +} + +type PullFilesOptions struct { + UpstreamRemote string + UpstreamBranch string + FastForwardOnly bool + Action string +} + +func (self *SyncController) PullAux(opts PullFilesOptions) error { + return self.c.WithLoaderPanel(self.c.Tr.PullWait, func() error { + return self.pullWithLock(opts) + }) +} + +func (self *SyncController) pullWithLock(opts PullFilesOptions) error { + self.c.LogAction(opts.Action) + + err := self.git.Sync.Pull( + git_commands.PullOptions{ + RemoteName: opts.UpstreamRemote, + BranchName: opts.UpstreamBranch, + FastForwardOnly: opts.FastForwardOnly, + }, + ) + + return self.checkMergeOrRebase(err) +} + +type pushOpts struct { + force bool + upstreamRemote string + upstreamBranch string + setUpstream bool +} + +func (self *SyncController) pushAux(opts pushOpts) error { + return self.c.WithLoaderPanel(self.c.Tr.PushWait, func() error { + self.c.LogAction(self.c.Tr.Actions.Push) + err := self.git.Sync.Push(git_commands.PushOpts{ + Force: opts.force, + UpstreamRemote: opts.upstreamRemote, + UpstreamBranch: opts.upstreamBranch, + SetUpstream: opts.setUpstream, + }) + + if err != nil { + if !opts.force && strings.Contains(err.Error(), "Updates were rejected") { + forcePushDisabled := self.c.UserConfig.Git.DisableForcePushing + if forcePushDisabled { + _ = self.c.ErrorMsg(self.c.Tr.UpdatesRejectedAndForcePushDisabled) + return nil + } + _ = self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.ForcePush, + Prompt: self.c.Tr.ForcePushPrompt, + HandleConfirm: func() error { + newOpts := opts + newOpts.force = true + + return self.pushAux(newOpts) + }, + }) + return nil + } + _ = self.c.Error(err) + } + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + }) +} + +func (self *SyncController) requestToForcePush(opts pushOpts) error { + forcePushDisabled := self.c.UserConfig.Git.DisableForcePushing + if forcePushDisabled { + return self.c.ErrorMsg(self.c.Tr.ForcePushDisabled) + } + + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.ForcePush, + Prompt: self.c.Tr.ForcePushPrompt, + HandleConfirm: func() error { + return self.pushAux(opts) + }, + }) +} diff --git a/pkg/gui/controllers/tags_controller.go b/pkg/gui/controllers/tags_controller.go new file mode 100644 index 000000000..723a1074b --- /dev/null +++ b/pkg/gui/controllers/tags_controller.go @@ -0,0 +1,229 @@ +package controllers + +import ( + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +type TagsController struct { + c *ControllerCommon + context types.IListContext + git *commands.GitCommand + allContexts context.ContextTree + + refHelper IRefHelper + suggestionsHelper ISuggestionsHelper + + getSelectedTag func() *models.Tag + switchToSubCommitsContext func(string) error +} + +var _ types.IController = &TagsController{} + +func NewTagsController( + c *ControllerCommon, + context types.IListContext, + git *commands.GitCommand, + allContexts context.ContextTree, + refHelper IRefHelper, + suggestionsHelper ISuggestionsHelper, + + getSelectedTag func() *models.Tag, + switchToSubCommitsContext func(string) error, +) *TagsController { + return &TagsController{ + c: c, + context: context, + git: git, + allContexts: allContexts, + refHelper: refHelper, + suggestionsHelper: suggestionsHelper, + + getSelectedTag: getSelectedTag, + switchToSubCommitsContext: switchToSubCommitsContext, + } +} + +func (self *TagsController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { + bindings := []*types.Binding{ + { + Key: getKey(config.Universal.Select), + Handler: self.withSelectedTag(self.checkout), + Description: self.c.Tr.LcCheckout, + }, + { + Key: getKey(config.Universal.Remove), + Handler: self.withSelectedTag(self.delete), + Description: self.c.Tr.LcDeleteTag, + }, + { + Key: getKey(config.Branches.PushTag), + Handler: self.withSelectedTag(self.push), + Description: self.c.Tr.LcPushTag, + }, + { + Key: getKey(config.Universal.New), + Handler: self.create, + Description: self.c.Tr.LcCreateTag, + }, + { + Key: getKey(config.Commits.ViewResetOptions), + Handler: self.withSelectedTag(self.createResetMenu), + Description: self.c.Tr.LcViewResetOptions, + OpensMenu: true, + }, + { + Key: getKey(config.Universal.GoInto), + Handler: self.withSelectedTag(self.enter), + Description: self.c.Tr.LcViewCommits, + }, + } + + return append(bindings, self.context.Keybindings(getKey, config, guards)...) +} + +func (self *TagsController) checkout(tag *models.Tag) error { + self.c.LogAction(self.c.Tr.Actions.CheckoutTag) + if err := self.refHelper.CheckoutRef(tag.Name, types.CheckoutRefOptions{}); err != nil { + return err + } + return self.c.PushContext(self.allContexts.Branches) +} + +func (self *TagsController) enter(tag *models.Tag) error { + return self.switchToSubCommitsContext(tag.Name) +} + +func (self *TagsController) delete(tag *models.Tag) error { + prompt := utils.ResolvePlaceholderString( + self.c.Tr.DeleteTagPrompt, + map[string]string{ + "tagName": tag.Name, + }, + ) + + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.DeleteTagTitle, + Prompt: prompt, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.DeleteTag) + if err := self.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}}) + }, + }) +} + +func (self *TagsController) push(tag *models.Tag) error { + title := utils.ResolvePlaceholderString( + self.c.Tr.PushTagTitle, + map[string]string{ + "tagName": tag.Name, + }, + ) + + return self.c.Prompt(popup.PromptOpts{ + Title: title, + InitialContent: "origin", + FindSuggestionsFunc: self.suggestionsHelper.GetRemoteSuggestionsFunc(), + HandleConfirm: func(response string) error { + return self.c.WithWaitingStatus(self.c.Tr.PushingTagStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.PushTag) + err := self.git.Tag.Push(response, tag.Name) + if err != nil { + _ = self.c.Error(err) + } + + return nil + }) + }, + }) +} + +func (self *TagsController) createResetMenu(tag *models.Tag) error { + return self.refHelper.CreateGitResetMenu(tag.Name) +} + +func (self *TagsController) CreateTagMenu(commitSha string) error { + return self.c.Menu(popup.CreateMenuOptions{ + Title: self.c.Tr.TagMenuTitle, + Items: []*popup.MenuItem{ + { + DisplayString: self.c.Tr.LcLightweightTag, + OnPress: func() error { + return self.handleCreateLightweightTag(commitSha) + }, + }, + { + DisplayString: self.c.Tr.LcAnnotatedTag, + OnPress: func() error { + return self.handleCreateAnnotatedTag(commitSha) + }, + }, + }, + }) +} + +func (self *TagsController) afterTagCreate() error { + self.context.GetPanelState().SetSelectedLineIdx(0) + return self.c.Refresh(types.RefreshOptions{ + Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}, + }) +} + +func (self *TagsController) handleCreateAnnotatedTag(commitSha string) error { + return self.c.Prompt(popup.PromptOpts{ + Title: self.c.Tr.TagNameTitle, + HandleConfirm: func(tagName string) error { + return self.c.Prompt(popup.PromptOpts{ + Title: self.c.Tr.TagMessageTitle, + HandleConfirm: func(msg string) error { + self.c.LogAction(self.c.Tr.Actions.CreateAnnotatedTag) + if err := self.git.Tag.CreateAnnotated(tagName, commitSha, msg); err != nil { + return self.c.Error(err) + } + return self.afterTagCreate() + }, + }) + }, + }) +} + +func (self *TagsController) handleCreateLightweightTag(commitSha string) error { + return self.c.Prompt(popup.PromptOpts{ + Title: self.c.Tr.TagNameTitle, + HandleConfirm: func(tagName string) error { + self.c.LogAction(self.c.Tr.Actions.CreateLightweightTag) + if err := self.git.Tag.CreateLightweight(tagName, commitSha); err != nil { + return self.c.Error(err) + } + return self.afterTagCreate() + }, + }) +} + +func (self *TagsController) create() error { + // leaving commit SHA blank so that we're just creating the tag for the current commit + return self.CreateTagMenu("") +} + +func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func() error { + return func() error { + tag := self.getSelectedTag() + if tag == nil { + return nil + } + + return f(tag) + } +} + +func (self *TagsController) Context() types.Context { + return self.context +} diff --git a/pkg/gui/controllers/types.go b/pkg/gui/controllers/types.go index 75abc1704..21f774944 100644 --- a/pkg/gui/controllers/types.go +++ b/pkg/gui/controllers/types.go @@ -1,6 +1,9 @@ package controllers import ( + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -8,6 +11,54 @@ import ( type IGuiCommon interface { popup.IPopupHandler - LogAction(string) + LogAction(action string) + LogCommand(cmdStr string, isCommandLine bool) + // we call this when we want to refetch some models and render the result. Internally calls PostRefreshUpdate Refresh(types.RefreshOptions) error + // we call this when we've changed something in the view model but not the actual model, + // e.g. expanding or collapsing a folder in a file view. Calling 'Refresh' in this + // case would be overkill, although refresh will internally call 'PostRefreshUpdate' + PostRefreshUpdate(types.Context) error + RunSubprocessAndRefresh(oscommands.ICmdObj) error + PushContext(context types.Context, opts ...types.OnFocusOpts) error + PopContext() error + + GetAppState() *config.AppState + SaveAppState() error +} + +type IRefHelper interface { + CheckoutRef(ref string, options types.CheckoutRefOptions) error + CreateGitResetMenu(ref string) error + ResetToRef(ref string, strength string, envVars []string) error +} + +type ISuggestionsHelper interface { + GetRemoteSuggestionsFunc() func(string) []*types.Suggestion + GetBranchNameSuggestionsFunc() func(string) []*types.Suggestion + GetFilePathSuggestionsFunc() func(string) []*types.Suggestion + GetRemoteBranchesSuggestionsFunc(separator string) func(string) []*types.Suggestion + GetRefsSuggestionsFunc() func(string) []*types.Suggestion + GetCustomCommandsHistorySuggestionsFunc() func(string) []*types.Suggestion +} + +type IFileHelper interface { + EditFile(filename string) error + EditFileAtLine(filename string, lineNumber int) error + OpenFile(filename string) error +} + +type IWorkingTreeHelper interface { + AnyStagedFiles() bool + AnyTrackedFiles() bool + IsWorkingTreeDirty() bool + FileForSubmodule(submodule *models.SubmoduleConfig) *models.File +} + +// all fields mandatory (except `CanRebase` because it's boolean) +type SwitchToCommitFilesContextOpts struct { + RefName string + CanRebase bool + Context types.Context + WindowName string } diff --git a/pkg/gui/undoing.go b/pkg/gui/controllers/undo_controller.go similarity index 56% rename from pkg/gui/undoing.go rename to pkg/gui/controllers/undo_controller.go index e61950700..984b8e1a6 100644 --- a/pkg/gui/undoing.go +++ b/pkg/gui/controllers/undo_controller.go @@ -1,7 +1,10 @@ -package gui +package controllers import ( + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" + "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -17,6 +20,36 @@ import ( // the reflog will read UUCBA, and when I read the first two undos, I know to skip the following // two user actions, meaning we end up undoing reflog entry C. Redoing works in a similar way. +type UndoController struct { + c *ControllerCommon + git *commands.GitCommand + + refHelper IRefHelper + workingTreeHelper IWorkingTreeHelper + + getFilteredReflogCommits func() []*models.Commit +} + +var _ types.IController = &UndoController{} + +func NewUndoController( + c *ControllerCommon, + git *commands.GitCommand, + refHelper IRefHelper, + workingTreeHelper IWorkingTreeHelper, + + getFilteredReflogCommits func() []*models.Commit, +) *UndoController { + return &UndoController{ + c: c, + git: git, + refHelper: refHelper, + workingTreeHelper: workingTreeHelper, + + getFilteredReflogCommits: getFilteredReflogCommits, + } +} + type ReflogActionKind int const ( @@ -32,15 +65,113 @@ type reflogAction struct { to string } +func (self *UndoController) Keybindings( + getKey func(key string) interface{}, + config config.KeybindingConfig, + guards types.KeybindingGuards, +) []*types.Binding { + bindings := []*types.Binding{ + { + Key: getKey(config.Universal.Undo), + Handler: self.reflogUndo, + Description: self.c.Tr.LcUndoReflog, + }, + { + Key: getKey(config.Universal.Redo), + Handler: self.reflogRedo, + Description: self.c.Tr.LcRedoReflog, + }, + } + + return bindings +} + +func (self *UndoController) Context() types.Context { + return nil +} + +func (self *UndoController) reflogUndo() error { + undoEnvVars := []string{"GIT_REFLOG_ACTION=[lazygit undo]"} + undoingStatus := self.c.Tr.UndoingStatus + + if self.git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING { + return self.c.ErrorMsg(self.c.Tr.LcCantUndoWhileRebasing) + } + + return self.parseReflogForActions(func(counter int, action reflogAction) (bool, error) { + if counter != 0 { + return false, nil + } + + switch action.kind { + case COMMIT, REBASE: + self.c.LogAction(self.c.Tr.Actions.Undo) + return true, self.hardResetWithAutoStash(action.from, hardResetOptions{ + EnvVars: undoEnvVars, + WaitingStatus: undoingStatus, + }) + case CHECKOUT: + self.c.LogAction(self.c.Tr.Actions.Undo) + return true, self.refHelper.CheckoutRef(action.from, types.CheckoutRefOptions{ + EnvVars: undoEnvVars, + WaitingStatus: undoingStatus, + }) + case CURRENT_REBASE: + // do nothing + } + + self.c.Log.Error("didn't match on the user action when trying to undo") + return true, nil + }) +} + +func (self *UndoController) reflogRedo() error { + redoEnvVars := []string{"GIT_REFLOG_ACTION=[lazygit redo]"} + redoingStatus := self.c.Tr.RedoingStatus + + if self.git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING { + return self.c.ErrorMsg(self.c.Tr.LcCantRedoWhileRebasing) + } + + return self.parseReflogForActions(func(counter int, action reflogAction) (bool, error) { + // if we're redoing and the counter is zero, we just return + if counter == 0 { + return true, nil + } else if counter > 1 { + return false, nil + } + + switch action.kind { + case COMMIT, REBASE: + self.c.LogAction(self.c.Tr.Actions.Redo) + return true, self.hardResetWithAutoStash(action.to, hardResetOptions{ + EnvVars: redoEnvVars, + WaitingStatus: redoingStatus, + }) + case CHECKOUT: + self.c.LogAction(self.c.Tr.Actions.Redo) + return true, self.refHelper.CheckoutRef(action.to, types.CheckoutRefOptions{ + EnvVars: redoEnvVars, + WaitingStatus: redoingStatus, + }) + case CURRENT_REBASE: + // do nothing + } + + self.c.Log.Error("didn't match on the user action when trying to redo") + return true, nil + }) +} + // Here we're going through the reflog and maintaining a counter that represents how many // undos/redos/user actions we've seen. when we hit a user action we call the callback specifying // what the counter is up to and the nature of the action. // If we find ourselves mid-rebase, we just return because undo/redo mid rebase // requires knowledge of previous TODO file states, which you can't just get from the reflog. // Though we might support this later, hence the use of the CURRENT_REBASE action kind. -func (gui *Gui) parseReflogForActions(onUserAction func(counter int, action reflogAction) (bool, error)) error { +func (self *UndoController) parseReflogForActions(onUserAction func(counter int, action reflogAction) (bool, error)) error { counter := 0 - reflogCommits := gui.State.FilteredReflogCommits + reflogCommits := self.getFilteredReflogCommits() rebaseFinishCommitSha := "" var action *reflogAction for reflogCommitIdx, reflogCommit := range reflogCommits { @@ -86,115 +217,42 @@ func (gui *Gui) parseReflogForActions(onUserAction func(counter int, action refl return nil } -func (gui *Gui) reflogUndo() error { - undoEnvVars := []string{"GIT_REFLOG_ACTION=[lazygit undo]"} - undoingStatus := gui.Tr.UndoingStatus - - if gui.Git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING { - return gui.PopupHandler.ErrorMsg(gui.Tr.LcCantUndoWhileRebasing) - } - - return gui.parseReflogForActions(func(counter int, action reflogAction) (bool, error) { - if counter != 0 { - return false, nil - } - - switch action.kind { - case COMMIT, REBASE: - gui.logAction(gui.Tr.Actions.Undo) - return true, gui.handleHardResetWithAutoStash(action.from, handleHardResetWithAutoStashOptions{ - EnvVars: undoEnvVars, - WaitingStatus: undoingStatus, - }) - case CHECKOUT: - gui.logAction(gui.Tr.Actions.Undo) - return true, gui.handleCheckoutRef(action.from, handleCheckoutRefOptions{ - EnvVars: undoEnvVars, - WaitingStatus: undoingStatus, - }) - case CURRENT_REBASE: - // do nothing - } - - gui.Log.Error("didn't match on the user action when trying to undo") - return true, nil - }) -} - -func (gui *Gui) reflogRedo() error { - redoEnvVars := []string{"GIT_REFLOG_ACTION=[lazygit redo]"} - redoingStatus := gui.Tr.RedoingStatus - - if gui.Git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING { - return gui.PopupHandler.ErrorMsg(gui.Tr.LcCantRedoWhileRebasing) - } - - return gui.parseReflogForActions(func(counter int, action reflogAction) (bool, error) { - // if we're redoing and the counter is zero, we just return - if counter == 0 { - return true, nil - } else if counter > 1 { - return false, nil - } - - switch action.kind { - case COMMIT, REBASE: - gui.logAction(gui.Tr.Actions.Redo) - return true, gui.handleHardResetWithAutoStash(action.to, handleHardResetWithAutoStashOptions{ - EnvVars: redoEnvVars, - WaitingStatus: redoingStatus, - }) - case CHECKOUT: - gui.logAction(gui.Tr.Actions.Redo) - return true, gui.handleCheckoutRef(action.to, handleCheckoutRefOptions{ - EnvVars: redoEnvVars, - WaitingStatus: redoingStatus, - }) - case CURRENT_REBASE: - // do nothing - } - - gui.Log.Error("didn't match on the user action when trying to redo") - return true, nil - }) -} - -type handleHardResetWithAutoStashOptions struct { +type hardResetOptions struct { WaitingStatus string EnvVars []string } -// only to be used in the undo flow for now -func (gui *Gui) handleHardResetWithAutoStash(commitSha string, options handleHardResetWithAutoStashOptions) error { +// only to be used in the undo flow for now (does an autostash) +func (self *UndoController) hardResetWithAutoStash(commitSha string, options hardResetOptions) error { reset := func() error { - if err := gui.resetToRef(commitSha, "hard", options.EnvVars); err != nil { - return gui.PopupHandler.Error(err) + if err := self.refHelper.ResetToRef(commitSha, "hard", options.EnvVars); err != nil { + return self.c.Error(err) } return nil } // if we have any modified tracked files we need to ask the user if they want us to stash for them - dirtyWorkingTree := len(gui.trackedFiles()) > 0 || len(gui.stagedFiles()) > 0 + dirtyWorkingTree := self.workingTreeHelper.IsWorkingTreeDirty() if dirtyWorkingTree { // offer to autostash changes - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.AutoStashTitle, - Prompt: gui.Tr.AutoStashPrompt, + return self.c.Ask(popup.AskOpts{ + Title: self.c.Tr.AutoStashTitle, + Prompt: self.c.Tr.AutoStashPrompt, HandleConfirm: func() error { - return gui.PopupHandler.WithWaitingStatus(options.WaitingStatus, func() error { - if err := gui.Git.Stash.Save(gui.Tr.StashPrefix + commitSha); err != nil { - return gui.PopupHandler.Error(err) + return self.c.WithWaitingStatus(options.WaitingStatus, func() error { + if err := self.git.Stash.Save(self.c.Tr.StashPrefix + commitSha); err != nil { + return self.c.Error(err) } if err := reset(); err != nil { return err } - err := gui.Git.Stash.Pop(0) - if err := gui.refreshSidePanels(types.RefreshOptions{}); err != nil { + err := self.git.Stash.Pop(0) + if err := self.c.Refresh(types.RefreshOptions{}); err != nil { return err } if err != nil { - return gui.PopupHandler.Error(err) + return self.c.Error(err) } return nil }) @@ -202,7 +260,7 @@ func (gui *Gui) handleHardResetWithAutoStash(commitSha string, options handleHar }) } - return gui.PopupHandler.WithWaitingStatus(options.WaitingStatus, func() error { + return self.c.WithWaitingStatus(options.WaitingStatus, func() error { return reset() }) } diff --git a/pkg/gui/credentials_panel.go b/pkg/gui/credentials_panel.go index b7981338d..796aa70c6 100644 --- a/pkg/gui/credentials_panel.go +++ b/pkg/gui/credentials_panel.go @@ -17,21 +17,20 @@ func (gui *Gui) promptUserForCredential(passOrUname oscommands.CredentialType) s credentialsView := gui.Views.Credentials switch passOrUname { case oscommands.Username: - credentialsView.Title = gui.Tr.CredentialsUsername + credentialsView.Title = gui.c.Tr.CredentialsUsername credentialsView.Mask = 0 case oscommands.Password: - credentialsView.Title = gui.Tr.CredentialsPassword + credentialsView.Title = gui.c.Tr.CredentialsPassword credentialsView.Mask = '*' case oscommands.Passphrase: - credentialsView.Title = gui.Tr.CredentialsPassphrase + credentialsView.Title = gui.c.Tr.CredentialsPassphrase credentialsView.Mask = '*' } - if err := gui.pushContext(gui.State.Contexts.Credentials); err != nil { + if err := gui.c.PushContext(gui.State.Contexts.Credentials); err != nil { return err } - gui.RenderCommitLength() return nil }) @@ -49,7 +48,7 @@ func (gui *Gui) handleSubmitCredential() error { return err } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) } func (gui *Gui) handleCloseCredentialsView() error { @@ -59,10 +58,10 @@ func (gui *Gui) handleCloseCredentialsView() error { } func (gui *Gui) handleAskFocused() error { - keybindingConfig := gui.UserConfig.Keybinding + keybindingConfig := gui.c.UserConfig.Keybinding message := utils.ResolvePlaceholderString( - gui.Tr.CloseConfirm, + gui.c.Tr.CloseConfirm, map[string]string{ "keyBindClose": gui.getKeyDisplay(keybindingConfig.Universal.Return), "keyBindConfirm": gui.getKeyDisplay(keybindingConfig.Universal.Confirm), diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index 44548ef72..3470797a3 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -54,7 +54,7 @@ func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (s SelectedCommitFile: gui.getSelectedCommitFile(), SelectedCommitFilePath: gui.getSelectedCommitFilePath(), SelectedSubCommit: gui.getSelectedSubCommit(), - CheckedOutBranch: gui.currentBranch(), + CheckedOutBranch: gui.getCheckedOutBranch(), PromptResponses: promptResponses, } @@ -64,15 +64,15 @@ func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (s func (gui *Gui) inputPrompt(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error { title, err := gui.resolveTemplate(prompt.Title, promptResponses) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } initialValue, err := gui.resolveTemplate(prompt.InitialValue, promptResponses) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } - return gui.PopupHandler.Prompt(popup.PromptOpts{ + return gui.c.Prompt(popup.PromptOpts{ Title: title, InitialContent: initialValue, HandleConfirm: func(str string) error { @@ -95,17 +95,17 @@ func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses [] } name, err := gui.resolveTemplate(nameTemplate, promptResponses) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } description, err := gui.resolveTemplate(option.Description, promptResponses) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } value, err := gui.resolveTemplate(option.Value, promptResponses) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } menuItems[i] = &popup.MenuItem{ @@ -119,30 +119,30 @@ func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses [] title, err := gui.resolveTemplate(prompt.Title, promptResponses) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } - return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: title, Items: menuItems}) + return gui.c.Menu(popup.CreateMenuOptions{Title: title, Items: menuItems}) } func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, labelFormat string) ([]commandMenuEntry, error) { reg, err := regexp.Compile(filter) if err != nil { - return nil, gui.PopupHandler.Error(errors.New("unable to parse filter regex, error: " + err.Error())) + return nil, gui.c.Error(errors.New("unable to parse filter regex, error: " + err.Error())) } buff := bytes.NewBuffer(nil) valueTemp, err := template.New("format").Parse(valueFormat) if err != nil { - return nil, gui.PopupHandler.Error(errors.New("unable to parse value format, error: " + err.Error())) + return nil, gui.c.Error(errors.New("unable to parse value format, error: " + err.Error())) } colorFuncMap := style.TemplateFuncMapAddColors(template.FuncMap{}) descTemp, err := template.New("format").Funcs(colorFuncMap).Parse(labelFormat) if err != nil { - return nil, gui.PopupHandler.Error(errors.New("unable to parse label format, error: " + err.Error())) + return nil, gui.c.Error(errors.New("unable to parse label format, error: " + err.Error())) } candidates := []commandMenuEntry{} @@ -167,7 +167,7 @@ func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, label err = valueTemp.Execute(buff, tmplData) if err != nil { - return candidates, gui.PopupHandler.Error(err) + return candidates, gui.c.Error(err) } entry := commandMenuEntry{ value: strings.TrimSpace(buff.String()), @@ -177,7 +177,7 @@ func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, label buff.Reset() err = descTemp.Execute(buff, tmplData) if err != nil { - return candidates, gui.PopupHandler.Error(err) + return candidates, gui.c.Error(err) } entry.label = strings.TrimSpace(buff.String()) } else { @@ -195,25 +195,25 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR // Collect cmd to run from config cmdStr, err := gui.resolveTemplate(prompt.Command, promptResponses) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } // Collect Filter regexp filter, err := gui.resolveTemplate(prompt.Filter, promptResponses) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } // Run and save output - message, err := gui.Git.Custom.RunWithOutput(cmdStr) + message, err := gui.git.Custom.RunWithOutput(cmdStr) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } // Need to make a menu out of what the cmd has displayed candidates, err := gui.GenerateMenuCandidates(message, filter, prompt.ValueFormat, prompt.LabelFormat) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } menuItems := make([]*popup.MenuItem, len(candidates)) @@ -230,10 +230,10 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR title, err := gui.resolveTemplate(prompt.Title, promptResponses) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } - return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: title, Items: menuItems}) + return gui.c.Menu(popup.CreateMenuOptions{Title: title, Items: menuItems}) } func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand) func() error { @@ -243,7 +243,7 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand f := func() error { cmdStr, err := gui.resolveTemplate(customCommand.Command, promptResponses) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } if customCommand.Subprocess { @@ -252,19 +252,19 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand loadingText := customCommand.LoadingText if loadingText == "" { - loadingText = gui.Tr.LcRunningCustomCommandStatus + loadingText = gui.c.Tr.LcRunningCustomCommandStatus } - return gui.PopupHandler.WithWaitingStatus(loadingText, func() error { - gui.logAction(gui.Tr.Actions.CustomCommand) + return gui.c.WithWaitingStatus(loadingText, func() error { + gui.c.LogAction(gui.c.Tr.Actions.CustomCommand) cmdObj := gui.OSCommand.Cmd.NewShell(cmdStr) if customCommand.Stream { cmdObj.StreamOutput() } err := cmdObj.Run() if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{}) + return gui.c.Refresh(types.RefreshOptions{}) }) } @@ -293,7 +293,7 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand return gui.menuPromptFromCommand(prompt, promptResponses, idx, wrappedF) } default: - return gui.PopupHandler.ErrorMsg("custom command prompt must have a type of 'input', 'menu' or 'menuFromCommand'") + return gui.c.ErrorMsg("custom command prompt must have a type of 'input', 'menu' or 'menuFromCommand'") } } @@ -304,7 +304,7 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand func (gui *Gui) GetCustomCommandKeybindings() []*types.Binding { bindings := []*types.Binding{} - customCommands := gui.UserConfig.CustomCommands + customCommands := gui.c.UserConfig.CustomCommands for _, customCommand := range customCommands { var viewName string @@ -315,11 +315,11 @@ func (gui *Gui) GetCustomCommandKeybindings() []*types.Binding { case "": log.Fatalf("Error parsing custom command keybindings: context not provided (use context: 'global' for the global context). Key: %s, Command: %s", customCommand.Key, customCommand.Command) default: - context, ok := gui.contextForContextKey(ContextKey(customCommand.Context)) + context, ok := gui.contextForContextKey(types.ContextKey(customCommand.Context)) // stupid golang making me build an array of strings for this. - allContextKeyStrings := make([]string, len(allContextKeys)) - for i := range allContextKeys { - allContextKeyStrings[i] = string(allContextKeys[i]) + allContextKeyStrings := make([]string, len(AllContextKeys)) + for i := range AllContextKeys { + allContextKeyStrings[i] = string(AllContextKeys[i]) } if !ok { log.Fatalf("Error when setting custom command keybindings: unknown context: %s. Key: %s, Command: %s.\nPermitted contexts: %s", customCommand.Context, customCommand.Key, customCommand.Command, strings.Join(allContextKeyStrings, ", ")) diff --git a/pkg/gui/diff_context_size.go b/pkg/gui/diff_context_size.go index e5ea340a6..5caefd032 100644 --- a/pkg/gui/diff_context_size.go +++ b/pkg/gui/diff_context_size.go @@ -2,9 +2,11 @@ package gui import ( "errors" + + "github.com/jesseduffield/lazygit/pkg/gui/types" ) -var CONTEXT_KEYS_SHOWING_DIFFS = []ContextKey{ +var CONTEXT_KEYS_SHOWING_DIFFS = []types.ContextKey{ FILES_CONTEXT_KEY, COMMIT_FILES_CONTEXT_KEY, STASH_CONTEXT_KEY, @@ -28,10 +30,10 @@ func isShowingDiff(gui *Gui) bool { func (gui *Gui) IncreaseContextInDiffView() error { if isShowingDiff(gui) { if err := gui.CheckCanChangeContext(); err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } - gui.UserConfig.Git.DiffContextSize = gui.UserConfig.Git.DiffContextSize + 1 + gui.c.UserConfig.Git.DiffContextSize = gui.c.UserConfig.Git.DiffContextSize + 1 return gui.handleDiffContextSizeChange() } @@ -39,14 +41,14 @@ func (gui *Gui) IncreaseContextInDiffView() error { } func (gui *Gui) DecreaseContextInDiffView() error { - old_size := gui.UserConfig.Git.DiffContextSize + old_size := gui.c.UserConfig.Git.DiffContextSize if isShowingDiff(gui) && old_size > 1 { if err := gui.CheckCanChangeContext(); err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } - gui.UserConfig.Git.DiffContextSize = old_size - 1 + gui.c.UserConfig.Git.DiffContextSize = old_size - 1 return gui.handleDiffContextSizeChange() } @@ -67,8 +69,8 @@ func (gui *Gui) handleDiffContextSizeChange() error { } func (gui *Gui) CheckCanChangeContext() error { - if gui.Git.Patch.PatchManager.Active() { - return errors.New(gui.Tr.CantChangeContextSizeError) + if gui.git.Patch.PatchManager.Active() { + return errors.New(gui.c.Tr.CantChangeContextSizeError) } return nil diff --git a/pkg/gui/diff_context_size_test.go b/pkg/gui/diff_context_size_test.go index 4f53cd3ff..4515118bf 100644 --- a/pkg/gui/diff_context_size_test.go +++ b/pkg/gui/diff_context_size_test.go @@ -29,7 +29,7 @@ func setupGuiForTest(gui *Gui) { gui.Views.Main, _ = gui.prepareView("main") gui.Views.Secondary, _ = gui.prepareView("secondary") gui.Views.Options, _ = gui.prepareView("options") - gui.Git.Patch.PatchManager = &patch.PatchManager{} + gui.git.Patch.PatchManager = &patch.PatchManager{} _, _ = gui.refreshLineByLinePanel(diffForTest, "", false, 11) } @@ -48,12 +48,12 @@ func TestIncreasesContextInDiffViewByOneInContextWithDiff(t *testing.T) { gui := NewDummyGui() context := c(gui) setupGuiForTest(gui) - gui.UserConfig.Git.DiffContextSize = 1 - _ = gui.pushContext(context) + gui.c.UserConfig.Git.DiffContextSize = 1 + _ = gui.c.PushContext(context) _ = gui.IncreaseContextInDiffView() - assert.Equal(t, 2, gui.UserConfig.Git.DiffContextSize, string(context.GetKey())) + assert.Equal(t, 2, gui.c.UserConfig.Git.DiffContextSize, string(context.GetKey())) } } @@ -76,12 +76,12 @@ func TestDoesntIncreaseContextInDiffViewInContextWithoutDiff(t *testing.T) { gui := NewDummyGui() context := c(gui) setupGuiForTest(gui) - gui.UserConfig.Git.DiffContextSize = 1 - _ = gui.pushContext(context) + gui.c.UserConfig.Git.DiffContextSize = 1 + _ = gui.c.PushContext(context) _ = gui.IncreaseContextInDiffView() - assert.Equal(t, 1, gui.UserConfig.Git.DiffContextSize, string(context.GetKey())) + assert.Equal(t, 1, gui.c.UserConfig.Git.DiffContextSize, string(context.GetKey())) } } @@ -100,12 +100,12 @@ func TestDecreasesContextInDiffViewByOneInContextWithDiff(t *testing.T) { gui := NewDummyGui() context := c(gui) setupGuiForTest(gui) - gui.UserConfig.Git.DiffContextSize = 2 - _ = gui.pushContext(context) + gui.c.UserConfig.Git.DiffContextSize = 2 + _ = gui.c.PushContext(context) _ = gui.DecreaseContextInDiffView() - assert.Equal(t, 1, gui.UserConfig.Git.DiffContextSize, string(context.GetKey())) + assert.Equal(t, 1, gui.c.UserConfig.Git.DiffContextSize, string(context.GetKey())) } } @@ -128,26 +128,26 @@ func TestDoesntDecreaseContextInDiffViewInContextWithoutDiff(t *testing.T) { gui := NewDummyGui() context := c(gui) setupGuiForTest(gui) - gui.UserConfig.Git.DiffContextSize = 2 - _ = gui.pushContext(context) + gui.c.UserConfig.Git.DiffContextSize = 2 + _ = gui.c.PushContext(context) _ = gui.DecreaseContextInDiffView() - assert.Equal(t, 2, gui.UserConfig.Git.DiffContextSize, string(context.GetKey())) + assert.Equal(t, 2, gui.c.UserConfig.Git.DiffContextSize, string(context.GetKey())) } } func TestDoesntIncreaseContextInDiffViewInContextWhenInPatchBuildingMode(t *testing.T) { gui := NewDummyGui() setupGuiForTest(gui) - gui.UserConfig.Git.DiffContextSize = 2 - _ = gui.pushContext(gui.State.Contexts.CommitFiles) - gui.Git.Patch.PatchManager.Start("from", "to", false, false) + gui.c.UserConfig.Git.DiffContextSize = 2 + _ = gui.c.PushContext(gui.State.Contexts.CommitFiles) + gui.git.Patch.PatchManager.Start("from", "to", false, false) errorCount := 0 gui.PopupHandler = &popup.TestPopupHandler{ OnErrorMsg: func(message string) error { - assert.Equal(t, gui.Tr.CantChangeContextSizeError, message) + assert.Equal(t, gui.c.Tr.CantChangeContextSizeError, message) errorCount += 1 return nil }, @@ -156,20 +156,20 @@ func TestDoesntIncreaseContextInDiffViewInContextWhenInPatchBuildingMode(t *test _ = gui.IncreaseContextInDiffView() assert.Equal(t, 1, errorCount) - assert.Equal(t, 2, gui.UserConfig.Git.DiffContextSize) + assert.Equal(t, 2, gui.c.UserConfig.Git.DiffContextSize) } func TestDoesntDecreaseContextInDiffViewInContextWhenInPatchBuildingMode(t *testing.T) { gui := NewDummyGui() setupGuiForTest(gui) - gui.UserConfig.Git.DiffContextSize = 2 - _ = gui.pushContext(gui.State.Contexts.CommitFiles) - gui.Git.Patch.PatchManager.Start("from", "to", false, false) + gui.c.UserConfig.Git.DiffContextSize = 2 + _ = gui.c.PushContext(gui.State.Contexts.CommitFiles) + gui.git.Patch.PatchManager.Start("from", "to", false, false) errorCount := 0 gui.PopupHandler = &popup.TestPopupHandler{ OnErrorMsg: func(message string) error { - assert.Equal(t, gui.Tr.CantChangeContextSizeError, message) + assert.Equal(t, gui.c.Tr.CantChangeContextSizeError, message) errorCount += 1 return nil }, @@ -177,15 +177,15 @@ func TestDoesntDecreaseContextInDiffViewInContextWhenInPatchBuildingMode(t *test _ = gui.DecreaseContextInDiffView() - assert.Equal(t, 2, gui.UserConfig.Git.DiffContextSize) + assert.Equal(t, 2, gui.c.UserConfig.Git.DiffContextSize) } func TestDecreasesContextInDiffViewNoFurtherThanOne(t *testing.T) { gui := NewDummyGui() setupGuiForTest(gui) - gui.UserConfig.Git.DiffContextSize = 1 + gui.c.UserConfig.Git.DiffContextSize = 1 _ = gui.DecreaseContextInDiffView() - assert.Equal(t, 1, gui.UserConfig.Git.DiffContextSize) + assert.Equal(t, 1, gui.c.UserConfig.Git.DiffContextSize) } diff --git a/pkg/gui/diffing.go b/pkg/gui/diffing.go index 232f9130b..2408cc79f 100644 --- a/pkg/gui/diffing.go +++ b/pkg/gui/diffing.go @@ -11,7 +11,7 @@ import ( func (gui *Gui) exitDiffMode() error { gui.State.Modes.Diffing = diffing.New() - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) } func (gui *Gui) renderDiff() error { @@ -112,11 +112,11 @@ func (gui *Gui) handleCreateDiffingMenuPanel() error { name := name menuItems = append(menuItems, []*popup.MenuItem{ { - DisplayString: fmt.Sprintf("%s %s", gui.Tr.LcDiff, name), + DisplayString: fmt.Sprintf("%s %s", gui.c.Tr.LcDiff, name), OnPress: func() error { gui.State.Modes.Diffing.Ref = name // can scope this down based on current view but too lazy right now - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) }, }, }...) @@ -124,14 +124,14 @@ func (gui *Gui) handleCreateDiffingMenuPanel() error { menuItems = append(menuItems, []*popup.MenuItem{ { - DisplayString: gui.Tr.LcEnterRefToDiff, + DisplayString: gui.c.Tr.LcEnterRefToDiff, OnPress: func() error { - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: gui.Tr.LcEnteRefName, - FindSuggestionsFunc: gui.getRefsSuggestionsFunc(), + return gui.c.Prompt(popup.PromptOpts{ + Title: gui.c.Tr.LcEnteRefName, + FindSuggestionsFunc: gui.suggestionsHelper.GetRefsSuggestionsFunc(), HandleConfirm: func(response string) error { gui.State.Modes.Diffing.Ref = strings.TrimSpace(response) - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) }, }) }, @@ -141,21 +141,21 @@ func (gui *Gui) handleCreateDiffingMenuPanel() error { if gui.State.Modes.Diffing.Active() { menuItems = append(menuItems, []*popup.MenuItem{ { - DisplayString: gui.Tr.LcSwapDiff, + DisplayString: gui.c.Tr.LcSwapDiff, OnPress: func() error { gui.State.Modes.Diffing.Reverse = !gui.State.Modes.Diffing.Reverse - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) }, }, { - DisplayString: gui.Tr.LcExitDiffMode, + DisplayString: gui.c.Tr.LcExitDiffMode, OnPress: func() error { gui.State.Modes.Diffing = diffing.New() - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) }, }, }...) } - return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: gui.Tr.DiffingMenuTitle, Items: menuItems}) + return gui.c.Menu(popup.CreateMenuOptions{Title: gui.c.Tr.DiffingMenuTitle, Items: menuItems}) } diff --git a/pkg/gui/discard_changes_menu_panel.go b/pkg/gui/discard_changes_menu_panel.go index 7624730e0..473a4611f 100644 --- a/pkg/gui/discard_changes_menu_panel.go +++ b/pkg/gui/discard_changes_menu_panel.go @@ -15,27 +15,27 @@ func (gui *Gui) handleCreateDiscardMenu() error { if node.File == nil { menuItems = []*popup.MenuItem{ { - DisplayString: gui.Tr.LcDiscardAllChanges, + DisplayString: gui.c.Tr.LcDiscardAllChanges, OnPress: func() error { - gui.logAction(gui.Tr.Actions.DiscardAllChangesInDirectory) - if err := gui.Git.WorkingTree.DiscardAllDirChanges(node); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.DiscardAllChangesInDirectory) + if err := gui.git.WorkingTree.DiscardAllDirChanges(node); err != nil { + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, } if node.GetHasStagedChanges() && node.GetHasUnstagedChanges() { menuItems = append(menuItems, &popup.MenuItem{ - DisplayString: gui.Tr.LcDiscardUnstagedChanges, + DisplayString: gui.c.Tr.LcDiscardUnstagedChanges, OnPress: func() error { - gui.logAction(gui.Tr.Actions.DiscardUnstagedChangesInDirectory) - if err := gui.Git.WorkingTree.DiscardUnstagedDirChanges(node); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.DiscardUnstagedChangesInDirectory) + if err := gui.git.WorkingTree.DiscardUnstagedDirChanges(node); err != nil { + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }) } @@ -48,41 +48,41 @@ func (gui *Gui) handleCreateDiscardMenu() error { menuItems = []*popup.MenuItem{ { - DisplayString: gui.Tr.LcSubmoduleStashAndReset, + DisplayString: gui.c.Tr.LcSubmoduleStashAndReset, OnPress: func() error { - return gui.resetSubmodule(submodule) + return gui.Controllers.Files.ResetSubmodule(submodule) }, }, } } else { menuItems = []*popup.MenuItem{ { - DisplayString: gui.Tr.LcDiscardAllChanges, + DisplayString: gui.c.Tr.LcDiscardAllChanges, OnPress: func() error { - gui.logAction(gui.Tr.Actions.DiscardAllChangesInFile) - if err := gui.Git.WorkingTree.DiscardAllFileChanges(file); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.DiscardAllChangesInFile) + if err := gui.git.WorkingTree.DiscardAllFileChanges(file); err != nil { + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, } if file.HasStagedChanges && file.HasUnstagedChanges { menuItems = append(menuItems, &popup.MenuItem{ - DisplayString: gui.Tr.LcDiscardUnstagedChanges, + DisplayString: gui.c.Tr.LcDiscardUnstagedChanges, OnPress: func() error { - gui.logAction(gui.Tr.Actions.DiscardAllUnstagedChangesInFile) - if err := gui.Git.WorkingTree.DiscardUnstagedFileChanges(file); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.DiscardAllUnstagedChangesInFile) + if err := gui.git.WorkingTree.DiscardUnstagedFileChanges(file); err != nil { + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }) } } } - return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: node.GetPath(), Items: menuItems}) + return gui.c.Menu(popup.CreateMenuOptions{Title: node.GetPath(), Items: menuItems}) } diff --git a/pkg/gui/editors.go b/pkg/gui/editors.go index 054a36094..145a6a62b 100644 --- a/pkg/gui/editors.go +++ b/pkg/gui/editors.go @@ -7,7 +7,7 @@ import ( ) func (gui *Gui) handleEditorKeypress(textArea *gocui.TextArea, key gocui.Key, ch rune, mod gocui.Modifier, allowMultiline bool) bool { - newlineKey, ok := gui.getKey(gui.UserConfig.Keybinding.Universal.AppendNewline).(gocui.Key) + newlineKey, ok := gui.getKey(gui.c.UserConfig.Keybinding.Universal.AppendNewline).(gocui.Key) if !ok { newlineKey = gocui.KeyAltEnter } @@ -62,7 +62,7 @@ func (gui *Gui) commitMessageEditor(v *gocui.View, key gocui.Key, ch rune, mod g // considered out of bounds to add a newline, meaning we can avoid unnecessary scrolling. err := gui.resizePopupPanel(v, v.TextArea.GetContent()) if err != nil { - gui.Log.Error(err) + gui.c.Log.Error(err) } v.RenderTextArea() gui.RenderCommitLength() diff --git a/pkg/gui/extras_panel.go b/pkg/gui/extras_panel.go index bd65dea87..fd2998cb3 100644 --- a/pkg/gui/extras_panel.go +++ b/pkg/gui/extras_panel.go @@ -8,11 +8,11 @@ import ( ) func (gui *Gui) handleCreateExtrasMenuPanel() error { - return gui.PopupHandler.Menu(popup.CreateMenuOptions{ - Title: gui.Tr.CommandLog, + return gui.c.Menu(popup.CreateMenuOptions{ + Title: gui.c.Tr.CommandLog, Items: []*popup.MenuItem{ { - DisplayString: gui.Tr.ToggleShowCommandLog, + DisplayString: gui.c.Tr.ToggleShowCommandLog, OnPress: func() error { currentContext := gui.currentStaticContext() if gui.ShowExtrasWindow && currentContext.GetKey() == COMMAND_LOG_CONTEXT_KEY { @@ -22,13 +22,13 @@ func (gui *Gui) handleCreateExtrasMenuPanel() error { } show := !gui.ShowExtrasWindow gui.ShowExtrasWindow = show - gui.Config.GetAppState().HideCommandLog = !show - _ = gui.Config.SaveAppState() + gui.c.GetAppState().HideCommandLog = !show + _ = gui.c.SaveAppState() return nil }, }, { - DisplayString: gui.Tr.FocusCommandLog, + DisplayString: gui.c.Tr.FocusCommandLog, OnPress: gui.handleFocusCommandLog, }, }, @@ -37,8 +37,9 @@ func (gui *Gui) handleCreateExtrasMenuPanel() error { func (gui *Gui) handleFocusCommandLog() error { gui.ShowExtrasWindow = true + // TODO: is this necessary? Can't I just call 'return from context'? gui.State.Contexts.CommandLog.SetParentContext(gui.currentSideContext()) - return gui.pushContext(gui.State.Contexts.CommandLog) + return gui.c.PushContext(gui.State.Contexts.CommandLog) } func (gui *Gui) scrollUpExtra() error { @@ -58,7 +59,7 @@ func (gui *Gui) scrollDownExtra() error { } func (gui *Gui) getCmdWriter() io.Writer { - return &prefixWriter{writer: gui.Views.Extras, prefix: style.FgMagenta.Sprintf("\n\n%s\n", gui.Tr.GitOutput)} + return &prefixWriter{writer: gui.Views.Extras, prefix: style.FgMagenta.Sprintf("\n\n%s\n", gui.c.Tr.GitOutput)} } // Ensures that the first write is preceded by writing a prefix. diff --git a/pkg/gui/file_helper.go b/pkg/gui/file_helper.go new file mode 100644 index 000000000..1b50aac82 --- /dev/null +++ b/pkg/gui/file_helper.go @@ -0,0 +1,51 @@ +package gui + +import ( + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/gui/controllers" +) + +type FileHelper struct { + c *controllers.ControllerCommon + git *commands.GitCommand + os *oscommands.OSCommand +} + +func NewFileHelper( + c *controllers.ControllerCommon, + git *commands.GitCommand, + os *oscommands.OSCommand, +) *FileHelper { + return &FileHelper{ + c: c, + git: git, + os: os, + } +} + +var _ controllers.IFileHelper = &FileHelper{} + +func (self *FileHelper) EditFile(filename string) error { + return self.EditFileAtLine(filename, 1) +} + +func (self *FileHelper) EditFileAtLine(filename string, lineNumber int) error { + cmdStr, err := self.git.File.GetEditCmdStr(filename, lineNumber) + if err != nil { + return self.c.Error(err) + } + + self.c.LogAction(self.c.Tr.Actions.EditFile) + return self.c.RunSubprocessAndRefresh( + self.os.Cmd.NewShell(cmdStr), + ) +} + +func (self *FileHelper) OpenFile(filename string) error { + self.c.LogAction(self.c.Tr.Actions.OpenFile) + if err := self.os.OpenFile(filename); err != nil { + return self.c.Error(err) + } + return nil +} diff --git a/pkg/gui/file_watching.go b/pkg/gui/file_watching.go index 9f4e84a0f..01a2d0b88 100644 --- a/pkg/gui/file_watching.go +++ b/pkg/gui/file_watching.go @@ -118,13 +118,13 @@ func (gui *Gui) watchFilesForChanges() { } // only refresh if we're not already if !gui.State.IsRefreshingFiles { - _ = gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + _ = gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) } // watch for errors case err := <-gui.fileWatcher.Watcher.Errors: if err != nil { - gui.Log.Error(err) + gui.c.Log.Error(err) } } } diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index b442a566f..8ebecba14 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -1,15 +1,10 @@ package gui import ( - "fmt" - "regexp" - "strings" - - "github.com/jesseduffield/lazygit/pkg/commands/git_commands" + "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/loaders" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" - "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/mergeconflicts" "github.com/jesseduffield/lazygit/pkg/gui/popup" @@ -52,7 +47,7 @@ func (gui *Gui) filesRenderToMain() error { return gui.refreshMainViews(refreshMainOpts{ main: &viewUpdateOpts{ title: "", - task: NewRenderStringTask(gui.Tr.NoChangedFiles), + task: NewRenderStringTask(gui.c.Tr.NoChangedFiles), }, }) } @@ -69,24 +64,24 @@ func (gui *Gui) filesRenderToMain() error { gui.resetMergeStateWithLock() - cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(node, false, !node.GetHasUnstagedChanges() && node.GetHasStagedChanges(), gui.IgnoreWhitespaceInDiffView) + cmdObj := gui.git.WorkingTree.WorktreeFileDiffCmdObj(node, false, !node.GetHasUnstagedChanges() && node.GetHasStagedChanges(), gui.IgnoreWhitespaceInDiffView) refreshOpts := refreshMainOpts{main: &viewUpdateOpts{ - title: gui.Tr.UnstagedChanges, + title: gui.c.Tr.UnstagedChanges, task: NewRunPtyTask(cmdObj.GetCmd()), }} if node.GetHasUnstagedChanges() { if node.GetHasStagedChanges() { - cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(node, false, true, gui.IgnoreWhitespaceInDiffView) + cmdObj := gui.git.WorkingTree.WorktreeFileDiffCmdObj(node, false, true, gui.IgnoreWhitespaceInDiffView) refreshOpts.secondary = &viewUpdateOpts{ - title: gui.Tr.StagedChanges, + title: gui.c.Tr.StagedChanges, task: NewRunPtyTask(cmdObj.GetCmd()), } } } else { - refreshOpts.main.title = gui.Tr.StagedChanges + refreshOpts.main.title = gui.c.Tr.StagedChanges } return gui.refreshMainViews(refreshOpts) @@ -115,12 +110,12 @@ func (gui *Gui) refreshFilesAndSubmodules() error { } gui.OnUIThread(func() error { - if err := gui.postRefreshUpdate(gui.State.Contexts.Submodules); err != nil { - gui.Log.Error(err) + if err := gui.c.PostRefreshUpdate(gui.State.Contexts.Submodules); err != nil { + gui.c.Log.Error(err) } - if ContextKey(gui.Views.Files.Context) == FILES_CONTEXT_KEY { - // doing this a little custom (as opposed to using gui.postRefreshUpdate) because we handle selecting the file explicitly below + if types.ContextKey(gui.Views.Files.Context) == FILES_CONTEXT_KEY { + // doing this a little custom (as opposed to using gui.c.PostRefreshUpdate) because we handle selecting the file explicitly below if err := gui.State.Contexts.Files.HandleRender(); err != nil { return err } @@ -143,418 +138,6 @@ func (gui *Gui) refreshFilesAndSubmodules() error { return nil } -// specific functions - -func (gui *Gui) stagedFiles() []*models.File { - files := gui.State.FileTreeViewModel.GetAllFiles() - result := make([]*models.File, 0) - for _, file := range files { - if file.HasStagedChanges { - result = append(result, file) - } - } - return result -} - -func (gui *Gui) trackedFiles() []*models.File { - files := gui.State.FileTreeViewModel.GetAllFiles() - result := make([]*models.File, 0, len(files)) - for _, file := range files { - if file.Tracked { - result = append(result, file) - } - } - return result -} - -func (gui *Gui) handleEnterFile() error { - return gui.enterFile(OnFocusOpts{ClickedViewName: "", ClickedViewLineIdx: -1}) -} - -func (gui *Gui) enterFile(opts OnFocusOpts) error { - node := gui.getSelectedFileNode() - if node == nil { - return nil - } - - if node.File == nil { - return gui.handleToggleDirCollapsed() - } - - file := node.File - - submoduleConfigs := gui.State.Submodules - if file.IsSubmodule(submoduleConfigs) { - submoduleConfig := file.SubmoduleConfig(submoduleConfigs) - return gui.enterSubmodule(submoduleConfig) - } - - if file.HasInlineMergeConflicts { - return gui.switchToMerge() - } - if file.HasMergeConflicts { - return gui.PopupHandler.ErrorMsg(gui.Tr.FileStagingRequirements) - } - - return gui.pushContext(gui.State.Contexts.Staging, opts) -} - -func (gui *Gui) handleFilePress() error { - node := gui.getSelectedFileNode() - if node == nil { - return nil - } - - if node.IsLeaf() { - file := node.File - - if file.HasInlineMergeConflicts { - return gui.switchToMerge() - } - - if file.HasUnstagedChanges { - gui.logAction(gui.Tr.Actions.StageFile) - if err := gui.Git.WorkingTree.StageFile(file.Name); err != nil { - return gui.PopupHandler.Error(err) - } - } else { - gui.logAction(gui.Tr.Actions.UnstageFile) - if err := gui.Git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil { - return gui.PopupHandler.Error(err) - } - } - } else { - // if any files within have inline merge conflicts we can't stage or unstage, - // or it'll end up with those >>>>>> lines actually staged - if node.GetHasInlineMergeConflicts() { - return gui.PopupHandler.ErrorMsg(gui.Tr.ErrStageDirWithInlineMergeConflicts) - } - - if node.GetHasUnstagedChanges() { - gui.logAction(gui.Tr.Actions.StageFile) - if err := gui.Git.WorkingTree.StageFile(node.Path); err != nil { - return gui.PopupHandler.Error(err) - } - } else { - // pretty sure it doesn't matter that we're always passing true here - gui.logAction(gui.Tr.Actions.UnstageFile) - if err := gui.Git.WorkingTree.UnStageFile([]string{node.Path}, true); err != nil { - return gui.PopupHandler.Error(err) - } - } - } - - if err := gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}); err != nil { - return err - } - - return gui.State.Contexts.Files.HandleFocus() -} - -func (gui *Gui) allFilesStaged() bool { - for _, file := range gui.State.FileTreeViewModel.GetAllFiles() { - if file.HasUnstagedChanges { - return false - } - } - return true -} - -func (gui *Gui) onFocusFile() error { - gui.takeOverMergeConflictScrolling() - return nil -} - -func (gui *Gui) handleStageAll() error { - var err error - if gui.allFilesStaged() { - gui.logAction(gui.Tr.Actions.UnstageAllFiles) - err = gui.Git.WorkingTree.UnstageAll() - } else { - gui.logAction(gui.Tr.Actions.StageAllFiles) - err = gui.Git.WorkingTree.StageAll() - } - if err != nil { - _ = gui.PopupHandler.Error(err) - } - - if err := gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}); err != nil { - return err - } - - return gui.State.Contexts.Files.HandleFocus() -} - -func (gui *Gui) handleIgnoreFile() error { - node := gui.getSelectedFileNode() - if node == nil { - return nil - } - - if node.GetPath() == ".gitignore" { - return gui.PopupHandler.ErrorMsg("Cannot ignore .gitignore") - } - - unstageFiles := func() error { - return node.ForEachFile(func(file *models.File) error { - if file.HasStagedChanges { - if err := gui.Git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil { - return err - } - } - - return nil - }) - } - - if node.GetIsTracked() { - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.IgnoreTracked, - Prompt: gui.Tr.IgnoreTrackedPrompt, - HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.IgnoreFile) - // not 100% sure if this is necessary but I'll assume it is - if err := unstageFiles(); err != nil { - return err - } - - if err := gui.Git.WorkingTree.RemoveTrackedFiles(node.GetPath()); err != nil { - return err - } - - if err := gui.Git.WorkingTree.Ignore(node.GetPath()); err != nil { - return err - } - return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}) - }, - }) - } - - gui.logAction(gui.Tr.Actions.IgnoreFile) - - if err := unstageFiles(); err != nil { - return err - } - - if err := gui.Git.WorkingTree.Ignore(node.GetPath()); err != nil { - return gui.PopupHandler.Error(err) - } - - return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}) -} - -func (gui *Gui) handleWIPCommitPress() error { - skipHookPrefix := gui.UserConfig.Git.SkipHookPrefix - if skipHookPrefix == "" { - return gui.PopupHandler.ErrorMsg(gui.Tr.SkipHookPrefixNotConfigured) - } - - textArea := gui.Views.CommitMessage.TextArea - textArea.Clear() - textArea.TypeString(skipHookPrefix) - gui.Views.CommitMessage.RenderTextArea() - - return gui.handleCommitPress() -} - -func (gui *Gui) commitPrefixConfigForRepo() *config.CommitPrefixConfig { - cfg, ok := gui.UserConfig.Git.CommitPrefixes[utils.GetCurrentRepoName()] - if !ok { - return nil - } - - return &cfg -} - -func (gui *Gui) prepareFilesForCommit() error { - noStagedFiles := len(gui.stagedFiles()) == 0 - if noStagedFiles && gui.UserConfig.Gui.SkipNoStagedFilesWarning { - gui.logAction(gui.Tr.Actions.StageAllFiles) - err := gui.Git.WorkingTree.StageAll() - if err != nil { - return err - } - - return gui.refreshFilesAndSubmodules() - } - - return nil -} - -func (gui *Gui) handleCommitPress() error { - if err := gui.prepareFilesForCommit(); err != nil { - return gui.PopupHandler.Error(err) - } - - if gui.State.FileTreeViewModel.GetItemsLength() == 0 { - return gui.PopupHandler.ErrorMsg(gui.Tr.NoFilesStagedTitle) - } - - if len(gui.stagedFiles()) == 0 { - return gui.promptToStageAllAndRetry(gui.handleCommitPress) - } - - if len(gui.State.failedCommitMessage) > 0 { - gui.Views.CommitMessage.ClearTextArea() - gui.Views.CommitMessage.TextArea.TypeString(gui.State.failedCommitMessage) - gui.Views.CommitMessage.RenderTextArea() - } else { - commitPrefixConfig := gui.commitPrefixConfigForRepo() - if commitPrefixConfig != nil { - prefixPattern := commitPrefixConfig.Pattern - prefixReplace := commitPrefixConfig.Replace - rgx, err := regexp.Compile(prefixPattern) - if err != nil { - return gui.PopupHandler.ErrorMsg(fmt.Sprintf("%s: %s", gui.Tr.LcCommitPrefixPatternError, err.Error())) - } - prefix := rgx.ReplaceAllString(gui.getCheckedOutBranch().Name, prefixReplace) - gui.Views.CommitMessage.ClearTextArea() - gui.Views.CommitMessage.TextArea.TypeString(prefix) - gui.Views.CommitMessage.RenderTextArea() - } - } - - if err := gui.pushContext(gui.State.Contexts.CommitMessage); err != nil { - return err - } - - gui.RenderCommitLength() - return nil -} - -func (gui *Gui) promptToStageAllAndRetry(retry func() error) error { - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.NoFilesStagedTitle, - Prompt: gui.Tr.NoFilesStagedPrompt, - HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.StageAllFiles) - if err := gui.Git.WorkingTree.StageAll(); err != nil { - return gui.PopupHandler.Error(err) - } - if err := gui.refreshFilesAndSubmodules(); err != nil { - return gui.PopupHandler.Error(err) - } - - return retry() - }, - }) -} - -func (gui *Gui) handleAmendCommitPress() error { - if gui.State.FileTreeViewModel.GetItemsLength() == 0 { - return gui.PopupHandler.ErrorMsg(gui.Tr.NoFilesStagedTitle) - } - - if len(gui.stagedFiles()) == 0 { - return gui.promptToStageAllAndRetry(gui.handleAmendCommitPress) - } - - if len(gui.State.Commits) == 0 { - return gui.PopupHandler.ErrorMsg(gui.Tr.NoCommitToAmend) - } - - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: strings.Title(gui.Tr.AmendLastCommit), - Prompt: gui.Tr.SureToAmend, - HandleConfirm: func() error { - cmdObj := gui.Git.Commit.AmendHeadCmdObj() - gui.logAction(gui.Tr.Actions.AmendCommit) - return gui.withGpgHandling(cmdObj, gui.Tr.AmendingStatus, nil) - }, - }) -} - -// handleCommitEditorPress - handle when the user wants to commit changes via -// their editor rather than via the popup panel -func (gui *Gui) handleCommitEditorPress() error { - if gui.State.FileTreeViewModel.GetItemsLength() == 0 { - return gui.PopupHandler.ErrorMsg(gui.Tr.NoFilesStagedTitle) - } - - if len(gui.stagedFiles()) == 0 { - return gui.promptToStageAllAndRetry(gui.handleCommitEditorPress) - } - - gui.logAction(gui.Tr.Actions.Commit) - return gui.runSubprocessWithSuspenseAndRefresh( - gui.Git.Commit.CommitEditorCmdObj(), - ) -} - -func (gui *Gui) handleStatusFilterPressed() error { - return gui.PopupHandler.Menu(popup.CreateMenuOptions{ - Title: gui.Tr.FilteringMenuTitle, - Items: []*popup.MenuItem{ - { - DisplayString: gui.Tr.FilterStagedFiles, - OnPress: func() error { - return gui.setStatusFiltering(filetree.DisplayStaged) - }, - }, - { - DisplayString: gui.Tr.FilterUnstagedFiles, - OnPress: func() error { - return gui.setStatusFiltering(filetree.DisplayUnstaged) - }, - }, - { - DisplayString: gui.Tr.ResetCommitFilterState, - OnPress: func() error { - return gui.setStatusFiltering(filetree.DisplayAll) - }, - }, - }, - }) -} - -func (gui *Gui) setStatusFiltering(filter filetree.FileTreeDisplayFilter) error { - state := gui.State - state.FileTreeViewModel.SetFilter(filter) - return gui.handleRefreshFiles() -} - -func (gui *Gui) editFile(filename string) error { - return gui.editFileAtLine(filename, 1) -} - -func (gui *Gui) editFileAtLine(filename string, lineNumber int) error { - cmdStr, err := gui.Git.File.GetEditCmdStr(filename, lineNumber) - if err != nil { - return gui.PopupHandler.Error(err) - } - - gui.logAction(gui.Tr.Actions.EditFile) - return gui.runSubprocessWithSuspenseAndRefresh( - gui.OSCommand.Cmd.NewShell(cmdStr), - ) -} - -func (gui *Gui) handleFileEdit() error { - node := gui.getSelectedFileNode() - if node == nil { - return nil - } - - if node.File == nil { - return gui.PopupHandler.ErrorMsg(gui.Tr.ErrCannotEditDirectory) - } - - return gui.editFile(node.GetPath()) -} - -func (gui *Gui) handleFileOpen() error { - node := gui.getSelectedFileNode() - if node == nil { - return nil - } - - return gui.openFile(node.GetPath()) -} - -func (gui *Gui) handleRefreshFiles() error { - return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}) -} - func (gui *Gui) refreshStateFiles() error { state := gui.State @@ -591,13 +174,13 @@ func (gui *Gui) refreshStateFiles() error { } if len(pathsToStage) > 0 { - gui.logAction(gui.Tr.Actions.StageResolvedFiles) - if err := gui.Git.WorkingTree.StageFiles(pathsToStage); err != nil { - return gui.surfaceError(err) + gui.c.LogAction(gui.Tr.Actions.StageResolvedFiles) + if err := gui.git.WorkingTree.StageFiles(pathsToStage); err != nil { + return gui.c.Error(err) } } - files := gui.Git.Loaders.Files. + files := gui.git.Loaders.Files. GetStatusFiles(loaders.GetStatusFileOptions{}) conflictFileCount := 0 @@ -607,7 +190,7 @@ func (gui *Gui) refreshStateFiles() error { } } - if gui.Git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE && conflictFileCount == 0 && prevConflictFileCount > 0 { + if gui.git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE && conflictFileCount == 0 && prevConflictFileCount > 0 { gui.OnUIThread(func() error { return gui.promptToContinueRebase() }) } @@ -716,218 +299,7 @@ func (gui *Gui) findNewSelectedIdx(prevNodes []*filetree.FileNode, currNodes []* return -1 } -func (gui *Gui) handlePullFiles() error { - if gui.popupPanelFocused() { - return nil - } - - action := gui.Tr.Actions.Pull - - currentBranch := gui.currentBranch() - if currentBranch == nil { - // need to wait for branches to refresh - return nil - } - - // if we have no upstream branch we need to set that first - if !currentBranch.IsTrackingRemote() { - suggestedRemote := getSuggestedRemote(gui.State.Remotes) - - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: gui.Tr.EnterUpstream, - InitialContent: suggestedRemote + " " + currentBranch.Name, - FindSuggestionsFunc: gui.getRemoteBranchesSuggestionsFunc(" "), - HandleConfirm: func(upstream string) error { - var upstreamBranch, upstreamRemote string - split := strings.Split(upstream, " ") - if len(split) != 2 { - return gui.PopupHandler.ErrorMsg(gui.Tr.InvalidUpstream) - } - - upstreamRemote = split[0] - upstreamBranch = split[1] - - if err := gui.Git.Branch.SetCurrentBranchUpstream(upstreamRemote, upstreamBranch); err != nil { - errorMessage := err.Error() - if strings.Contains(errorMessage, "does not exist") { - errorMessage = fmt.Sprintf("upstream branch %s not found.\nIf you expect it to exist, you should fetch (with 'f').\nOtherwise, you should push (with 'shift+P')", upstream) - } - return gui.PopupHandler.ErrorMsg(errorMessage) - } - return gui.pullFiles(PullFilesOptions{UpstreamRemote: upstreamRemote, UpstreamBranch: upstreamBranch, action: action}) - }, - }) - } - - return gui.pullFiles(PullFilesOptions{UpstreamRemote: currentBranch.UpstreamRemote, UpstreamBranch: currentBranch.UpstreamBranch, action: action}) -} - -type PullFilesOptions struct { - UpstreamRemote string - UpstreamBranch string - FastForwardOnly bool - action string -} - -func (gui *Gui) pullFiles(opts PullFilesOptions) error { - return gui.PopupHandler.WithLoaderPanel(gui.Tr.PullWait, func() error { - return gui.pullWithLock(opts) - }) -} - -func (gui *Gui) pullWithLock(opts PullFilesOptions) error { - gui.Mutexes.FetchMutex.Lock() - defer gui.Mutexes.FetchMutex.Unlock() - - gui.logAction(opts.action) - - err := gui.Git.Sync.Pull( - git_commands.PullOptions{ - RemoteName: opts.UpstreamRemote, - BranchName: opts.UpstreamBranch, - FastForwardOnly: opts.FastForwardOnly, - }, - ) - if err == nil { - _ = gui.closeConfirmationPrompt(false) - } - return gui.handleGenericMergeCommandResult(err) -} - -type pushOpts struct { - force bool - upstreamRemote string - upstreamBranch string - setUpstream bool -} - -func (gui *Gui) push(opts pushOpts) error { - return gui.PopupHandler.WithLoaderPanel(gui.Tr.PushWait, func() error { - gui.logAction(gui.Tr.Actions.Push) - err := gui.Git.Sync.Push(git_commands.PushOpts{ - Force: opts.force, - UpstreamRemote: opts.upstreamRemote, - UpstreamBranch: opts.upstreamBranch, - SetUpstream: opts.setUpstream, - }) - - if err != nil { - if !opts.force && strings.Contains(err.Error(), "Updates were rejected") { - forcePushDisabled := gui.UserConfig.Git.DisableForcePushing - if forcePushDisabled { - _ = gui.PopupHandler.ErrorMsg(gui.Tr.UpdatesRejectedAndForcePushDisabled) - return nil - } - _ = gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.ForcePush, - Prompt: gui.Tr.ForcePushPrompt, - HandleConfirm: func() error { - newOpts := opts - newOpts.force = true - - return gui.push(newOpts) - }, - }) - return nil - } - _ = gui.PopupHandler.Error(err) - } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) - }) -} - -func (gui *Gui) pushFiles() error { - if gui.popupPanelFocused() { - return nil - } - - // if we have pullables we'll ask if the user wants to force push - currentBranch := gui.currentBranch() - if currentBranch == nil { - // need to wait for branches to refresh - return nil - } - - if currentBranch.IsTrackingRemote() { - opts := pushOpts{ - force: false, - upstreamRemote: currentBranch.UpstreamRemote, - upstreamBranch: currentBranch.UpstreamBranch, - } - if currentBranch.HasCommitsToPull() { - opts.force = true - return gui.requestToForcePush(opts) - } else { - return gui.push(opts) - } - } else { - suggestedRemote := getSuggestedRemote(gui.State.Remotes) - - if gui.Git.Config.GetPushToCurrent() { - return gui.push(pushOpts{setUpstream: true}) - } else { - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: gui.Tr.EnterUpstream, - InitialContent: suggestedRemote + " " + currentBranch.Name, - FindSuggestionsFunc: gui.getRemoteBranchesSuggestionsFunc(" "), - HandleConfirm: func(upstream string) error { - var upstreamBranch, upstreamRemote string - split := strings.Split(upstream, " ") - if len(split) == 2 { - upstreamRemote = split[0] - upstreamBranch = split[1] - } else { - upstreamRemote = upstream - upstreamBranch = "" - } - - return gui.push(pushOpts{ - force: false, - upstreamRemote: upstreamRemote, - upstreamBranch: upstreamBranch, - setUpstream: true, - }) - }, - }) - } - } -} - -func getSuggestedRemote(remotes []*models.Remote) string { - if len(remotes) == 0 { - return "origin" - } - - for _, remote := range remotes { - if remote.Name == "origin" { - return remote.Name - } - } - - return remotes[0].Name -} - -func (gui *Gui) requestToForcePush(opts pushOpts) error { - forcePushDisabled := gui.UserConfig.Git.DisableForcePushing - if forcePushDisabled { - return gui.PopupHandler.ErrorMsg(gui.Tr.ForcePushDisabled) - } - - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.ForcePush, - Prompt: gui.Tr.ForcePushPrompt, - HandleConfirm: func() error { - return gui.push(opts) - }, - }) -} - -func (gui *Gui) switchToMerge() error { - file := gui.getSelectedFile() - if file == nil { - return nil - } - +func (gui *Gui) onFocusFile() error { gui.takeOverMergeConflictScrolling() if gui.State.Panels.Merging.GetPath() != file.Name { @@ -940,155 +312,14 @@ func (gui *Gui) switchToMerge() error { } } + // TODO: this can't be right. return gui.pushContext(gui.State.Contexts.Merging) } -func (gui *Gui) openFile(filename string) error { - gui.logAction(gui.Tr.Actions.OpenFile) - if err := gui.OSCommand.OpenFile(filename); err != nil { - return gui.PopupHandler.Error(err) +func (gui *Gui) getSetTextareaTextFn(view *gocui.View) func(string) { + return func(text string) { + view.ClearTextArea() + view.TextArea.TypeString(text) + view.RenderTextArea() } - return nil -} - -func (gui *Gui) handleCustomCommand() error { - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: gui.Tr.CustomCommand, - FindSuggestionsFunc: gui.getCustomCommandsHistorySuggestionsFunc(), - HandleConfirm: func(command string) error { - gui.Config.GetAppState().CustomCommandsHistory = utils.Limit( - utils.Uniq( - append(gui.Config.GetAppState().CustomCommandsHistory, command), - ), - 1000, - ) - - err := gui.Config.SaveAppState() - if err != nil { - gui.Log.Error(err) - } - - gui.logAction(gui.Tr.Actions.CustomCommand) - return gui.runSubprocessWithSuspenseAndRefresh( - gui.OSCommand.Cmd.NewShell(command), - ) - }, - }) -} - -func (gui *Gui) handleCreateStashMenu() error { - return gui.PopupHandler.Menu(popup.CreateMenuOptions{ - Title: gui.Tr.LcStashOptions, - Items: []*popup.MenuItem{ - { - DisplayString: gui.Tr.LcStashAllChanges, - OnPress: func() error { - gui.logAction(gui.Tr.Actions.StashAllChanges) - return gui.handleStashSave(gui.Git.Stash.Save) - }, - }, - { - DisplayString: gui.Tr.LcStashStagedChanges, - OnPress: func() error { - gui.logAction(gui.Tr.Actions.StashStagedChanges) - return gui.handleStashSave(gui.Git.Stash.SaveStagedChanges) - }, - }, - }, - }) -} - -func (gui *Gui) handleStashChanges() error { - return gui.handleStashSave(gui.Git.Stash.Save) -} - -func (gui *Gui) handleCreateResetToUpstreamMenu() error { - return gui.createResetMenu("@{upstream}") -} - -func (gui *Gui) handleToggleDirCollapsed() error { - node := gui.getSelectedFileNode() - if node == nil { - return nil - } - - gui.State.FileTreeViewModel.ToggleCollapsed(node.GetPath()) - - if err := gui.postRefreshUpdate(gui.State.Contexts.Files); err != nil { - gui.Log.Error(err) - } - - return nil -} - -func (gui *Gui) handleToggleFileTreeView() error { - // get path of currently selected file - path := gui.getSelectedPath() - - gui.State.FileTreeViewModel.ToggleShowTree() - - // find that same node in the new format and move the cursor to it - if path != "" { - gui.State.FileTreeViewModel.ExpandToPath(path) - index, found := gui.State.FileTreeViewModel.GetIndexForPath(path) - if found { - gui.filesListContext().GetPanelState().SetSelectedLineIdx(index) - } - } - - if ContextKey(gui.Views.Files.Context) == FILES_CONTEXT_KEY { - if err := gui.State.Contexts.Files.HandleRender(); err != nil { - return err - } - if err := gui.State.Contexts.Files.HandleFocus(); err != nil { - return err - } - } - - return nil -} - -func (gui *Gui) handleOpenMergeTool() error { - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.MergeToolTitle, - Prompt: gui.Tr.MergeToolPrompt, - HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.OpenMergeTool) - return gui.runSubprocessWithSuspenseAndRefresh( - gui.Git.WorkingTree.OpenMergeToolCmdObj(), - ) - }, - }) -} - -func (gui *Gui) resetSubmodule(submodule *models.SubmoduleConfig) error { - return gui.PopupHandler.WithWaitingStatus(gui.Tr.LcResettingSubmoduleStatus, func() error { - gui.logAction(gui.Tr.Actions.ResetSubmodule) - - file := gui.fileForSubmodule(submodule) - if file != nil { - if err := gui.Git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil { - return gui.PopupHandler.Error(err) - } - } - - if err := gui.Git.Submodule.Stash(submodule); err != nil { - return gui.PopupHandler.Error(err) - } - if err := gui.Git.Submodule.Reset(submodule); err != nil { - return gui.PopupHandler.Error(err) - } - - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.SUBMODULES}}) - }) -} - -func (gui *Gui) fileForSubmodule(submodule *models.SubmoduleConfig) *models.File { - for _, file := range gui.State.FileManager.GetAllFiles() { - if file.IsSubmodule([]*models.SubmoduleConfig{submodule}) { - return file - } - } - - return nil } diff --git a/pkg/gui/filetree/commit_file_node.go b/pkg/gui/filetree/commit_file_node.go index 14960ee30..98428348e 100644 --- a/pkg/gui/filetree/commit_file_node.go +++ b/pkg/gui/filetree/commit_file_node.go @@ -2,6 +2,7 @@ package filetree import ( "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) type CommitFileNode struct { @@ -12,8 +13,7 @@ type CommitFileNode struct { } var _ INode = &CommitFileNode{} - -// methods satisfying ListItem interface +var _ types.ListItem = &CommitFileNode{} func (s *CommitFileNode) ID() string { return s.GetPath() diff --git a/pkg/gui/filetree/file_node.go b/pkg/gui/filetree/file_node.go index f332f0a76..5a99b3e12 100644 --- a/pkg/gui/filetree/file_node.go +++ b/pkg/gui/filetree/file_node.go @@ -2,6 +2,7 @@ package filetree import ( "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) type FileNode struct { @@ -12,8 +13,7 @@ type FileNode struct { } var _ INode = &FileNode{} - -// methods satisfying ListItem interface +var _ types.ListItem = &FileNode{} func (s *FileNode) ID() string { return s.GetPath() diff --git a/pkg/gui/filtering.go b/pkg/gui/filtering.go index df007b69a..df4fa848d 100644 --- a/pkg/gui/filtering.go +++ b/pkg/gui/filtering.go @@ -5,17 +5,27 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/types" ) -func (gui *Gui) validateNotInFilterMode() (bool, error) { +func (gui *Gui) validateNotInFilterMode() bool { if gui.State.Modes.Filtering.Active() { - err := gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.MustExitFilterModeTitle, - Prompt: gui.Tr.MustExitFilterModePrompt, + _ = gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.MustExitFilterModeTitle, + Prompt: gui.c.Tr.MustExitFilterModePrompt, HandleConfirm: gui.exitFilterMode, }) - return false, err + return false + } + return true +} + +func (gui *Gui) outsideFilterMode(f func() error) func() error { + return func() error { + if !gui.validateNotInFilterMode() { + return nil + } + + return f() } - return true, nil } func (gui *Gui) exitFilterMode() error { @@ -28,7 +38,7 @@ func (gui *Gui) clearFiltering() error { gui.State.ScreenMode = SCREEN_NORMAL } - return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}}) + return gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}}) } func (gui *Gui) setFiltering(path string) error { @@ -37,11 +47,11 @@ func (gui *Gui) setFiltering(path string) error { gui.State.ScreenMode = SCREEN_HALF } - if err := gui.pushContext(gui.State.Contexts.BranchCommits); err != nil { + if err := gui.c.PushContext(gui.State.Contexts.BranchCommits); err != nil { return err } - return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}, Then: func() { + return gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}, Then: func() { gui.State.Contexts.BranchCommits.GetPanelState().SetSelectedLineIdx(0) }}) } diff --git a/pkg/gui/filtering_menu_panel.go b/pkg/gui/filtering_menu_panel.go index dcdf1ec40..39d39765e 100644 --- a/pkg/gui/filtering_menu_panel.go +++ b/pkg/gui/filtering_menu_panel.go @@ -26,7 +26,7 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error { if fileName != "" { menuItems = append(menuItems, &popup.MenuItem{ - DisplayString: fmt.Sprintf("%s '%s'", gui.Tr.LcFilterBy, fileName), + DisplayString: fmt.Sprintf("%s '%s'", gui.c.Tr.LcFilterBy, fileName), OnPress: func() error { return gui.setFiltering(fileName) }, @@ -34,11 +34,11 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error { } menuItems = append(menuItems, &popup.MenuItem{ - DisplayString: gui.Tr.LcFilterPathOption, + DisplayString: gui.c.Tr.LcFilterPathOption, OnPress: func() error { - return gui.PopupHandler.Prompt(popup.PromptOpts{ - FindSuggestionsFunc: gui.getFilePathSuggestionsFunc(), - Title: gui.Tr.EnterFileName, + return gui.c.Prompt(popup.PromptOpts{ + FindSuggestionsFunc: gui.suggestionsHelper.GetFilePathSuggestionsFunc(), + Title: gui.c.Tr.EnterFileName, HandleConfirm: func(response string) error { return gui.setFiltering(strings.TrimSpace(response)) }, @@ -48,10 +48,10 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error { if gui.State.Modes.Filtering.Active() { menuItems = append(menuItems, &popup.MenuItem{ - DisplayString: gui.Tr.LcExitFilterMode, + DisplayString: gui.c.Tr.LcExitFilterMode, OnPress: gui.clearFiltering, }) } - return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: gui.Tr.FilteringMenuTitle, Items: menuItems}) + return gui.c.Menu(popup.CreateMenuOptions{Title: gui.c.Tr.FilteringMenuTitle, Items: menuItems}) } diff --git a/pkg/gui/git_flow.go b/pkg/gui/git_flow.go index ab58adfe8..171310785 100644 --- a/pkg/gui/git_flow.go +++ b/pkg/gui/git_flow.go @@ -13,27 +13,27 @@ func (gui *Gui) handleCreateGitFlowMenu() error { return nil } - if !gui.Git.Flow.GitFlowEnabled() { - return gui.PopupHandler.ErrorMsg("You need to install git-flow and enable it in this repo to use git-flow features") + if !gui.git.Flow.GitFlowEnabled() { + return gui.c.ErrorMsg("You need to install git-flow and enable it in this repo to use git-flow features") } startHandler := func(branchType string) func() error { return func() error { - title := utils.ResolvePlaceholderString(gui.Tr.NewGitFlowBranchPrompt, map[string]string{"branchType": branchType}) + title := utils.ResolvePlaceholderString(gui.c.Tr.NewGitFlowBranchPrompt, map[string]string{"branchType": branchType}) - return gui.PopupHandler.Prompt(popup.PromptOpts{ + return gui.c.Prompt(popup.PromptOpts{ Title: title, HandleConfirm: func(name string) error { - gui.logAction(gui.Tr.Actions.GitFlowStart) + gui.c.LogAction(gui.c.Tr.Actions.GitFlowStart) return gui.runSubprocessWithSuspenseAndRefresh( - gui.Git.Flow.StartCmdObj(branchType, name), + gui.git.Flow.StartCmdObj(branchType, name), ) }, }) } } - return gui.PopupHandler.Menu(popup.CreateMenuOptions{ + return gui.c.Menu(popup.CreateMenuOptions{ Title: "git flow", Items: []*popup.MenuItem{ { @@ -64,11 +64,11 @@ func (gui *Gui) handleCreateGitFlowMenu() error { } func (gui *Gui) gitFlowFinishBranch(branchName string) error { - cmdObj, err := gui.Git.Flow.FinishCmdObj(branchName) + cmdObj, err := gui.git.Flow.FinishCmdObj(branchName) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } - gui.logAction(gui.Tr.Actions.GitFlowFinish) + gui.c.LogAction(gui.c.Tr.Actions.GitFlowFinish) return gui.runSubprocessWithSuspenseAndRefresh(cmdObj) } diff --git a/pkg/gui/global_handlers.go b/pkg/gui/global_handlers.go index 1b4394519..380704fbc 100644 --- a/pkg/gui/global_handlers.go +++ b/pkg/gui/global_handlers.go @@ -65,7 +65,7 @@ func (gui *Gui) prevScreenMode() error { func (gui *Gui) scrollUpView(view *gocui.View) error { ox, oy := view.Origin() - newOy := int(math.Max(0, float64(oy-gui.UserConfig.Gui.ScrollHeight))) + newOy := int(math.Max(0, float64(oy-gui.c.UserConfig.Gui.ScrollHeight))) return view.SetOrigin(ox, newOy) } @@ -87,12 +87,12 @@ func (gui *Gui) scrollDownView(view *gocui.View) error { func (gui *Gui) linesToScrollDown(view *gocui.View) int { _, oy := view.Origin() y := oy - canScrollPastBottom := gui.UserConfig.Gui.ScrollPastBottom + canScrollPastBottom := gui.c.UserConfig.Gui.ScrollPastBottom if !canScrollPastBottom { _, sy := view.Size() y += sy } - scrollHeight := gui.UserConfig.Gui.ScrollHeight + scrollHeight := gui.c.UserConfig.Gui.ScrollHeight scrollableLines := view.ViewLinesHeight() - y if scrollableLines < 0 { return 0 @@ -177,7 +177,7 @@ func (gui *Gui) scrollDownConfirmationPanel() error { } func (gui *Gui) handleRefresh() error { - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) } func (gui *Gui) handleMouseDownMain() error { @@ -190,9 +190,9 @@ func (gui *Gui) handleMouseDownMain() error { // set filename, set primary/secondary selected, set line number, then switch context // I'll need to know it was changed though. // Could I pass something along to the context change? - return gui.enterFile(OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: gui.Views.Main.SelectedLineIdx()}) + return gui.Controllers.Files.EnterFile(types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: gui.Views.Main.SelectedLineIdx()}) case gui.State.Contexts.CommitFiles: - return gui.enterCommitFile(OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: gui.Views.Main.SelectedLineIdx()}) + return gui.enterCommitFile(types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: gui.Views.Main.SelectedLineIdx()}) } return nil @@ -205,35 +205,29 @@ func (gui *Gui) handleMouseDownSecondary() error { switch gui.g.CurrentView() { case gui.Views.Files: - return gui.enterFile(OnFocusOpts{ClickedViewName: "secondary", ClickedViewLineIdx: gui.Views.Secondary.SelectedLineIdx()}) + return gui.Controllers.Files.EnterFile(types.OnFocusOpts{ClickedViewName: "secondary", ClickedViewLineIdx: gui.Views.Secondary.SelectedLineIdx()}) } return nil } func (gui *Gui) fetch() (err error) { - gui.Mutexes.FetchMutex.Lock() - defer gui.Mutexes.FetchMutex.Unlock() - - gui.logAction("Fetch") - err = gui.Git.Sync.Fetch(git_commands.FetchOptions{}) + gui.c.LogAction("Fetch") + err = gui.git.Sync.Fetch(git_commands.FetchOptions{}) if err != nil && strings.Contains(err.Error(), "exit status 128") { - _ = gui.PopupHandler.ErrorMsg(gui.Tr.PassUnameWrong) + _ = gui.c.ErrorMsg(gui.c.Tr.PassUnameWrong) } - _ = gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.ASYNC}) + _ = gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.ASYNC}) return err } func (gui *Gui) backgroundFetch() (err error) { - gui.Mutexes.FetchMutex.Lock() - defer gui.Mutexes.FetchMutex.Unlock() + err = gui.git.Sync.Fetch(git_commands.FetchOptions{Background: true}) - err = gui.Git.Sync.Fetch(git_commands.FetchOptions{Background: true}) - - _ = gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.ASYNC}) + _ = gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.ASYNC}) return err } @@ -246,14 +240,14 @@ func (gui *Gui) handleCopySelectedSideContextItemToClipboard() error { return nil } - gui.logAction(gui.Tr.Actions.CopyToClipboard) + gui.c.LogAction(gui.c.Tr.Actions.CopyToClipboard) if err := gui.OSCommand.CopyToClipboard(itemId); err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } truncatedItemId := utils.TruncateWithEllipsis(strings.Replace(itemId, "\n", " ", -1), 50) - gui.raiseToast(fmt.Sprintf("'%s' %s", truncatedItemId, gui.Tr.LcCopiedToClipboard)) + gui.c.Toast(fmt.Sprintf("'%s' %s", truncatedItemId, gui.c.Tr.LcCopiedToClipboard)) return nil } diff --git a/pkg/gui/gpg.go b/pkg/gui/gpg.go index 1384055bc..a469b2a61 100644 --- a/pkg/gui/gpg.go +++ b/pkg/gui/gpg.go @@ -14,9 +14,9 @@ import ( // we don't need to see a loading status if we're in a subprocess. // TODO: work out if we actually need to use a shell command here func (gui *Gui) withGpgHandling(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error { - gui.logCommand(cmdObj.ToString(), true) + gui.LogCommand(cmdObj.ToString(), true) - useSubprocess := gui.Git.Config.UsingGpg() + useSubprocess := gui.git.Config.UsingGpg() if useSubprocess { success, err := gui.runSubprocessWithSuspense(gui.OSCommand.Cmd.NewShell(cmdObj.ToString())) if success && onSuccess != nil { @@ -24,7 +24,7 @@ func (gui *Gui) withGpgHandling(cmdObj oscommands.ICmdObj, waitingStatus string, return err } } - if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}); err != nil { + if err := gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil { return err } @@ -35,7 +35,7 @@ func (gui *Gui) withGpgHandling(cmdObj oscommands.ICmdObj, waitingStatus string, } func (gui *Gui) RunAndStream(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error { - return gui.PopupHandler.WithWaitingStatus(waitingStatus, func() error { + return gui.c.WithWaitingStatus(waitingStatus, func() error { cmdObj := gui.OSCommand.Cmd.NewShell(cmdObj.ToString()) cmdObj.AddEnvVars("TERM=dumb") cmdWriter := gui.getCmdWriter() @@ -45,12 +45,12 @@ func (gui *Gui) RunAndStream(cmdObj oscommands.ICmdObj, waitingStatus string, on if err := cmd.Run(); err != nil { if _, err := cmd.Stdout.Write([]byte(fmt.Sprintf("%s\n", style.FgRed.Sprint(err.Error())))); err != nil { - gui.Log.Error(err) + gui.c.Log.Error(err) } - _ = gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) - return gui.PopupHandler.Error( + _ = gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Error( fmt.Errorf( - gui.Tr.GitCommandFailed, gui.UserConfig.Keybinding.Universal.ExtrasMenu, + gui.c.Tr.GitCommandFailed, gui.c.UserConfig.Keybinding.Universal.ExtrasMenu, ), ) } @@ -61,6 +61,6 @@ func (gui *Gui) RunAndStream(cmdObj oscommands.ICmdObj, waitingStatus string, on } } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) }) } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 2bfd7f2ac..45040e086 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -18,6 +18,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/lbl" @@ -25,6 +26,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking" "github.com/jesseduffield/lazygit/pkg/gui/modes/diffing" "github.com/jesseduffield/lazygit/pkg/gui/modes/filtering" + "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/presentation/authors" "github.com/jesseduffield/lazygit/pkg/gui/presentation/graph" @@ -55,13 +57,13 @@ const StartupPopupVersion = 5 var OverlappingEdges = false type ContextManager struct { - ContextStack []Context + ContextStack []types.Context sync.RWMutex } -func NewContextManager(initialContext Context) ContextManager { +func NewContextManager(initialContext types.Context) ContextManager { return ContextManager{ - ContextStack: []Context{initialContext}, + ContextStack: []types.Context{initialContext}, RWMutex: sync.RWMutex{}, } } @@ -72,7 +74,7 @@ type Repo string type Gui struct { *common.Common g *gocui.Gui - Git *commands.GitCommand + git *commands.GitCommand OSCommand *oscommands.OSCommand // this is the state of the GUI for the current repo @@ -126,6 +128,7 @@ type Gui struct { IsNewRepo bool + // controllers define keybindings for a given context Controllers Controllers // flag as to whether or not the diff view should ignore whitespace @@ -133,10 +136,19 @@ type Gui struct { // if this is true, we'll load our commits using `git log --all` ShowWholeGitGraph bool + + // we use this to decide whether we'll return to the original directory that + // lazygit was opened in, or if we'll retain the one we're currently in. RetainOriginalDir bool PrevLayout PrevLayout + c *controllers.ControllerCommon + refHelper *RefHelper + suggestionsHelper *SuggestionsHelper + fileHelper *FileHelper + workingTreeHelper *WorkingTreeHelper + // this is the initial dir we are in upon opening lazygit. We hold onto this // in case we want to restore it before quitting for users who have set up // the feature for changing directory upon quit. @@ -182,7 +194,7 @@ type GuiRepoState struct { Updating bool Panels *panelStates SplitMainPanel bool - MainContext ContextKey // used to keep the main and secondary views' contexts in sync + MainContext types.ContextKey // used to keep the main and secondary views' contexts in sync IsRefreshingFiles bool Searching searchingState @@ -192,9 +204,9 @@ type GuiRepoState struct { Modes Modes ContextManager ContextManager - Contexts ContextTree - ViewContextMap map[string]Context - ViewTabContextMap map[string][]tabContext + Contexts context.ContextTree + ViewContextMap map[string]types.Context + ViewTabContextMap map[string][]context.TabContext // WindowViewNameMap is a mapping of windows to the current view of that window. // Some views move between windows for example the commitFiles view and when cycling through @@ -212,12 +224,19 @@ type GuiRepoState struct { // this is the message of the last failed commit attempt failedCommitMessage string - // TODO: move these into the gui struct ScreenMode WindowMaximisation } type Controllers struct { - Submodules *controllers.SubmodulesController + Submodules *controllers.SubmodulesController + Tags *controllers.TagsController + LocalCommits *controllers.LocalCommitsController + Files *controllers.FilesController + Remotes *controllers.RemotesController + Menu *controllers.MenuController + Bisect *controllers.BisectController + Undo *controllers.UndoController + Sync *controllers.SyncController } type listPanelState struct { @@ -373,13 +392,15 @@ type Modes struct { Diffing diffing.Diffing } +// if you add a new mutex here be sure to instantiate it. We're using pointers to +// mutexes so that we can pass the mutexes to controllers. type guiMutexes struct { - RefreshingFilesMutex sync.Mutex - RefreshingStatusMutex sync.Mutex - FetchMutex sync.Mutex - BranchCommitsMutex sync.Mutex - LineByLinePanelMutex sync.Mutex - SubprocessMutex sync.Mutex + RefreshingFilesMutex *sync.Mutex + RefreshingStatusMutex *sync.Mutex + FetchMutex *sync.Mutex + BranchCommitsMutex *sync.Mutex + LineByLinePanelMutex *sync.Mutex + SubprocessMutex *sync.Mutex } // reuseState determines if we pull the repo state from our repo state map or @@ -402,7 +423,7 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { return } } else { - gui.Log.Error(err) + gui.c.Log.Error(err) } } @@ -424,6 +445,7 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { FilteredReflogCommits: make([]*models.Commit, 0), ReflogCommits: make([]*models.Commit, 0), StashEntries: make([]*models.StashEntry, 0), + BisectInfo: git_commands.NewNullBisectInfo(), Panels: &panelStates{ // TODO: work out why some of these are -1 and some are 0. Last time I checked there was a good reason but I'm less certain now Files: &filePanelState{listPanelState{SelectedLineIdx: -1}}, @@ -450,8 +472,8 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { CherryPicking: cherrypicking.New(), Diffing: diffing.New(), }, - ViewContextMap: contexts.initialViewContextMap(), - ViewTabContextMap: contexts.initialViewTabContextMap(), + ViewContextMap: contexts.InitialViewContextMap(), + ViewTabContextMap: contexts.InitialViewTabContextMap(), ScreenMode: screenMode, // TODO: put contexts in the context manager ContextManager: NewContextManager(initialContext), @@ -462,21 +484,6 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { gui.RepoStateMap[Repo(currentDir)] = gui.State } -type guiCommon struct { - gui *Gui - popup.IPopupHandler -} - -var _ controllers.IGuiCommon = &guiCommon{} - -func (self *guiCommon) LogAction(msg string) { - self.gui.logAction(msg) -} - -func (self *guiCommon) Refresh(opts types.RefreshOptions) error { - return self.gui.refreshSidePanels(opts) -} - // for now the split view will always be on // NewGui builds a new gui handler func NewGui( @@ -504,13 +511,20 @@ func NewGui( // but now we do it via state. So we need to still support the config for the // sake of backwards compatibility. We're making use of short circuiting here ShowExtrasWindow: cmn.UserConfig.Gui.ShowCommandLog && !config.GetAppState().HideCommandLog, - + Mutexes: guiMutexes{ + RefreshingFilesMutex: &sync.Mutex{}, + RefreshingStatusMutex: &sync.Mutex{}, + FetchMutex: &sync.Mutex{}, + BranchCommitsMutex: &sync.Mutex{}, + LineByLinePanelMutex: &sync.Mutex{}, + SubprocessMutex: &sync.Mutex{}, + }, InitialDir: initialDir, } guiIO := oscommands.NewGuiIO( cmn.Log, - gui.logCommand, + gui.LogCommand, gui.getCmdWriter, gui.promptUserForCredential, ) @@ -519,42 +533,151 @@ func NewGui( gui.OSCommand = osCommand var err error - gui.Git, err = commands.NewGitCommand( + gui.git, err = commands.NewGitCommand( cmn, osCommand, gitConfig, + gui.Mutexes.FetchMutex, ) if err != nil { return nil, err } - gui.resetState(filterPath, false) - gui.watchFilesForChanges() gui.PopupHandler = popup.NewPopupHandler( cmn, gui.createPopupPanel, - func() error { return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) }, + func() error { return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) }, func() error { return gui.closeConfirmationPrompt(false) }, gui.createMenu, gui.withWaitingStatus, + gui.toast, + func() string { return gui.Views.Confirmation.TextArea.GetContent() }, ) - authors.SetCustomAuthors(gui.UserConfig.Gui.AuthorColors) - presentation.SetCustomBranches(gui.UserConfig.Gui.BranchColors) - guiCommon := &guiCommon{gui: gui, IPopupHandler: gui.PopupHandler} controllerCommon := &controllers.ControllerCommon{IGuiCommon: guiCommon, Common: cmn} + // storing this stuff on the gui for now to ease refactoring + // TODO: reset these controllers upon changing repos due to state changing + gui.c = controllerCommon + + gui.resetState(filterPath, false) + authors.SetCustomAuthors(gui.UserConfig.Gui.AuthorColors) + presentation.SetCustomBranches(gui.UserConfig.Gui.BranchColors) + + refHelper := NewRefHelper( + controllerCommon, + gui.git, + gui.State, + ) + gui.refHelper = refHelper + gui.suggestionsHelper = NewSuggestionsHelper(controllerCommon, gui.State, gui.refreshSuggestions) + gui.fileHelper = NewFileHelper(controllerCommon, gui.git, osCommand) + gui.workingTreeHelper = NewWorkingTreeHelper(gui.State.FileTreeViewModel) + + tagsController := controllers.NewTagsController( + controllerCommon, + gui.State.Contexts.Tags, + gui.git, + gui.State.Contexts, + refHelper, + gui.suggestionsHelper, + gui.getSelectedTag, + gui.switchToSubCommitsContext, + ) + + syncController := controllers.NewSyncController( + controllerCommon, + gui.git, + gui.getCheckedOutBranch, + gui.suggestionsHelper, + gui.getSuggestedRemote, + gui.checkMergeOrRebase, + ) + gui.Controllers = Controllers{ Submodules: controllers.NewSubmodulesController( controllerCommon, + gui.State.Contexts.Submodules, + gui.git, gui.enterSubmodule, - gui.Git, - gui.State.Submodules, gui.getSelectedSubmodule, ), + Files: controllers.NewFilesController( + controllerCommon, + gui.State.Contexts.Files, + gui.git, + osCommand, + gui.getSelectedFileNode, + gui.State.Contexts, + gui.State.FileTreeViewModel, + gui.enterSubmodule, + func() []*models.SubmoduleConfig { return gui.State.Submodules }, + gui.getSetTextareaTextFn(gui.Views.CommitMessage), + gui.withGpgHandling, + func() string { return gui.State.failedCommitMessage }, + func() []*models.Commit { return gui.State.Commits }, + gui.getSelectedPath, + gui.switchToMerge, + gui.suggestionsHelper, + gui.refHelper, + gui.fileHelper, + gui.workingTreeHelper, + ), + Tags: tagsController, + + LocalCommits: controllers.NewLocalCommitsController( + controllerCommon, + gui.State.Contexts.BranchCommits, + osCommand, + gui.git, + refHelper, + gui.getSelectedLocalCommit, + func() []*models.Commit { return gui.State.Commits }, + func() int { return gui.State.Panels.Commits.SelectedLineIdx }, + gui.checkMergeOrRebase, + syncController.HandlePull, + tagsController.CreateTagMenu, + gui.getHostingServiceMgr, + gui.SwitchToCommitFilesContext, + gui.handleOpenSearch, + func() bool { return gui.State.Panels.Commits.LimitCommits }, + func(value bool) { gui.State.Panels.Commits.LimitCommits = value }, + func() bool { return gui.ShowWholeGitGraph }, + func(value bool) { gui.ShowWholeGitGraph = value }, + ), + + Remotes: controllers.NewRemotesController( + controllerCommon, + gui.State.Contexts.Remotes, + gui.git, + gui.State.Contexts, + gui.getSelectedRemote, + func(branches []*models.RemoteBranch) { gui.State.RemoteBranches = branches }, + gui.Mutexes.FetchMutex, + ), + Menu: controllers.NewMenuController( + controllerCommon, + gui.State.Contexts.Menu, + gui.getSelectedMenuItem, + ), + Bisect: controllers.NewBisectController( + controllerCommon, + gui.State.Contexts.BranchCommits, + gui.git, + gui.getSelectedLocalCommit, + func() []*models.Commit { return gui.State.Commits }, + ), + Undo: controllers.NewUndoController( + controllerCommon, + gui.git, + refHelper, + gui.workingTreeHelper, + func() []*models.Commit { return gui.State.FilteredReflogCommits }, + ), + Sync: syncController, } return gui, nil @@ -621,7 +744,7 @@ func (gui *Gui) Run() error { } gui.waitForIntro.Add(1) - if gui.UserConfig.Git.AutoFetch { + if gui.c.UserConfig.Git.AutoFetch { go utils.Safe(gui.startBackgroundFetch) } @@ -629,7 +752,7 @@ func (gui *Gui) Run() error { g.SetManager(gocui.ManagerFunc(gui.layout), gocui.ManagerFunc(gui.getFocusLayout())) - gui.Log.Info("starting main loop") + gui.c.Log.Info("starting main loop") err = g.MainLoop() return err @@ -684,7 +807,7 @@ func (gui *Gui) runSubprocessWithSuspenseAndRefresh(subprocess oscommands.ICmdOb return err } - if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}); err != nil { + if err := gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil { return err } @@ -705,7 +828,7 @@ func (gui *Gui) runSubprocessWithSuspense(subprocess oscommands.ICmdObj) (bool, } if err := gui.g.Suspend(); err != nil { - return false, gui.PopupHandler.Error(err) + return false, gui.c.Error(err) } gui.PauseBackgroundThreads = true @@ -719,14 +842,14 @@ func (gui *Gui) runSubprocessWithSuspense(subprocess oscommands.ICmdObj) (bool, gui.PauseBackgroundThreads = false if cmdErr != nil { - return false, gui.PopupHandler.Error(cmdErr) + return false, gui.c.Error(cmdErr) } return true, nil } func (gui *Gui) runSubprocess(cmdObj oscommands.ICmdObj) error { //nolint:unparam - gui.logCommand(cmdObj.ToString(), true) + gui.LogCommand(cmdObj.ToString(), true) subprocess := cmdObj.GetCmd() subprocess.Stdout = os.Stdout @@ -754,7 +877,7 @@ func (gui *Gui) loadNewRepo() error { return err } - if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}); err != nil { + if err := gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil { return err } @@ -774,7 +897,7 @@ func (gui *Gui) showInitialPopups(tasks []func(chan struct{}) error) { task := task go utils.Safe(func() { if err := task(done); err != nil { - _ = gui.PopupHandler.Error(err) + _ = gui.c.Error(err) } }) @@ -787,13 +910,13 @@ func (gui *Gui) showInitialPopups(tasks []func(chan struct{}) error) { func (gui *Gui) showIntroPopupMessage(done chan struct{}) error { onConfirm := func() error { done <- struct{}{} - gui.Config.GetAppState().StartupPopupVersion = StartupPopupVersion - return gui.Config.SaveAppState() + gui.c.GetAppState().StartupPopupVersion = StartupPopupVersion + return gui.c.SaveAppState() } - return gui.PopupHandler.Ask(popup.AskOpts{ + return gui.c.Ask(popup.AskOpts{ Title: "", - Prompt: gui.Tr.IntroPopupMessage, + Prompt: gui.c.Tr.IntroPopupMessage, HandleConfirm: onConfirm, HandleClose: onConfirm, }) @@ -826,9 +949,9 @@ func (gui *Gui) startBackgroundFetch() { } err := gui.backgroundFetch() if err != nil && strings.Contains(err.Error(), "exit status 128") && isNew { - _ = gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.NoAutomaticGitFetchTitle, - Prompt: gui.Tr.NoAutomaticGitFetchBody, + _ = gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.NoAutomaticGitFetchTitle, + Prompt: gui.c.Tr.NoAutomaticGitFetchBody, }) } else { gui.goEvery(time.Second*time.Duration(userConfig.Refresher.FetchInterval), gui.stopChan, func() error { diff --git a/pkg/gui/gui_common.go b/pkg/gui/gui_common.go new file mode 100644 index 000000000..8db398489 --- /dev/null +++ b/pkg/gui/gui_common.go @@ -0,0 +1,53 @@ +package gui + +import ( + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/controllers" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +// hacking this by including the gui struct for now until we split more things out +type guiCommon struct { + gui *Gui + popup.IPopupHandler +} + +var _ controllers.IGuiCommon = &guiCommon{} + +func (self *guiCommon) LogAction(msg string) { + self.gui.LogAction(msg) +} + +func (self *guiCommon) LogCommand(cmdStr string, isCommandLine bool) { + self.gui.LogCommand(cmdStr, isCommandLine) +} + +func (self *guiCommon) Refresh(opts types.RefreshOptions) error { + return self.gui.Refresh(opts) +} + +func (self *guiCommon) PostRefreshUpdate(context types.Context) error { + return self.gui.postRefreshUpdate(context) +} + +func (self *guiCommon) RunSubprocessAndRefresh(cmdObj oscommands.ICmdObj) error { + return self.gui.runSubprocessWithSuspenseAndRefresh(cmdObj) +} + +func (self *guiCommon) PushContext(context types.Context, opts ...types.OnFocusOpts) error { + return self.gui.pushContext(context, opts...) +} + +func (self *guiCommon) PopContext() error { + return self.gui.returnFromContext() +} + +func (self *guiCommon) GetAppState() *config.AppState { + return self.gui.Config.GetAppState() +} + +func (self *guiCommon) SaveAppState() error { + return self.gui.Config.SaveAppState() +} diff --git a/pkg/gui/information_panel.go b/pkg/gui/information_panel.go index d09f495c5..07e64fb42 100644 --- a/pkg/gui/information_panel.go +++ b/pkg/gui/information_panel.go @@ -15,8 +15,8 @@ func (gui *Gui) informationStr() string { } if gui.g.Mouse { - donate := style.FgMagenta.SetUnderline().Sprint(gui.Tr.Donate) - askQuestion := style.FgYellow.SetUnderline().Sprint(gui.Tr.AskQuestion) + donate := style.FgMagenta.SetUnderline().Sprint(gui.c.Tr.Donate) + askQuestion := style.FgYellow.SetUnderline().Sprint(gui.c.Tr.AskQuestion) return fmt.Sprintf("%s %s %s", donate, askQuestion, gui.Config.GetVersion()) } else { return gui.Config.GetVersion() @@ -35,7 +35,7 @@ func (gui *Gui) handleInfoClick() error { for _, mode := range gui.modeStatuses() { if mode.isActive() { - if width-cx > len(gui.Tr.ResetInParentheses) { + if width-cx > len(gui.c.Tr.ResetInParentheses) { return nil } return mode.reset() @@ -43,9 +43,9 @@ func (gui *Gui) handleInfoClick() error { } // if we're not in an active mode we show the donate button - if cx <= len(gui.Tr.Donate) { + if cx <= len(gui.c.Tr.Donate) { return gui.OSCommand.OpenLink(constants.Links.Donate) - } else if cx <= len(gui.Tr.Donate)+1+len(gui.Tr.AskQuestion) { + } else if cx <= len(gui.c.Tr.Donate)+1+len(gui.c.Tr.AskQuestion) { return gui.OSCommand.OpenLink(constants.Links.Discussions) } return nil diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 644e4560b..2f7e478b3 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -183,9 +183,24 @@ func (gui *Gui) getKey(key string) interface{} { return nil } +func (gui *Gui) noPopupPanel(f func() error) func() error { + return func() error { + if gui.popupPanelFocused() { + return nil + } + + return f() + } +} + // GetInitialKeybindings is a function. func (gui *Gui) GetInitialKeybindings() []*types.Binding { - config := gui.UserConfig.Keybinding + config := gui.c.UserConfig.Keybinding + + guards := types.KeybindingGuards{ + OutsideFilterMode: gui.outsideFilterMode, + NoPopupPanel: gui.noPopupPanel, + } bindings := []*types.Binding{ { @@ -217,21 +232,21 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Key: gui.getKey(config.Universal.OpenRecentRepos), Handler: gui.handleCreateRecentReposMenu, Alternative: " ", - Description: gui.Tr.SwitchRepo, + Description: gui.c.Tr.SwitchRepo, }, { ViewName: "", Key: gui.getKey(config.Universal.ScrollUpMain), Handler: gui.scrollUpMain, Alternative: "fn+up", - Description: gui.Tr.LcScrollUpMainPanel, + Description: gui.c.Tr.LcScrollUpMainPanel, }, { ViewName: "", Key: gui.getKey(config.Universal.ScrollDownMain), Handler: gui.scrollDownMain, Alternative: "fn+down", - Description: gui.Tr.LcScrollDownMainPanel, + Description: gui.c.Tr.LcScrollDownMainPanel, }, { ViewName: "", @@ -261,39 +276,27 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { ViewName: "", Key: gui.getKey(config.Universal.CreateRebaseOptionsMenu), Handler: gui.handleCreateRebaseOptionsMenu, - Description: gui.Tr.ViewMergeRebaseOptions, + Description: gui.c.Tr.ViewMergeRebaseOptions, OpensMenu: true, }, { ViewName: "", Key: gui.getKey(config.Universal.CreatePatchOptionsMenu), Handler: gui.handleCreatePatchOptionsMenu, - Description: gui.Tr.ViewPatchOptions, + Description: gui.c.Tr.ViewPatchOptions, OpensMenu: true, }, - { - ViewName: "", - Key: gui.getKey(config.Universal.PushFiles), - Handler: gui.pushFiles, - Description: gui.Tr.LcPush, - }, - { - ViewName: "", - Key: gui.getKey(config.Universal.PullFiles), - Handler: gui.handlePullFiles, - Description: gui.Tr.LcPull, - }, { ViewName: "", Key: gui.getKey(config.Universal.Refresh), Handler: gui.handleRefresh, - Description: gui.Tr.LcRefresh, + Description: gui.c.Tr.LcRefresh, }, { ViewName: "", Key: gui.getKey(config.Universal.OptionMenu), Handler: gui.handleCreateOptionsMenu, - Description: gui.Tr.LcOpenMenu, + Description: gui.c.Tr.LcOpenMenu, OpensMenu: true, }, { @@ -308,236 +311,98 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Modifier: gocui.ModNone, Handler: gui.handleCreateOptionsMenu, }, - { - ViewName: "", - Key: gui.getKey(config.Universal.Undo), - Handler: gui.reflogUndo, - Description: gui.Tr.LcUndoReflog, - }, - { - ViewName: "", - Key: gui.getKey(config.Universal.Redo), - Handler: gui.reflogRedo, - Description: gui.Tr.LcRedoReflog, - }, { ViewName: "status", Key: gui.getKey(config.Universal.Edit), Handler: gui.handleEditConfig, - Description: gui.Tr.EditConfig, + Description: gui.c.Tr.EditConfig, }, { ViewName: "", Key: gui.getKey(config.Universal.NextScreenMode), Handler: gui.nextScreenMode, - Description: gui.Tr.LcNextScreenMode, + Description: gui.c.Tr.LcNextScreenMode, }, { ViewName: "", Key: gui.getKey(config.Universal.PrevScreenMode), Handler: gui.prevScreenMode, - Description: gui.Tr.LcPrevScreenMode, + Description: gui.c.Tr.LcPrevScreenMode, }, { ViewName: "status", Key: gui.getKey(config.Universal.OpenFile), Handler: gui.handleOpenConfig, - Description: gui.Tr.OpenConfig, + Description: gui.c.Tr.OpenConfig, }, { ViewName: "status", Key: gui.getKey(config.Status.CheckForUpdate), Handler: gui.handleCheckForUpdate, - Description: gui.Tr.LcCheckForUpdate, + Description: gui.c.Tr.LcCheckForUpdate, }, { ViewName: "status", Key: gui.getKey(config.Status.RecentRepos), Handler: gui.handleCreateRecentReposMenu, - Description: gui.Tr.SwitchRepo, + Description: gui.c.Tr.SwitchRepo, }, { ViewName: "status", Key: gui.getKey(config.Status.AllBranchesLogGraph), Handler: gui.handleShowAllBranchLogs, - Description: gui.Tr.LcAllBranchesLogGraph, - }, - { - ViewName: "files", - Key: gui.getKey(" "), - Handler: gui.handleStatusFilterPressed, - Description: gui.Tr.LcCommitFileFilter, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.CommitChanges), - Handler: gui.handleCommitPress, - Description: gui.Tr.CommitChanges, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.CommitChangesWithoutHook), - Handler: gui.handleWIPCommitPress, - Description: gui.Tr.LcCommitChangesWithoutHook, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.AmendLastCommit), - Handler: gui.handleAmendCommitPress, - Description: gui.Tr.AmendLastCommit, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.CommitChangesWithEditor), - Handler: gui.handleCommitEditorPress, - Description: gui.Tr.CommitChangesWithEditor, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Select), - Handler: gui.handleFilePress, - Description: gui.Tr.LcToggleStaged, + Description: gui.c.Tr.LcAllBranchesLogGraph, }, { ViewName: "files", Contexts: []string{string(FILES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Remove), Handler: gui.handleCreateDiscardMenu, - Description: gui.Tr.LcViewDiscardOptions, + Description: gui.c.Tr.LcViewDiscardOptions, OpensMenu: true, }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Edit), - Handler: gui.handleFileEdit, - Description: gui.Tr.LcEditFile, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.OpenFile), - Handler: gui.handleFileOpen, - Description: gui.Tr.LcOpenFile, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.IgnoreFile), - Handler: gui.handleIgnoreFile, - Description: gui.Tr.LcIgnoreFile, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.RefreshFiles), - Handler: gui.handleRefreshFiles, - Description: gui.Tr.LcRefreshFiles, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.StashAllChanges), - Handler: gui.handleStashChanges, - Description: gui.Tr.LcStashAllChanges, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.ViewStashOptions), - Handler: gui.handleCreateStashMenu, - Description: gui.Tr.LcViewStashOptions, - OpensMenu: true, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.ToggleStagedAll), - Handler: gui.handleStageAll, - Description: gui.Tr.LcToggleStagedAll, - }, { ViewName: "files", Contexts: []string{string(FILES_CONTEXT_KEY)}, Key: gui.getKey(config.Files.ViewResetOptions), Handler: gui.handleCreateResetMenu, - Description: gui.Tr.LcViewResetOptions, + Description: gui.c.Tr.LcViewResetOptions, OpensMenu: true, }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.GoInto), - Handler: gui.handleEnterFile, - Description: gui.Tr.FileEnter, - }, { ViewName: "files", Contexts: []string{string(FILES_CONTEXT_KEY)}, Key: gui.getKey(config.Files.Fetch), Handler: gui.handleGitFetch, - Description: gui.Tr.LcFetch, + Description: gui.c.Tr.LcFetch, }, { ViewName: "files", Contexts: []string{string(FILES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.Tr.LcCopyFileNameToClipboard, - }, - { - ViewName: "", - Key: gui.getKey(config.Universal.ExecuteCustomCommand), - Handler: gui.handleCustomCommand, - Description: gui.Tr.LcExecuteCustomCommand, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.ViewResetOptions), - Handler: gui.handleCreateResetToUpstreamMenu, - Description: gui.Tr.LcViewResetToUpstreamOptions, - OpensMenu: true, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.ToggleTreeView), - Handler: gui.handleToggleFileTreeView, - Description: gui.Tr.LcToggleTreeView, - }, - { - ViewName: "files", - Contexts: []string{string(FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.OpenMergeTool), - Handler: gui.handleOpenMergeTool, - Description: gui.Tr.LcOpenMergeTool, + Description: gui.c.Tr.LcCopyFileNameToClipboard, }, { ViewName: "branches", Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Select), Handler: gui.handleBranchPress, - Description: gui.Tr.LcCheckout, + Description: gui.c.Tr.LcCheckout, }, { ViewName: "branches", Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Branches.CreatePullRequest), Handler: gui.handleCreatePullRequestPress, - Description: gui.Tr.LcCreatePullRequest, + Description: gui.c.Tr.LcCreatePullRequest, }, { ViewName: "branches", Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Branches.ViewPullRequestOptions), Handler: gui.handleCreatePullRequestMenu, - Description: gui.Tr.LcCreatePullRequestOptions, + Description: gui.c.Tr.LcCreatePullRequestOptions, OpensMenu: true, }, { @@ -545,56 +410,56 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Branches.CopyPullRequestURL), Handler: gui.handleCopyPullRequestURLPress, - Description: gui.Tr.LcCopyPullRequestURL, + Description: gui.c.Tr.LcCopyPullRequestURL, }, { ViewName: "branches", Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Branches.CheckoutBranchByName), Handler: gui.handleCheckoutByName, - Description: gui.Tr.LcCheckoutByName, + Description: gui.c.Tr.LcCheckoutByName, }, { ViewName: "branches", Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Branches.ForceCheckoutBranch), Handler: gui.handleForceCheckout, - Description: gui.Tr.LcForceCheckout, + Description: gui.c.Tr.LcForceCheckout, }, { ViewName: "branches", Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.New), Handler: gui.handleNewBranchOffCurrentItem, - Description: gui.Tr.LcNewBranch, + Description: gui.c.Tr.LcNewBranch, }, { ViewName: "branches", Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Remove), Handler: gui.handleDeleteBranch, - Description: gui.Tr.LcDeleteBranch, + Description: gui.c.Tr.LcDeleteBranch, }, { ViewName: "branches", Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Branches.RebaseBranch), - Handler: gui.handleRebaseOntoLocalBranch, - Description: gui.Tr.LcRebaseBranch, + Handler: guards.OutsideFilterMode(gui.handleRebaseOntoLocalBranch), + Description: gui.c.Tr.LcRebaseBranch, }, { ViewName: "branches", Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Branches.MergeIntoCurrentBranch), - Handler: gui.handleMerge, - Description: gui.Tr.LcMergeIntoCurrentBranch, + Handler: guards.OutsideFilterMode(gui.handleMerge), + Description: gui.c.Tr.LcMergeIntoCurrentBranch, }, { ViewName: "branches", Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Branches.ViewGitFlowOptions), Handler: gui.handleCreateGitFlowMenu, - Description: gui.Tr.LcGitFlowOptions, + Description: gui.c.Tr.LcGitFlowOptions, OpensMenu: true, }, { @@ -602,14 +467,14 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Branches.FastForward), Handler: gui.handleFastForward, - Description: gui.Tr.FastForward, + Description: gui.c.Tr.FastForward, }, { ViewName: "branches", Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.ViewResetOptions), Handler: gui.handleCreateResetToBranchMenu, - Description: gui.Tr.LcViewResetOptions, + Description: gui.c.Tr.LcViewResetOptions, OpensMenu: true, }, { @@ -617,78 +482,35 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Branches.RenameBranch), Handler: gui.handleRenameBranch, - Description: gui.Tr.LcRenameBranch, + Description: gui.c.Tr.LcRenameBranch, }, { ViewName: "branches", Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.Tr.LcCopyBranchNameToClipboard, + Description: gui.c.Tr.LcCopyBranchNameToClipboard, }, { ViewName: "branches", Contexts: []string{string(LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.GoInto), Handler: gui.handleSwitchToSubCommits, - Description: gui.Tr.LcViewCommits, - }, - { - ViewName: "branches", - Contexts: []string{string(TAGS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Select), - Handler: gui.withSelectedTag(gui.handleCheckoutTag), - Description: gui.Tr.LcCheckout, - }, - { - ViewName: "branches", - Contexts: []string{string(TAGS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Remove), - Handler: gui.withSelectedTag(gui.handleDeleteTag), - Description: gui.Tr.LcDeleteTag, - }, - { - ViewName: "branches", - Contexts: []string{string(TAGS_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.PushTag), - Handler: gui.withSelectedTag(gui.handlePushTag), - Description: gui.Tr.LcPushTag, - }, - { - ViewName: "branches", - Contexts: []string{string(TAGS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.New), - Handler: gui.handleCreateTag, - Description: gui.Tr.LcCreateTag, - }, - { - ViewName: "branches", - Contexts: []string{string(TAGS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.ViewResetOptions), - Handler: gui.withSelectedTag(gui.handleCreateResetToTagMenu), - Description: gui.Tr.LcViewResetOptions, - OpensMenu: true, - }, - { - ViewName: "branches", - Contexts: []string{string(TAGS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.GoInto), - Handler: gui.handleSwitchToSubCommits, - Description: gui.Tr.LcViewCommits, + Description: gui.c.Tr.LcViewCommits, }, { ViewName: "branches", Contexts: []string{string(REMOTE_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Return), Handler: gui.handleRemoteBranchesEscape, - Description: gui.Tr.ReturnToRemotesList, + Description: gui.c.Tr.ReturnToRemotesList, }, { ViewName: "branches", Contexts: []string{string(REMOTE_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.ViewResetOptions), Handler: gui.handleCreateResetToRemoteBranchMenu, - Description: gui.Tr.LcViewResetOptions, + Description: gui.c.Tr.LcViewResetOptions, OpensMenu: true, }, { @@ -696,162 +518,35 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(REMOTE_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.GoInto), Handler: gui.handleSwitchToSubCommits, - Description: gui.Tr.LcViewCommits, - }, - { - ViewName: "branches", - Contexts: []string{string(REMOTES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.FetchRemote), - Handler: gui.handleFetchRemote, - Description: gui.Tr.LcFetchRemote, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.OpenLogMenu), - Handler: gui.handleOpenLogMenu, - Description: gui.Tr.LcOpenLogMenu, - OpensMenu: true, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.SquashDown), - Handler: gui.handleCommitSquashDown, - Description: gui.Tr.LcSquashDown, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.RenameCommit), - Handler: gui.handleRewordCommit, - Description: gui.Tr.LcRewordCommit, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.RenameCommitWithEditor), - Handler: gui.handleRewordCommitEditor, - Description: gui.Tr.LcRenameCommitEditor, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.ViewResetOptions), - Handler: gui.handleCreateCommitResetMenu, - Description: gui.Tr.LcResetToThisCommit, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.MarkCommitAsFixup), - Handler: gui.handleCommitFixup, - Description: gui.Tr.LcFixupCommit, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.CreateFixupCommit), - Handler: gui.handleCreateFixupCommit, - Description: gui.Tr.LcCreateFixupCommit, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.SquashAboveCommits), - Handler: gui.handleSquashAllAboveFixupCommits, - Description: gui.Tr.LcSquashAboveCommits, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Remove), - Handler: gui.handleCommitDelete, - Description: gui.Tr.LcDeleteCommit, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.MoveDownCommit), - Handler: gui.handleCommitMoveDown, - Description: gui.Tr.LcMoveDownCommit, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.MoveUpCommit), - Handler: gui.handleCommitMoveUp, - Description: gui.Tr.LcMoveUpCommit, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Edit), - Handler: gui.handleCommitEdit, - Description: gui.Tr.LcEditCommit, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.AmendToCommit), - Handler: gui.handleCommitAmendTo, - Description: gui.Tr.LcAmendToCommit, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.PickCommit), - Handler: gui.handleCommitPick, - Description: gui.Tr.LcPickCommit, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.RevertCommit), - Handler: gui.handleCommitRevert, - Description: gui.Tr.LcRevertCommit, + Description: gui.c.Tr.LcViewCommits, }, { ViewName: "commits", Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.CherryPickCopy), Handler: gui.handleCopyCommit, - Description: gui.Tr.LcCherryPickCopy, + Description: gui.c.Tr.LcCherryPickCopy, }, { ViewName: "commits", Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.Tr.LcCopyCommitShaToClipboard, + Description: gui.c.Tr.LcCopyCommitShaToClipboard, }, { ViewName: "commits", Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.CherryPickCopyRange), Handler: gui.handleCopyCommitRange, - Description: gui.Tr.LcCherryPickCopyRange, + Description: gui.c.Tr.LcCherryPickCopyRange, }, { ViewName: "commits", Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.PasteCommits), - Handler: gui.HandlePasteCommits, - Description: gui.Tr.LcPasteCommits, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.GoInto), - Handler: gui.handleViewCommitFiles, - Description: gui.Tr.LcViewCommitFiles, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.CheckoutCommit), - Handler: gui.handleCheckoutCommit, - Description: gui.Tr.LcCheckoutCommit, + Handler: guards.OutsideFilterMode(gui.HandlePasteCommits), + Description: gui.c.Tr.LcPasteCommits, }, { ViewName: "commits", @@ -859,114 +554,85 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Key: gui.getKey(config.Universal.New), Modifier: gocui.ModNone, Handler: gui.handleNewBranchOffCurrentItem, - Description: gui.Tr.LcCreateNewBranchFromCommit, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.TagCommit), - Handler: gui.handleTagCommit, - Description: gui.Tr.LcTagCommit, + Description: gui.c.Tr.LcCreateNewBranchFromCommit, }, { ViewName: "commits", Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.ResetCherryPick), Handler: gui.exitCherryPickingMode, - Description: gui.Tr.LcResetCherryPick, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.CopyCommitMessageToClipboard), - Handler: gui.handleCopySelectedCommitMessageToClipboard, - Description: gui.Tr.LcCopyCommitMessageToClipboard, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.OpenInBrowser), - Handler: gui.handleOpenCommitInBrowser, - Description: gui.Tr.LcOpenCommitInBrowser, - }, - { - ViewName: "commits", - Contexts: []string{string(BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.ViewBisectOptions), - Handler: gui.handleOpenBisectMenu, - Description: gui.Tr.LcViewBisectOptions, - OpensMenu: true, + Description: gui.c.Tr.LcResetCherryPick, }, { ViewName: "commits", Contexts: []string{string(REFLOG_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.GoInto), Handler: gui.handleViewReflogCommitFiles, - Description: gui.Tr.LcViewCommitFiles, + Description: gui.c.Tr.LcViewCommitFiles, }, { ViewName: "commits", Contexts: []string{string(REFLOG_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Select), - Handler: gui.handleCheckoutReflogCommit, - Description: gui.Tr.LcCheckoutCommit, + Handler: gui.CheckoutReflogCommit, + Description: gui.c.Tr.LcCheckoutCommit, }, { ViewName: "commits", Contexts: []string{string(REFLOG_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.ViewResetOptions), Handler: gui.handleCreateReflogResetMenu, - Description: gui.Tr.LcViewResetOptions, + Description: gui.c.Tr.LcViewResetOptions, OpensMenu: true, }, { ViewName: "commits", Contexts: []string{string(REFLOG_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.CherryPickCopy), - Handler: gui.handleCopyCommit, - Description: gui.Tr.LcCherryPickCopy, + Handler: guards.OutsideFilterMode(gui.handleCopyCommit), + Description: gui.c.Tr.LcCherryPickCopy, }, { ViewName: "commits", Contexts: []string{string(REFLOG_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.CherryPickCopyRange), - Handler: gui.handleCopyCommitRange, - Description: gui.Tr.LcCherryPickCopyRange, + Handler: guards.OutsideFilterMode(gui.handleCopyCommitRange), + Description: gui.c.Tr.LcCherryPickCopyRange, }, { ViewName: "commits", Contexts: []string{string(REFLOG_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.ResetCherryPick), Handler: gui.exitCherryPickingMode, - Description: gui.Tr.LcResetCherryPick, + Description: gui.c.Tr.LcResetCherryPick, }, { ViewName: "commits", Contexts: []string{string(REFLOG_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.Tr.LcCopyCommitShaToClipboard, + Description: gui.c.Tr.LcCopyCommitShaToClipboard, }, { ViewName: "branches", Contexts: []string{string(SUB_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.GoInto), Handler: gui.handleViewSubCommitFiles, - Description: gui.Tr.LcViewCommitFiles, + Description: gui.c.Tr.LcViewCommitFiles, }, { ViewName: "branches", Contexts: []string{string(SUB_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Select), Handler: gui.handleCheckoutSubCommit, - Description: gui.Tr.LcCheckoutCommit, + Description: gui.c.Tr.LcCheckoutCommit, }, { ViewName: "branches", Contexts: []string{string(SUB_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.ViewResetOptions), Handler: gui.handleCreateSubCommitResetMenu, - Description: gui.Tr.LcViewResetOptions, + Description: gui.c.Tr.LcViewResetOptions, OpensMenu: true, }, { @@ -974,65 +640,65 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(SUB_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.New), Handler: gui.handleNewBranchOffCurrentItem, - Description: gui.Tr.LcNewBranch, + Description: gui.c.Tr.LcNewBranch, }, { ViewName: "branches", Contexts: []string{string(SUB_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.CherryPickCopy), Handler: gui.handleCopyCommit, - Description: gui.Tr.LcCherryPickCopy, + Description: gui.c.Tr.LcCherryPickCopy, }, { ViewName: "branches", Contexts: []string{string(SUB_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.CherryPickCopyRange), Handler: gui.handleCopyCommitRange, - Description: gui.Tr.LcCherryPickCopyRange, + Description: gui.c.Tr.LcCherryPickCopyRange, }, { ViewName: "branches", Contexts: []string{string(SUB_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.ResetCherryPick), Handler: gui.exitCherryPickingMode, - Description: gui.Tr.LcResetCherryPick, + Description: gui.c.Tr.LcResetCherryPick, }, { ViewName: "branches", Contexts: []string{string(SUB_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.Tr.LcCopyCommitShaToClipboard, + Description: gui.c.Tr.LcCopyCommitShaToClipboard, }, { ViewName: "stash", Key: gui.getKey(config.Universal.GoInto), Handler: gui.handleViewStashFiles, - Description: gui.Tr.LcViewStashFiles, + Description: gui.c.Tr.LcViewStashFiles, }, { ViewName: "stash", Key: gui.getKey(config.Universal.Select), Handler: gui.handleStashApply, - Description: gui.Tr.LcApply, + Description: gui.c.Tr.LcApply, }, { ViewName: "stash", Key: gui.getKey(config.Stash.PopStash), Handler: gui.handleStashPop, - Description: gui.Tr.LcPop, + Description: gui.c.Tr.LcPop, }, { ViewName: "stash", Key: gui.getKey(config.Universal.Remove), Handler: gui.handleStashDrop, - Description: gui.Tr.LcDrop, + Description: gui.c.Tr.LcDrop, }, { ViewName: "stash", Key: gui.getKey(config.Universal.New), Handler: gui.handleNewBranchOffCurrentItem, - Description: gui.Tr.LcNewBranch, + Description: gui.c.Tr.LcNewBranch, }, { ViewName: "commitMessage", @@ -1062,7 +728,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { ViewName: "menu", Key: gui.getKey(config.Universal.Return), Handler: gui.handleMenuClose, - Description: gui.Tr.LcCloseMenu, + Description: gui.c.Tr.LcCloseMenu, }, { ViewName: "information", @@ -1074,76 +740,76 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { ViewName: "commitFiles", Key: gui.getKey(config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.Tr.LcCopyCommitFileNameToClipboard, + Description: gui.c.Tr.LcCopyCommitFileNameToClipboard, }, { ViewName: "commitFiles", Key: gui.getKey(config.CommitFiles.CheckoutCommitFile), Handler: gui.handleCheckoutCommitFile, - Description: gui.Tr.LcCheckoutCommitFile, + Description: gui.c.Tr.LcCheckoutCommitFile, }, { ViewName: "commitFiles", Key: gui.getKey(config.Universal.Remove), Handler: gui.handleDiscardOldFileChange, - Description: gui.Tr.LcDiscardOldFileChange, + Description: gui.c.Tr.LcDiscardOldFileChange, }, { ViewName: "commitFiles", Key: gui.getKey(config.Universal.OpenFile), Handler: gui.handleOpenOldCommitFile, - Description: gui.Tr.LcOpenFile, + Description: gui.c.Tr.LcOpenFile, }, { ViewName: "commitFiles", Key: gui.getKey(config.Universal.Edit), Handler: gui.handleEditCommitFile, - Description: gui.Tr.LcEditFile, + Description: gui.c.Tr.LcEditFile, }, { ViewName: "commitFiles", Key: gui.getKey(config.Universal.Select), Handler: gui.handleToggleFileForPatch, - Description: gui.Tr.LcToggleAddToPatch, + Description: gui.c.Tr.LcToggleAddToPatch, }, { ViewName: "commitFiles", Key: gui.getKey(config.Universal.GoInto), Handler: gui.handleEnterCommitFile, - Description: gui.Tr.LcEnterFile, + Description: gui.c.Tr.LcEnterFile, }, { ViewName: "commitFiles", Key: gui.getKey(config.Files.ToggleTreeView), Handler: gui.handleToggleCommitFileTreeView, - Description: gui.Tr.LcToggleTreeView, + Description: gui.c.Tr.LcToggleTreeView, }, { ViewName: "", Key: gui.getKey(config.Universal.FilteringMenu), Handler: gui.handleCreateFilteringMenuPanel, - Description: gui.Tr.LcOpenFilteringMenu, + Description: gui.c.Tr.LcOpenFilteringMenu, OpensMenu: true, }, { ViewName: "", Key: gui.getKey(config.Universal.DiffingMenu), Handler: gui.handleCreateDiffingMenuPanel, - Description: gui.Tr.LcOpenDiffingMenu, + Description: gui.c.Tr.LcOpenDiffingMenu, OpensMenu: true, }, { ViewName: "", Key: gui.getKey(config.Universal.DiffingMenuAlt), Handler: gui.handleCreateDiffingMenuPanel, - Description: gui.Tr.LcOpenDiffingMenu, + Description: gui.c.Tr.LcOpenDiffingMenu, OpensMenu: true, }, { ViewName: "", Key: gui.getKey(config.Universal.ExtrasMenu), Handler: gui.handleCreateExtrasMenuPanel, - Description: gui.Tr.LcOpenExtrasMenu, + Description: gui.c.Tr.LcOpenExtrasMenu, OpensMenu: true, }, { @@ -1170,7 +836,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(MAIN_NORMAL_CONTEXT_KEY)}, Key: gocui.MouseWheelDown, Handler: gui.scrollDownMain, - Description: gui.Tr.ScrollDown, + Description: gui.c.Tr.ScrollDown, Alternative: "fn+up", }, { @@ -1178,7 +844,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(MAIN_NORMAL_CONTEXT_KEY)}, Key: gocui.MouseWheelUp, Handler: gui.scrollUpMain, - Description: gui.Tr.ScrollUp, + Description: gui.c.Tr.ScrollUp, Alternative: "fn+down", }, { @@ -1200,56 +866,56 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Return), Handler: gui.handleStagingEscape, - Description: gui.Tr.ReturnToFilesPanel, + Description: gui.c.Tr.ReturnToFilesPanel, }, { ViewName: "main", Contexts: []string{string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Select), Handler: gui.handleToggleStagedSelection, - Description: gui.Tr.StageSelection, + Description: gui.c.Tr.StageSelection, }, { ViewName: "main", Contexts: []string{string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Remove), Handler: gui.handleResetSelection, - Description: gui.Tr.ResetSelection, + Description: gui.c.Tr.ResetSelection, }, { ViewName: "main", Contexts: []string{string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.TogglePanel), Handler: gui.handleTogglePanel, - Description: gui.Tr.TogglePanel, + Description: gui.c.Tr.TogglePanel, }, { ViewName: "main", Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Return), Handler: gui.handleEscapePatchBuildingPanel, - Description: gui.Tr.ExitLineByLineMode, + Description: gui.c.Tr.ExitLineByLineMode, }, { ViewName: "main", Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY), string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.OpenFile), Handler: gui.handleOpenFileAtLine, - Description: gui.Tr.LcOpenFile, + Description: gui.c.Tr.LcOpenFile, }, { ViewName: "main", Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY), string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.PrevItem), Handler: gui.handleSelectPrevLine, - Description: gui.Tr.PrevLine, + Description: gui.c.Tr.PrevLine, }, { ViewName: "main", Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY), string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.NextItem), Handler: gui.handleSelectNextLine, - Description: gui.Tr.NextLine, + Description: gui.c.Tr.NextLine, }, { ViewName: "main", @@ -1284,7 +950,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY), string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.PrevBlock), Handler: gui.handleSelectPrevHunk, - Description: gui.Tr.PrevHunk, + Description: gui.c.Tr.PrevHunk, }, { ViewName: "main", @@ -1298,7 +964,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY), string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.NextBlock), Handler: gui.handleSelectNextHunk, - Description: gui.Tr.NextHunk, + Description: gui.c.Tr.NextHunk, }, { ViewName: "main", @@ -1313,21 +979,21 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Key: gui.getKey(config.Universal.CopyToClipboard), Modifier: gocui.ModNone, Handler: gui.copySelectedToClipboard, - Description: gui.Tr.LcCopySelectedTexToClipboard, + Description: gui.c.Tr.LcCopySelectedTexToClipboard, }, { ViewName: "main", Contexts: []string{string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Edit), Handler: gui.handleLineByLineEdit, - Description: gui.Tr.LcEditFile, + Description: gui.c.Tr.LcEditFile, }, { ViewName: "main", Contexts: []string{string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.OpenFile), - Handler: gui.handleFileOpen, - Description: gui.Tr.LcOpenFile, + Handler: gui.Controllers.Files.Open, + Description: gui.c.Tr.LcOpenFile, }, { ViewName: "main", @@ -1335,7 +1001,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Key: gui.getKey(config.Universal.NextPage), Modifier: gocui.ModNone, Handler: gui.handleLineByLineNextPage, - Description: gui.Tr.LcNextPage, + Description: gui.c.Tr.LcNextPage, Tag: "navigation", }, { @@ -1344,7 +1010,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Key: gui.getKey(config.Universal.PrevPage), Modifier: gocui.ModNone, Handler: gui.handleLineByLinePrevPage, - Description: gui.Tr.LcPrevPage, + Description: gui.c.Tr.LcPrevPage, Tag: "navigation", }, { @@ -1353,7 +1019,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Key: gui.getKey(config.Universal.GotoTop), Modifier: gocui.ModNone, Handler: gui.handleLineByLineGotoTop, - Description: gui.Tr.LcGotoTop, + Description: gui.c.Tr.LcGotoTop, Tag: "navigation", }, { @@ -1362,7 +1028,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Key: gui.getKey(config.Universal.GotoBottom), Modifier: gocui.ModNone, Handler: gui.handleLineByLineGotoBottom, - Description: gui.Tr.LcGotoBottom, + Description: gui.c.Tr.LcGotoBottom, Tag: "navigation", }, { @@ -1370,7 +1036,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY), string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.StartSearch), Handler: func() error { return gui.handleOpenSearch("main") }, - Description: gui.Tr.LcStartSearch, + Description: gui.c.Tr.LcStartSearch, Tag: "navigation", }, { @@ -1378,14 +1044,14 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Select), Handler: gui.handleToggleSelectionForPatch, - Description: gui.Tr.ToggleSelectionForPatch, + Description: gui.c.Tr.ToggleSelectionForPatch, }, { ViewName: "main", Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY), string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Main.ToggleDragSelect), Handler: gui.handleToggleSelectRange, - Description: gui.Tr.ToggleDragSelect, + Description: gui.c.Tr.ToggleDragSelect, }, // Alias 'V' -> 'v' { @@ -1393,14 +1059,14 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY), string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Main.ToggleDragSelectAlt), Handler: gui.handleToggleSelectRange, - Description: gui.Tr.ToggleDragSelect, + Description: gui.c.Tr.ToggleDragSelect, }, { ViewName: "main", Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY), string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Main.ToggleSelectHunk), Handler: gui.handleToggleSelectHunk, - Description: gui.Tr.ToggleSelectHunk, + Description: gui.c.Tr.ToggleSelectHunk, }, { ViewName: "main", @@ -1435,91 +1101,91 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY), string(MAIN_STAGING_CONTEXT_KEY), string(MAIN_MERGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.ScrollLeft), Handler: gui.scrollLeftMain, - Description: gui.Tr.LcScrollLeft, + Description: gui.c.Tr.LcScrollLeft, }, { ViewName: "main", Contexts: []string{string(MAIN_PATCH_BUILDING_CONTEXT_KEY), string(MAIN_STAGING_CONTEXT_KEY), string(MAIN_MERGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.ScrollRight), Handler: gui.scrollRightMain, - Description: gui.Tr.LcScrollRight, + Description: gui.c.Tr.LcScrollRight, }, { ViewName: "main", Contexts: []string{string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Files.CommitChanges), - Handler: gui.handleCommitPress, - Description: gui.Tr.CommitChanges, + Handler: gui.Controllers.Files.HandleCommitPress, + Description: gui.c.Tr.CommitChanges, }, { ViewName: "main", Contexts: []string{string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Files.CommitChangesWithoutHook), - Handler: gui.handleWIPCommitPress, - Description: gui.Tr.LcCommitChangesWithoutHook, + Handler: gui.Controllers.Files.HandleWIPCommitPress, + Description: gui.c.Tr.LcCommitChangesWithoutHook, }, { ViewName: "main", Contexts: []string{string(MAIN_STAGING_CONTEXT_KEY)}, Key: gui.getKey(config.Files.CommitChangesWithEditor), - Handler: gui.handleCommitEditorPress, - Description: gui.Tr.CommitChangesWithEditor, + Handler: gui.Controllers.Files.HandleCommitEditorPress, + Description: gui.c.Tr.CommitChangesWithEditor, }, { ViewName: "main", Contexts: []string{string(MAIN_MERGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Return), Handler: gui.handleEscapeMerge, - Description: gui.Tr.ReturnToFilesPanel, + Description: gui.c.Tr.ReturnToFilesPanel, }, { ViewName: "main", Contexts: []string{string(MAIN_MERGING_CONTEXT_KEY)}, Key: gui.getKey(config.Files.OpenMergeTool), - Handler: gui.handleOpenMergeTool, - Description: gui.Tr.LcOpenMergeTool, + Handler: gui.Controllers.Files.OpenMergeTool, + Description: gui.c.Tr.LcOpenMergeTool, }, { ViewName: "main", Contexts: []string{string(MAIN_MERGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Select), Handler: gui.handlePickHunk, - Description: gui.Tr.PickHunk, + Description: gui.c.Tr.PickHunk, }, { ViewName: "main", Contexts: []string{string(MAIN_MERGING_CONTEXT_KEY)}, Key: gui.getKey(config.Main.PickBothHunks), Handler: gui.handlePickAllHunks, - Description: gui.Tr.PickAllHunks, + Description: gui.c.Tr.PickAllHunks, }, { ViewName: "main", Contexts: []string{string(MAIN_MERGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.PrevBlock), Handler: gui.handleSelectPrevConflict, - Description: gui.Tr.PrevConflict, + Description: gui.c.Tr.PrevConflict, }, { ViewName: "main", Contexts: []string{string(MAIN_MERGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.NextBlock), Handler: gui.handleSelectNextConflict, - Description: gui.Tr.NextConflict, + Description: gui.c.Tr.NextConflict, }, { ViewName: "main", Contexts: []string{string(MAIN_MERGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.PrevItem), Handler: gui.handleSelectPrevConflictHunk, - Description: gui.Tr.SelectPrevHunk, + Description: gui.c.Tr.SelectPrevHunk, }, { ViewName: "main", Contexts: []string{string(MAIN_MERGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.NextItem), Handler: gui.handleSelectNextConflictHunk, - Description: gui.Tr.SelectNextHunk, + Description: gui.c.Tr.SelectNextHunk, }, { ViewName: "main", @@ -1554,35 +1220,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(MAIN_MERGING_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Undo), Handler: gui.handleMergeConflictUndo, - Description: gui.Tr.LcUndo, - }, - { - ViewName: "branches", - Contexts: []string{string(REMOTES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.GoInto), - Modifier: gocui.ModNone, - Handler: gui.handleRemoteEnter, - }, - { - ViewName: "branches", - Contexts: []string{string(REMOTES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.New), - Handler: gui.handleAddRemote, - Description: gui.Tr.LcAddNewRemote, - }, - { - ViewName: "branches", - Contexts: []string{string(REMOTES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Remove), - Handler: gui.handleRemoveRemote, - Description: gui.Tr.LcRemoveRemote, - }, - { - ViewName: "branches", - Contexts: []string{string(REMOTES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Edit), - Handler: gui.handleEditRemote, - Description: gui.Tr.LcEditRemote, + Description: gui.c.Tr.LcUndo, }, { ViewName: "branches", @@ -1590,42 +1228,42 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Key: gui.getKey(config.Universal.Select), // gonna use the exact same handler as the 'n' keybinding because everybody wants this to happen when they checkout a remote branch Handler: gui.handleNewBranchOffCurrentItem, - Description: gui.Tr.LcCheckout, + Description: gui.c.Tr.LcCheckout, }, { ViewName: "branches", Contexts: []string{string(REMOTE_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.New), Handler: gui.handleNewBranchOffCurrentItem, - Description: gui.Tr.LcNewBranch, + Description: gui.c.Tr.LcNewBranch, }, { ViewName: "branches", Contexts: []string{string(REMOTE_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Branches.MergeIntoCurrentBranch), - Handler: gui.handleMergeRemoteBranch, - Description: gui.Tr.LcMergeIntoCurrentBranch, + Handler: guards.OutsideFilterMode(gui.handleMergeRemoteBranch), + Description: gui.c.Tr.LcMergeIntoCurrentBranch, }, { ViewName: "branches", Contexts: []string{string(REMOTE_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Remove), Handler: gui.handleDeleteRemoteBranch, - Description: gui.Tr.LcDeleteBranch, + Description: gui.c.Tr.LcDeleteBranch, }, { ViewName: "branches", Contexts: []string{string(REMOTE_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Branches.RebaseBranch), - Handler: gui.handleRebaseOntoRemoteBranch, - Description: gui.Tr.LcRebaseBranch, + Handler: guards.OutsideFilterMode(gui.handleRebaseOntoRemoteBranch), + Description: gui.c.Tr.LcRebaseBranch, }, { ViewName: "branches", Contexts: []string{string(REMOTE_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Branches.SetUpstream), Handler: gui.handleSetBranchUpstream, - Description: gui.Tr.LcSetUpstream, + Description: gui.c.Tr.LcSetUpstream, }, { ViewName: "status", @@ -1669,49 +1307,31 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Modifier: gocui.ModNone, Handler: gui.scrollDownConfirmationPanel, }, - { - ViewName: "menu", - Key: gui.getKey(config.Universal.Select), - Modifier: gocui.ModNone, - Handler: gui.onMenuPress, - }, - { - ViewName: "menu", - Key: gui.getKey(config.Universal.Confirm), - Modifier: gocui.ModNone, - Handler: gui.onMenuPress, - }, - { - ViewName: "menu", - Key: gui.getKey(config.Universal.ConfirmAlt1), - Modifier: gocui.ModNone, - Handler: gui.onMenuPress, - }, { ViewName: "files", Contexts: []string{string(SUBMODULES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.CopyToClipboard), Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.Tr.LcCopySubmoduleNameToClipboard, + Description: gui.c.Tr.LcCopySubmoduleNameToClipboard, }, { ViewName: "files", Contexts: []string{string(FILES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.ToggleWhitespaceInDiffView), Handler: gui.toggleWhitespaceInDiffView, - Description: gui.Tr.ToggleWhitespaceInDiffView, + Description: gui.c.Tr.ToggleWhitespaceInDiffView, }, { ViewName: "", Key: gui.getKey(config.Universal.IncreaseContextInDiffView), Handler: gui.IncreaseContextInDiffView, - Description: gui.Tr.IncreaseContextInDiffView, + Description: gui.c.Tr.IncreaseContextInDiffView, }, { ViewName: "", Key: gui.getKey(config.Universal.DecreaseContextInDiffView), Handler: gui.DecreaseContextInDiffView, - Description: gui.Tr.DecreaseContextInDiffView, + Description: gui.c.Tr.DecreaseContextInDiffView, }, { ViewName: "extras", @@ -1727,7 +1347,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { ViewName: "extras", Key: gui.getKey(config.Universal.ExtrasMenu), Handler: gui.handleCreateExtrasMenuPanel, - Description: gui.Tr.LcOpenExtrasMenu, + Description: gui.c.Tr.LcOpenExtrasMenu, OpensMenu: true, }, { @@ -1771,22 +1391,49 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { }, } - type ContextKeybindings struct { - contextKey ContextKey - viewName string - bindings []*types.Binding + for _, controller := range []types.IController{ + gui.Controllers.LocalCommits, + gui.Controllers.Submodules, + gui.Controllers.Files, + gui.Controllers.Remotes, + gui.Controllers.Menu, + gui.Controllers.Bisect, + gui.Controllers.Undo, + gui.Controllers.Sync, + } { + context := controller.Context() + viewName := "" + var contextKeys []string + // nil context means global keybinding + if context != nil { + viewName = context.GetViewName() + contextKeys = []string{string(context.GetKey())} + } + + for _, binding := range controller.Keybindings(gui.getKey, config, guards) { + binding.Contexts = contextKeys + binding.ViewName = viewName + bindings = append(bindings, binding) + } } - for _, contextKeybindings := range []ContextKeybindings{ - { - contextKey: SUBMODULES_CONTEXT_KEY, - viewName: "files", - bindings: gui.Controllers.Submodules.Keybindings(gui.getKey, config), - }, + // while migrating we'll continue providing keybindings from the list contexts themselves. + // for each controller we add above we need to remove the corresponding list context from here. + for _, listContext := range []types.IListContext{ + gui.State.Contexts.Branches, + gui.State.Contexts.RemoteBranches, + gui.State.Contexts.Tags, + gui.State.Contexts.ReflogCommits, + gui.State.Contexts.SubCommits, + gui.State.Contexts.Stash, + gui.State.Contexts.CommitFiles, + gui.State.Contexts.Suggestions, } { - for _, binding := range contextKeybindings.bindings { - binding.Contexts = []string{string(contextKeybindings.contextKey)} - binding.ViewName = contextKeybindings.viewName + viewName := listContext.GetViewName() + contextKey := listContext.GetKey() + for _, binding := range listContext.Keybindings(gui.getKey, config, guards) { + binding.Contexts = []string{string(contextKey)} + binding.ViewName = viewName bindings = append(bindings, binding) } } @@ -1817,27 +1464,25 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { } } - for viewName := range gui.State.Contexts.initialViewTabContextMap() { + for viewName := range gui.State.Contexts.InitialViewTabContextMap() { bindings = append(bindings, []*types.Binding{ { ViewName: viewName, Key: gui.getKey(config.Universal.NextTab), Handler: gui.handleNextTab, - Description: gui.Tr.LcNextTab, + Description: gui.c.Tr.LcNextTab, Tag: "navigation", }, { ViewName: viewName, Key: gui.getKey(config.Universal.PrevTab), Handler: gui.handlePrevTab, - Description: gui.Tr.LcPrevTab, + Description: gui.c.Tr.LcPrevTab, Tag: "navigation", }, }...) } - bindings = append(bindings, gui.getListContextKeyBindings()...) - return bindings } @@ -1852,7 +1497,7 @@ func (gui *Gui) keybindings() error { } } - for viewName := range gui.State.Contexts.initialViewTabContextMap() { + for viewName := range gui.State.Contexts.InitialViewTabContextMap() { viewName := viewName tabClickCallback := func(tabIndex int) error { return gui.onViewTabClick(viewName, tabIndex) } diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index 3af9ea9af..aa2878250 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -2,6 +2,7 @@ package gui import ( "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/theme" ) @@ -50,36 +51,36 @@ func (gui *Gui) createAllViews() error { gui.Views.SearchPrefix.Frame = false gui.setViewContent(gui.Views.SearchPrefix, SEARCH_PREFIX) - gui.Views.Stash.Title = gui.Tr.StashTitle + gui.Views.Stash.Title = gui.c.Tr.StashTitle gui.Views.Stash.FgColor = theme.GocuiDefaultTextColor - gui.Views.Commits.Title = gui.Tr.CommitsTitle + gui.Views.Commits.Title = gui.c.Tr.CommitsTitle gui.Views.Commits.FgColor = theme.GocuiDefaultTextColor - gui.Views.CommitFiles.Title = gui.Tr.CommitFiles + gui.Views.CommitFiles.Title = gui.c.Tr.CommitFiles gui.Views.CommitFiles.FgColor = theme.GocuiDefaultTextColor - gui.Views.Branches.Title = gui.Tr.BranchesTitle + gui.Views.Branches.Title = gui.c.Tr.BranchesTitle gui.Views.Branches.FgColor = theme.GocuiDefaultTextColor gui.Views.Files.Highlight = true - gui.Views.Files.Title = gui.Tr.FilesTitle + gui.Views.Files.Title = gui.c.Tr.FilesTitle gui.Views.Files.FgColor = theme.GocuiDefaultTextColor - gui.Views.Secondary.Title = gui.Tr.DiffTitle + gui.Views.Secondary.Title = gui.c.Tr.DiffTitle gui.Views.Secondary.Wrap = true gui.Views.Secondary.FgColor = theme.GocuiDefaultTextColor gui.Views.Secondary.IgnoreCarriageReturns = true - gui.Views.Main.Title = gui.Tr.DiffTitle + gui.Views.Main.Title = gui.c.Tr.DiffTitle gui.Views.Main.Wrap = true gui.Views.Main.FgColor = theme.GocuiDefaultTextColor gui.Views.Main.IgnoreCarriageReturns = true - gui.Views.Limit.Title = gui.Tr.NotEnoughSpace + gui.Views.Limit.Title = gui.c.Tr.NotEnoughSpace gui.Views.Limit.Wrap = true - gui.Views.Status.Title = gui.Tr.StatusTitle + gui.Views.Status.Title = gui.c.Tr.StatusTitle gui.Views.Status.FgColor = theme.GocuiDefaultTextColor gui.Views.Search.BgColor = gocui.ColorDefault @@ -93,7 +94,7 @@ func (gui *Gui) createAllViews() error { gui.Views.AppStatus.Visible = false gui.Views.CommitMessage.Visible = false - gui.Views.CommitMessage.Title = gui.Tr.CommitMessage + gui.Views.CommitMessage.Title = gui.c.Tr.CommitMessage gui.Views.CommitMessage.FgColor = theme.GocuiDefaultTextColor gui.Views.CommitMessage.Editable = true gui.Views.CommitMessage.Editor = gocui.EditorFunc(gui.commitMessageEditor) @@ -101,7 +102,7 @@ func (gui *Gui) createAllViews() error { gui.Views.Confirmation.Visible = false gui.Views.Credentials.Visible = false - gui.Views.Credentials.Title = gui.Tr.CredentialsUsername + gui.Views.Credentials.Title = gui.c.Tr.CredentialsUsername gui.Views.Credentials.FgColor = theme.GocuiDefaultTextColor gui.Views.Credentials.Editable = true @@ -113,7 +114,7 @@ func (gui *Gui) createAllViews() error { gui.Views.Information.FgColor = gocui.ColorGreen gui.Views.Information.Frame = false - gui.Views.Extras.Title = gui.Tr.CommandLog + gui.Views.Extras.Title = gui.c.Tr.CommandLog gui.Views.Extras.FgColor = theme.GocuiDefaultTextColor gui.Views.Extras.Autoscroll = true gui.Views.Extras.Wrap = true @@ -262,7 +263,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { } // ignore contexts whose view is owned by another context right now - if ContextKey(view.Context) != listContext.GetKey() { + if types.ContextKey(view.Context) != listContext.GetKey() { continue } @@ -271,7 +272,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { view.SelBgColor = theme.GocuiSelectedLineBgColor // I doubt this is expensive though it's admittedly redundant after the first render - view.SetOnSelectItem(gui.onSelectItemWrapper(listContext.onSearchSelect)) + view.SetOnSelectItem(gui.onSelectItemWrapper(listContext.OnSearchSelect)) } gui.Views.Main.SetOnSelectItem(gui.onSelectItemWrapper(gui.handlelineByLineNavigateTo)) @@ -288,7 +289,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { // here is a good place log some stuff // if you run `lazygit --logs` // this will let you see these branches as prettified json - // gui.Log.Info(utils.AsJson(gui.State.Branches[0:4])) + // gui.c.Log.Info(utils.AsJson(gui.State.Branches[0:4])) return gui.resizeCurrentPopupPanel() } @@ -310,7 +311,7 @@ func (gui *Gui) onInitialViewsCreationForRepo() error { } initialContext := gui.currentSideContext() - if err := gui.pushContext(initialContext); err != nil { + if err := gui.c.PushContext(initialContext); err != nil { return err } @@ -372,9 +373,9 @@ func (gui *Gui) onInitialViewsCreation() error { return err } - if !gui.UserConfig.DisableStartupPopups { + if !gui.c.UserConfig.DisableStartupPopups { popupTasks := []func(chan struct{}) error{} - storedPopupVersion := gui.Config.GetAppState().StartupPopupVersion + storedPopupVersion := gui.c.GetAppState().StartupPopupVersion if storedPopupVersion < StartupPopupVersion { popupTasks = append(popupTasks, gui.showIntroPopupMessage) } diff --git a/pkg/gui/line_by_line_panel.go b/pkg/gui/line_by_line_panel.go index e851bc821..aec581a14 100644 --- a/pkg/gui/line_by_line_panel.go +++ b/pkg/gui/line_by_line_panel.go @@ -87,9 +87,9 @@ func (gui *Gui) copySelectedToClipboard() error { return gui.withLBLActiveCheck(func(state *LblPanelState) error { selected := state.PlainRenderSelected() - gui.logAction(gui.Tr.Actions.CopySelectedTextToClipboard) + gui.c.LogAction(gui.c.Tr.Actions.CopySelectedTextToClipboard) if err := gui.OSCommand.CopyToClipboard(selected); err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } return nil @@ -141,7 +141,7 @@ func (gui *Gui) refreshMainViewForLineByLine(state *LblPanelState) error { if gui.currentContext().GetKey() == gui.State.Contexts.PatchBuilding.GetKey() { filename := gui.getSelectedCommitFileName() var err error - includedLineIndices, err = gui.Git.Patch.PatchManager.GetFileIncLineIndices(filename) + includedLineIndices, err = gui.git.Patch.PatchManager.GetFileIncLineIndices(filename) if err != nil { return err } @@ -285,5 +285,5 @@ func (gui *Gui) handleLineByLineEdit() error { } lineNumber := gui.State.Panels.LineByLine.CurrentLineNumber() - return gui.editFileAtLine(file.Name, lineNumber) + return gui.fileHelper.EditFileAtLine(file.Name, lineNumber) } diff --git a/pkg/gui/list_context.go b/pkg/gui/list_context.go index 9f0d86372..3d779cabd 100644 --- a/pkg/gui/list_context.go +++ b/pkg/gui/list_context.go @@ -4,19 +4,20 @@ import ( "fmt" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) type ListContext struct { - GetItemsLength func() int - GetDisplayStrings func(startIdx int, length int) [][]string - OnFocus func(...OnFocusOpts) error - OnRenderToMain func(...OnFocusOpts) error - OnFocusLost func() error - OnClickSelectedItem func() error + GetItemsLength func() int + GetDisplayStrings func(startIdx int, length int) [][]string + OnFocus func(...types.OnFocusOpts) error + OnRenderToMain func(...types.OnFocusOpts) error + OnFocusLost func() error // the boolean here tells us whether the item is nil. This is needed because you can't work it out on the calling end once the pointer is wrapped in an interface (unless you want to use reflection) - SelectedItem func() (ListItem, bool) - OnGetPanelState func() IListPanelState + SelectedItem func() (types.ListItem, bool) + OnGetPanelState func() types.IListPanelState // if this is true, we'll call GetDisplayStrings for just the visible part of the // view and re-render that. This is useful when you need to render different // content based on the selection (e.g. for showing the selected commit) @@ -27,45 +28,12 @@ type ListContext struct { *BasicContext } -type IListContext interface { - GetSelectedItem() (ListItem, bool) - GetSelectedItemId() string - handlePrevLine() error - handleNextLine() error - handleScrollLeft() error - handleScrollRight() error - handleLineChange(change int) error - handleNextPage() error - handleGotoTop() error - handleGotoBottom() error - handlePrevPage() error - handleClick() error - onSearchSelect(selectedLineIdx int) error - FocusLine() - HandleRenderToMain() error +var _ types.IListContext = &ListContext{} - GetPanelState() IListPanelState - - Context -} - -func (self *ListContext) GetPanelState() IListPanelState { +func (self *ListContext) GetPanelState() types.IListPanelState { return self.OnGetPanelState() } -type IListPanelState interface { - SetSelectedLineIdx(int) - GetSelectedLineIdx() int -} - -type ListItem interface { - // ID is a SHA when the item is a commit, a filename when the item is a file, 'stash@{4}' when it's a stash entry, 'my_branch' when it's a branch - ID() string - - // Description is something we would show in a message e.g. '123as14: push blah' for a commit - Description() string -} - func (self *ListContext) FocusLine() { view, err := self.Gui.g.View(self.ViewName) if err != nil { @@ -87,7 +55,7 @@ func formatListFooter(selectedLineIdx int, length int) string { return fmt.Sprintf("%d of %d", selectedLineIdx+1, length) } -func (self *ListContext) GetSelectedItem() (ListItem, bool) { +func (self *ListContext) GetSelectedItem() (types.ListItem, bool) { return self.SelectedItem() } @@ -132,7 +100,7 @@ func (self *ListContext) HandleFocusLost() error { return nil } -func (self *ListContext) HandleFocus(opts ...OnFocusOpts) error { +func (self *ListContext) HandleFocus(opts ...types.OnFocusOpts) error { if self.Gui.popupPanelFocused() { return nil } @@ -158,19 +126,19 @@ func (self *ListContext) HandleFocus(opts ...OnFocusOpts) error { return nil } -func (self *ListContext) handlePrevLine() error { +func (self *ListContext) HandlePrevLine() error { return self.handleLineChange(-1) } -func (self *ListContext) handleNextLine() error { +func (self *ListContext) HandleNextLine() error { return self.handleLineChange(1) } -func (self *ListContext) handleScrollLeft() error { +func (self *ListContext) HandleScrollLeft() error { return self.scroll(self.Gui.scrollLeft) } -func (self *ListContext) handleScrollRight() error { +func (self *ListContext) HandleScrollRight() error { return self.scroll(self.Gui.scrollRight) } @@ -209,7 +177,7 @@ func (self *ListContext) handleLineChange(change int) error { return self.HandleFocus() } -func (self *ListContext) handleNextPage() error { +func (self *ListContext) HandleNextPage() error { view, err := self.Gui.g.View(self.ViewName) if err != nil { return nil @@ -219,15 +187,15 @@ func (self *ListContext) handleNextPage() error { return self.handleLineChange(delta) } -func (self *ListContext) handleGotoTop() error { +func (self *ListContext) HandleGotoTop() error { return self.handleLineChange(-self.GetItemsLength()) } -func (self *ListContext) handleGotoBottom() error { +func (self *ListContext) HandleGotoBottom() error { return self.handleLineChange(self.GetItemsLength()) } -func (self *ListContext) handlePrevPage() error { +func (self *ListContext) HandlePrevPage() error { view, err := self.Gui.g.View(self.ViewName) if err != nil { return nil @@ -238,7 +206,7 @@ func (self *ListContext) handlePrevPage() error { return self.handleLineChange(-delta) } -func (self *ListContext) handleClick() error { +func (self *ListContext) HandleClick(onClick func() error) error { if self.ignoreKeybinding() { return nil } @@ -252,7 +220,7 @@ func (self *ListContext) handleClick() error { newSelectedLineIdx := view.SelectedLineIdx() // we need to focus the view - if err := self.Gui.pushContext(self); err != nil { + if err := self.Gui.c.PushContext(self); err != nil { return err } @@ -263,13 +231,13 @@ func (self *ListContext) handleClick() error { self.GetPanelState().SetSelectedLineIdx(newSelectedLineIdx) prevViewName := self.Gui.currentViewName() - if prevSelectedLineIdx == newSelectedLineIdx && prevViewName == self.ViewName && self.OnClickSelectedItem != nil { - return self.OnClickSelectedItem() + if prevSelectedLineIdx == newSelectedLineIdx && prevViewName == self.ViewName && onClick != nil { + return onClick() } return self.HandleFocus() } -func (self *ListContext) onSearchSelect(selectedLineIdx int) error { +func (self *ListContext) OnSearchSelect(selectedLineIdx int) error { self.GetPanelState().SetSelectedLineIdx(selectedLineIdx) return self.HandleFocus() } @@ -281,3 +249,35 @@ func (self *ListContext) HandleRenderToMain() error { return nil } + +func (self *ListContext) Keybindings( + getKey func(key string) interface{}, + config config.KeybindingConfig, + guards types.KeybindingGuards, +) []*types.Binding { + return []*types.Binding{ + {Tag: "navigation", Key: getKey(config.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, + {Tag: "navigation", Key: getKey(config.Universal.PrevItem), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, + {Tag: "navigation", Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, + {Tag: "navigation", Key: getKey(config.Universal.NextItemAlt), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, + {Tag: "navigation", Key: getKey(config.Universal.NextItem), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, + {Tag: "navigation", Key: getKey(config.Universal.PrevPage), Modifier: gocui.ModNone, Handler: self.HandlePrevPage, Description: self.Gui.c.Tr.LcPrevPage}, + {Tag: "navigation", Key: getKey(config.Universal.NextPage), Modifier: gocui.ModNone, Handler: self.HandleNextPage, Description: self.Gui.c.Tr.LcNextPage}, + {Tag: "navigation", Key: getKey(config.Universal.GotoTop), Modifier: gocui.ModNone, Handler: self.HandleGotoTop, Description: self.Gui.c.Tr.LcGotoTop}, + {Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: func() error { return self.HandleClick(nil) }}, + {Tag: "navigation", Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: self.HandleNextLine}, + {Tag: "navigation", Key: getKey(config.Universal.ScrollLeft), Modifier: gocui.ModNone, Handler: self.HandleScrollLeft}, + {Tag: "navigation", Key: getKey(config.Universal.ScrollRight), Modifier: gocui.ModNone, Handler: self.HandleScrollRight}, + { + Key: getKey(config.Universal.StartSearch), + Handler: func() error { return self.Gui.handleOpenSearch(self.GetViewName()) }, + Description: self.Gui.c.Tr.LcStartSearch, + Tag: "navigation", + }, + { + Key: getKey(config.Universal.GotoBottom), + Description: self.Gui.c.Tr.LcGotoBottom, + Tag: "navigation", + }, + } +} diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index c40cade2c..9b1ebdc49 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -3,44 +3,41 @@ package gui import ( "log" - "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" ) -func (gui *Gui) menuListContext() IListContext { +func (gui *Gui) menuListContext() types.IListContext { return &ListContext{ BasicContext: &BasicContext{ ViewName: "menu", Key: "menu", - Kind: PERSISTENT_POPUP, + Kind: types.PERSISTENT_POPUP, OnGetOptionsMap: gui.getMenuOptions, }, - GetItemsLength: func() int { return gui.Views.Menu.LinesHeight() }, - OnGetPanelState: func() IListPanelState { return gui.State.Panels.Menu }, - OnClickSelectedItem: gui.onMenuPress, - Gui: gui, + GetItemsLength: func() int { return gui.Views.Menu.LinesHeight() }, + OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Menu }, + Gui: gui, // no GetDisplayStrings field because we do a custom render on menu creation } } -func (gui *Gui) filesListContext() IListContext { +func (gui *Gui) filesListContext() types.IListContext { return &ListContext{ BasicContext: &BasicContext{ ViewName: "files", WindowName: "files", Key: FILES_CONTEXT_KEY, - Kind: SIDE_CONTEXT, + Kind: types.SIDE_CONTEXT, }, - GetItemsLength: func() int { return gui.State.FileTreeViewModel.GetItemsLength() }, - OnGetPanelState: func() IListPanelState { return gui.State.Panels.Files }, - OnFocus: OnFocusWrapper(gui.onFocusFile), - OnRenderToMain: OnFocusWrapper(gui.filesRenderToMain), - OnClickSelectedItem: gui.handleFilePress, - Gui: gui, + GetItemsLength: func() int { return gui.State.FileTreeViewModel.GetItemsLength() }, + OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Files }, + OnFocus: OnFocusWrapper(gui.onFocusFile), + OnRenderToMain: OnFocusWrapper(gui.filesRenderToMain), + Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { lines := presentation.RenderFileTree(gui.State.FileTreeViewModel, gui.State.Modes.Diffing.Ref, gui.State.Submodules) mappedLines := make([][]string, len(lines)) @@ -50,117 +47,115 @@ func (gui *Gui) filesListContext() IListContext { return mappedLines }, - SelectedItem: func() (ListItem, bool) { + SelectedItem: func() (types.ListItem, bool) { item := gui.getSelectedFileNode() return item, item != nil }, } } -func (gui *Gui) branchesListContext() IListContext { +func (gui *Gui) branchesListContext() types.IListContext { return &ListContext{ BasicContext: &BasicContext{ ViewName: "branches", WindowName: "branches", Key: LOCAL_BRANCHES_CONTEXT_KEY, - Kind: SIDE_CONTEXT, + Kind: types.SIDE_CONTEXT, }, GetItemsLength: func() int { return len(gui.State.Branches) }, - OnGetPanelState: func() IListPanelState { return gui.State.Panels.Branches }, + OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Branches }, OnRenderToMain: OnFocusWrapper(gui.branchesRenderToMain), Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref) }, - SelectedItem: func() (ListItem, bool) { + SelectedItem: func() (types.ListItem, bool) { item := gui.getSelectedBranch() return item, item != nil }, } } -func (gui *Gui) remotesListContext() IListContext { +func (gui *Gui) remotesListContext() types.IListContext { return &ListContext{ BasicContext: &BasicContext{ ViewName: "branches", WindowName: "branches", Key: REMOTES_CONTEXT_KEY, - Kind: SIDE_CONTEXT, + Kind: types.SIDE_CONTEXT, }, - GetItemsLength: func() int { return len(gui.State.Remotes) }, - OnGetPanelState: func() IListPanelState { return gui.State.Panels.Remotes }, - OnRenderToMain: OnFocusWrapper(gui.remotesRenderToMain), - OnClickSelectedItem: gui.handleRemoteEnter, - Gui: gui, + GetItemsLength: func() int { return len(gui.State.Remotes) }, + OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Remotes }, + OnRenderToMain: OnFocusWrapper(gui.remotesRenderToMain), + Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetRemoteListDisplayStrings(gui.State.Remotes, gui.State.Modes.Diffing.Ref) }, - SelectedItem: func() (ListItem, bool) { + SelectedItem: func() (types.ListItem, bool) { item := gui.getSelectedRemote() return item, item != nil }, } } -func (gui *Gui) remoteBranchesListContext() IListContext { +func (gui *Gui) remoteBranchesListContext() types.IListContext { return &ListContext{ BasicContext: &BasicContext{ ViewName: "branches", WindowName: "branches", Key: REMOTE_BRANCHES_CONTEXT_KEY, - Kind: SIDE_CONTEXT, + Kind: types.SIDE_CONTEXT, }, GetItemsLength: func() int { return len(gui.State.RemoteBranches) }, - OnGetPanelState: func() IListPanelState { return gui.State.Panels.RemoteBranches }, + OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.RemoteBranches }, OnRenderToMain: OnFocusWrapper(gui.remoteBranchesRenderToMain), Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetRemoteBranchListDisplayStrings(gui.State.RemoteBranches, gui.State.Modes.Diffing.Ref) }, - SelectedItem: func() (ListItem, bool) { + SelectedItem: func() (types.ListItem, bool) { item := gui.getSelectedRemoteBranch() return item, item != nil }, } } -func (gui *Gui) tagsListContext() IListContext { +func (gui *Gui) tagsListContext() types.IListContext { return &ListContext{ BasicContext: &BasicContext{ ViewName: "branches", WindowName: "branches", Key: TAGS_CONTEXT_KEY, - Kind: SIDE_CONTEXT, + Kind: types.SIDE_CONTEXT, }, GetItemsLength: func() int { return len(gui.State.Tags) }, - OnGetPanelState: func() IListPanelState { return gui.State.Panels.Tags }, + OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Tags }, OnRenderToMain: OnFocusWrapper(gui.tagsRenderToMain), Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetTagListDisplayStrings(gui.State.Tags, gui.State.Modes.Diffing.Ref) }, - SelectedItem: func() (ListItem, bool) { + SelectedItem: func() (types.ListItem, bool) { item := gui.getSelectedTag() return item, item != nil }, } } -func (gui *Gui) branchCommitsListContext() IListContext { - parseEmoji := gui.UserConfig.Git.ParseEmoji +func (gui *Gui) branchCommitsListContext() types.IListContext { + parseEmoji := gui.c.UserConfig.Git.ParseEmoji return &ListContext{ BasicContext: &BasicContext{ ViewName: "commits", WindowName: "commits", Key: BRANCH_COMMITS_CONTEXT_KEY, - Kind: SIDE_CONTEXT, + Kind: types.SIDE_CONTEXT, }, - GetItemsLength: func() int { return len(gui.State.Commits) }, - OnGetPanelState: func() IListPanelState { return gui.State.Panels.Commits }, - OnFocus: OnFocusWrapper(gui.onCommitFocus), - OnRenderToMain: OnFocusWrapper(gui.branchCommitsRenderToMain), - OnClickSelectedItem: gui.handleViewCommitFiles, - Gui: gui, + GetItemsLength: func() int { return len(gui.State.Commits) }, + OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Commits }, + OnFocus: OnFocusWrapper(gui.onCommitFocus), + OnRenderToMain: OnFocusWrapper(gui.branchCommitsRenderToMain), + Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { selectedCommitSha := "" if gui.currentContext().GetKey() == BRANCH_COMMITS_CONTEXT_KEY { @@ -182,7 +177,7 @@ func (gui *Gui) branchCommitsListContext() IListContext { gui.State.BisectInfo, ) }, - SelectedItem: func() (ListItem, bool) { + SelectedItem: func() (types.ListItem, bool) { item := gui.getSelectedLocalCommit() return item, item != nil }, @@ -190,17 +185,17 @@ func (gui *Gui) branchCommitsListContext() IListContext { } } -func (gui *Gui) subCommitsListContext() IListContext { - parseEmoji := gui.UserConfig.Git.ParseEmoji +func (gui *Gui) subCommitsListContext() types.IListContext { + parseEmoji := gui.c.UserConfig.Git.ParseEmoji return &ListContext{ BasicContext: &BasicContext{ ViewName: "branches", WindowName: "branches", Key: SUB_COMMITS_CONTEXT_KEY, - Kind: SIDE_CONTEXT, + Kind: types.SIDE_CONTEXT, }, GetItemsLength: func() int { return len(gui.State.SubCommits) }, - OnGetPanelState: func() IListPanelState { return gui.State.Panels.SubCommits }, + OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.SubCommits }, OnRenderToMain: OnFocusWrapper(gui.subCommitsRenderToMain), Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { @@ -224,7 +219,7 @@ func (gui *Gui) subCommitsListContext() IListContext { git_commands.NewNullBisectInfo(), ) }, - SelectedItem: func() (ListItem, bool) { + SelectedItem: func() (types.ListItem, bool) { item := gui.getSelectedSubCommit() return item, item != nil }, @@ -237,7 +232,7 @@ func (gui *Gui) shouldShowGraph() bool { return false } - value := gui.UserConfig.Git.Log.ShowGraph + value := gui.c.UserConfig.Git.Log.ShowGraph switch value { case "always": return true @@ -251,17 +246,17 @@ func (gui *Gui) shouldShowGraph() bool { return false } -func (gui *Gui) reflogCommitsListContext() IListContext { - parseEmoji := gui.UserConfig.Git.ParseEmoji +func (gui *Gui) reflogCommitsListContext() types.IListContext { + parseEmoji := gui.c.UserConfig.Git.ParseEmoji return &ListContext{ BasicContext: &BasicContext{ ViewName: "commits", WindowName: "commits", Key: REFLOG_COMMITS_CONTEXT_KEY, - Kind: SIDE_CONTEXT, + Kind: types.SIDE_CONTEXT, }, GetItemsLength: func() int { return len(gui.State.FilteredReflogCommits) }, - OnGetPanelState: func() IListPanelState { return gui.State.Panels.ReflogCommits }, + OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.ReflogCommits }, OnRenderToMain: OnFocusWrapper(gui.reflogCommitsRenderToMain), Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { @@ -273,45 +268,45 @@ func (gui *Gui) reflogCommitsListContext() IListContext { parseEmoji, ) }, - SelectedItem: func() (ListItem, bool) { + SelectedItem: func() (types.ListItem, bool) { item := gui.getSelectedReflogCommit() return item, item != nil }, } } -func (gui *Gui) stashListContext() IListContext { +func (gui *Gui) stashListContext() types.IListContext { return &ListContext{ BasicContext: &BasicContext{ ViewName: "stash", WindowName: "stash", Key: STASH_CONTEXT_KEY, - Kind: SIDE_CONTEXT, + Kind: types.SIDE_CONTEXT, }, GetItemsLength: func() int { return len(gui.State.StashEntries) }, - OnGetPanelState: func() IListPanelState { return gui.State.Panels.Stash }, + OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Stash }, OnRenderToMain: OnFocusWrapper(gui.stashRenderToMain), Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetStashEntryListDisplayStrings(gui.State.StashEntries, gui.State.Modes.Diffing.Ref) }, - SelectedItem: func() (ListItem, bool) { + SelectedItem: func() (types.ListItem, bool) { item := gui.getSelectedStashEntry() return item, item != nil }, } } -func (gui *Gui) commitFilesListContext() IListContext { +func (gui *Gui) commitFilesListContext() types.IListContext { return &ListContext{ BasicContext: &BasicContext{ ViewName: "commitFiles", WindowName: "commits", Key: COMMIT_FILES_CONTEXT_KEY, - Kind: SIDE_CONTEXT, + Kind: types.SIDE_CONTEXT, }, GetItemsLength: func() int { return gui.State.CommitFileTreeViewModel.GetItemsLength() }, - OnGetPanelState: func() IListPanelState { return gui.State.Panels.CommitFiles }, + OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.CommitFiles }, OnFocus: OnFocusWrapper(gui.onCommitFileFocus), OnRenderToMain: OnFocusWrapper(gui.commitFilesRenderToMain), Gui: gui, @@ -320,7 +315,7 @@ func (gui *Gui) commitFilesListContext() IListContext { return [][]string{{style.FgRed.Sprint("(none)")}} } - lines := presentation.RenderCommitFileTree(gui.State.CommitFileTreeViewModel, gui.State.Modes.Diffing.Ref, gui.Git.Patch.PatchManager) + lines := presentation.RenderCommitFileTree(gui.State.CommitFileTreeViewModel, gui.State.Modes.Diffing.Ref, gui.git.Patch.PatchManager) mappedLines := make([][]string, len(lines)) for i, line := range lines { mappedLines[i] = []string{line} @@ -328,45 +323,45 @@ func (gui *Gui) commitFilesListContext() IListContext { return mappedLines }, - SelectedItem: func() (ListItem, bool) { + SelectedItem: func() (types.ListItem, bool) { item := gui.getSelectedCommitFileNode() return item, item != nil }, } } -func (gui *Gui) submodulesListContext() IListContext { +func (gui *Gui) submodulesListContext() types.IListContext { return &ListContext{ BasicContext: &BasicContext{ ViewName: "files", WindowName: "files", Key: SUBMODULES_CONTEXT_KEY, - Kind: SIDE_CONTEXT, + Kind: types.SIDE_CONTEXT, }, GetItemsLength: func() int { return len(gui.State.Submodules) }, - OnGetPanelState: func() IListPanelState { return gui.State.Panels.Submodules }, + OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Submodules }, OnRenderToMain: OnFocusWrapper(gui.submodulesRenderToMain), Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetSubmoduleListDisplayStrings(gui.State.Submodules) }, - SelectedItem: func() (ListItem, bool) { + SelectedItem: func() (types.ListItem, bool) { item := gui.getSelectedSubmodule() return item, item != nil }, } } -func (gui *Gui) suggestionsListContext() IListContext { +func (gui *Gui) suggestionsListContext() types.IListContext { return &ListContext{ BasicContext: &BasicContext{ ViewName: "suggestions", WindowName: "suggestions", Key: SUGGESTIONS_CONTEXT_KEY, - Kind: PERSISTENT_POPUP, + Kind: types.PERSISTENT_POPUP, }, GetItemsLength: func() int { return len(gui.State.Suggestions) }, - OnGetPanelState: func() IListPanelState { return gui.State.Panels.Suggestions }, + OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Suggestions }, Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetSuggestionListDisplayStrings(gui.State.Suggestions) @@ -374,8 +369,8 @@ func (gui *Gui) suggestionsListContext() IListContext { } } -func (gui *Gui) getListContexts() []IListContext { - return []IListContext{ +func (gui *Gui) getListContexts() []types.IListContext { + return []types.IListContext{ gui.State.Contexts.Menu, gui.State.Contexts.Files, gui.State.Contexts.Branches, @@ -391,58 +386,3 @@ func (gui *Gui) getListContexts() []IListContext { gui.State.Contexts.Suggestions, } } - -func (gui *Gui) getListContextKeyBindings() []*types.Binding { - bindings := make([]*types.Binding, 0) - - keybindingConfig := gui.UserConfig.Keybinding - - for _, listContext := range gui.getListContexts() { - listContext := listContext - - bindings = append(bindings, []*types.Binding{ - {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: listContext.handlePrevLine}, - {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.PrevItem), Modifier: gocui.ModNone, Handler: listContext.handlePrevLine}, - {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, Handler: listContext.handlePrevLine}, - {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.NextItemAlt), Modifier: gocui.ModNone, Handler: listContext.handleNextLine}, - {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.NextItem), Modifier: gocui.ModNone, Handler: listContext.handleNextLine}, - {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.PrevPage), Modifier: gocui.ModNone, Handler: listContext.handlePrevPage, Description: gui.Tr.LcPrevPage}, - {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.NextPage), Modifier: gocui.ModNone, Handler: listContext.handleNextPage, Description: gui.Tr.LcNextPage}, - {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.GotoTop), Modifier: gocui.ModNone, Handler: listContext.handleGotoTop, Description: gui.Tr.LcGotoTop}, - {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: listContext.handleNextLine}, - {ViewName: listContext.GetViewName(), Contexts: []string{string(listContext.GetKey())}, Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: listContext.handleClick}, - {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.ScrollLeft), Modifier: gocui.ModNone, Handler: listContext.handleScrollLeft}, - {ViewName: listContext.GetViewName(), Tag: "navigation", Contexts: []string{string(listContext.GetKey())}, Key: gui.getKey(keybindingConfig.Universal.ScrollRight), Modifier: gocui.ModNone, Handler: listContext.handleScrollRight}, - }...) - - openSearchHandler := gui.handleOpenSearch - gotoBottomHandler := listContext.handleGotoBottom - - // the branch commits context needs to lazyload things so it has a couple of its own handlers - if listContext.GetKey() == BRANCH_COMMITS_CONTEXT_KEY { - openSearchHandler = gui.handleOpenSearchForCommitsPanel - gotoBottomHandler = gui.handleGotoBottomForCommitsPanel - } - - bindings = append(bindings, []*types.Binding{ - { - ViewName: listContext.GetViewName(), - Contexts: []string{string(listContext.GetKey())}, - Key: gui.getKey(keybindingConfig.Universal.StartSearch), - Handler: func() error { return openSearchHandler(listContext.GetViewName()) }, - Description: gui.Tr.LcStartSearch, - Tag: "navigation", - }, - { - ViewName: listContext.GetViewName(), - Contexts: []string{string(listContext.GetKey())}, - Key: gui.getKey(keybindingConfig.Universal.GotoBottom), - Handler: gotoBottomHandler, - Description: gui.Tr.LcGotoBottom, - Tag: "navigation", - }, - }...) - } - - return bindings -} diff --git a/pkg/gui/main_panels.go b/pkg/gui/main_panels.go index 72af94b1d..1ecbd82e1 100644 --- a/pkg/gui/main_panels.go +++ b/pkg/gui/main_panels.go @@ -124,7 +124,7 @@ func (gui *Gui) refreshMainView(opts *viewUpdateOpts, view *gocui.View) error { view.Highlight = opts.highlight if err := gui.runTaskForView(view, opts.task); err != nil { - gui.Log.Error(err) + gui.c.Log.Error(err) return nil } diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go index f1bc558c4..fc7f70329 100644 --- a/pkg/gui/menu_panel.go +++ b/pkg/gui/menu_panel.go @@ -10,12 +10,12 @@ import ( ) func (gui *Gui) getMenuOptions() map[string]string { - keybindingConfig := gui.UserConfig.Keybinding + keybindingConfig := gui.c.UserConfig.Keybinding return map[string]string{ - gui.getKeyDisplay(keybindingConfig.Universal.Return): gui.Tr.LcClose, - fmt.Sprintf("%s %s", gui.getKeyDisplay(keybindingConfig.Universal.PrevItem), gui.getKeyDisplay(keybindingConfig.Universal.NextItem)): gui.Tr.LcNavigate, - gui.getKeyDisplay(keybindingConfig.Universal.Select): gui.Tr.LcExecute, + gui.getKeyDisplay(keybindingConfig.Universal.Return): gui.c.Tr.LcClose, + fmt.Sprintf("%s %s", gui.getKeyDisplay(keybindingConfig.Universal.PrevItem), gui.getKeyDisplay(keybindingConfig.Universal.NextItem)): gui.c.Tr.LcNavigate, + gui.getKeyDisplay(keybindingConfig.Universal.Select): gui.c.Tr.LcExecute, } } @@ -28,7 +28,7 @@ func (gui *Gui) createMenu(opts popup.CreateMenuOptions) error { if !opts.HideCancel { // this is mutative but I'm okay with that for now opts.Items = append(opts.Items, &popup.MenuItem{ - DisplayStrings: []string{gui.Tr.LcCancel}, + DisplayStrings: []string{gui.c.Tr.LcCancel}, OnPress: func() error { return nil }, @@ -66,18 +66,13 @@ func (gui *Gui) createMenu(opts popup.CreateMenuOptions) error { menuView.SetContent(list) gui.State.Panels.Menu.SelectedLineIdx = 0 - return gui.pushContext(gui.State.Contexts.Menu) + return gui.c.PushContext(gui.State.Contexts.Menu) } -func (gui *Gui) onMenuPress() error { - selectedLine := gui.State.Panels.Menu.SelectedLineIdx - if err := gui.returnFromContext(); err != nil { - return err +func (gui *Gui) getSelectedMenuItem() *popup.MenuItem { + if len(gui.State.MenuItems) == 0 { + return nil } - if err := gui.State.MenuItems[selectedLine].OnPress(); err != nil { - return err - } - - return nil + return gui.State.MenuItems[gui.State.Panels.Menu.SelectedLineIdx] } diff --git a/pkg/gui/merge_panel.go b/pkg/gui/merge_panel.go index 9f46c177c..eb154d57d 100644 --- a/pkg/gui/merge_panel.go +++ b/pkg/gui/merge_panel.go @@ -52,8 +52,8 @@ func (gui *Gui) handleMergeConflictUndo() error { return nil } - gui.logAction("Restoring file to previous state") - gui.logCommand("Undoing last conflict resolution", false) + gui.c.LogAction("Restoring file to previous state") + gui.LogCommand("Undoing last conflict resolution", false) if err := ioutil.WriteFile(state.GetPath(), []byte(state.GetContent()), 0644); err != nil { return err } @@ -124,8 +124,8 @@ func (gui *Gui) resolveConflict(selection mergeconflicts.Selection) (bool, error case mergeconflicts.ALL: logStr = "Picking all hunks" } - gui.logAction("Resolve merge conflict") - gui.logCommand(logStr, false) + gui.c.LogAction("Resolve merge conflict") + gui.LogCommand(logStr, false) state.PushContent(content) return true, ioutil.WriteFile(state.GetPath(), []byte(content), 0644) } @@ -153,7 +153,7 @@ func (gui *Gui) renderConflicts(hasFocus bool) error { return gui.refreshMainViews(refreshMainOpts{ main: &viewUpdateOpts{ - title: gui.Tr.MergeConflictsTitle, + title: gui.c.Tr.MergeConflictsTitle, task: NewRenderStringWithoutScrollTask(content), noWrap: true, }, @@ -178,19 +178,19 @@ func (gui *Gui) centerYPos(view *gocui.View, y int) { } func (gui *Gui) getMergingOptions() map[string]string { - keybindingConfig := gui.UserConfig.Keybinding + keybindingConfig := gui.c.UserConfig.Keybinding return map[string]string{ - fmt.Sprintf("%s %s", gui.getKeyDisplay(keybindingConfig.Universal.PrevItem), gui.getKeyDisplay(keybindingConfig.Universal.NextItem)): gui.Tr.LcSelectHunk, - fmt.Sprintf("%s %s", gui.getKeyDisplay(keybindingConfig.Universal.PrevBlock), gui.getKeyDisplay(keybindingConfig.Universal.NextBlock)): gui.Tr.LcNavigateConflicts, - gui.getKeyDisplay(keybindingConfig.Universal.Select): gui.Tr.LcPickHunk, - gui.getKeyDisplay(keybindingConfig.Main.PickBothHunks): gui.Tr.LcPickAllHunks, - gui.getKeyDisplay(keybindingConfig.Universal.Undo): gui.Tr.LcUndo, + fmt.Sprintf("%s %s", gui.getKeyDisplay(keybindingConfig.Universal.PrevItem), gui.getKeyDisplay(keybindingConfig.Universal.NextItem)): gui.c.Tr.LcSelectHunk, + fmt.Sprintf("%s %s", gui.getKeyDisplay(keybindingConfig.Universal.PrevBlock), gui.getKeyDisplay(keybindingConfig.Universal.NextBlock)): gui.c.Tr.LcNavigateConflicts, + gui.getKeyDisplay(keybindingConfig.Universal.Select): gui.c.Tr.LcPickHunk, + gui.getKeyDisplay(keybindingConfig.Main.PickBothHunks): gui.c.Tr.LcPickAllHunks, + gui.getKeyDisplay(keybindingConfig.Universal.Undo): gui.c.Tr.LcUndo, } } func (gui *Gui) handleEscapeMerge() error { - if err := gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}); err != nil { + if err := gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}); err != nil { return err } @@ -200,7 +200,7 @@ func (gui *Gui) handleEscapeMerge() error { func (gui *Gui) onLastConflictResolved() error { // as part of refreshing files, we handle the situation where a file has had // its merge conflicts resolved. - return gui.refreshSidePanels(types.RefreshOptions{mode: types.ASYNC, scope: []types.RefreshableView{types.FILES}}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) } func (gui *Gui) resetMergeState() { @@ -209,7 +209,7 @@ func (gui *Gui) resetMergeState() { } func (gui *Gui) setMergeState(path string) (bool, error) { - content, err := gui.Git.File.Cat(path) + content, err := gui.git.File.Cat(path) if err != nil { return false, err } @@ -269,7 +269,6 @@ func (gui *Gui) setConflictsAndRender(path string, hasFocus bool) (bool, error) return false, err } - // if we don't have conflicts we'll fall through and show the diff if hasConflicts { return true, gui.renderConflicts(hasFocus) } @@ -294,7 +293,7 @@ func (gui *Gui) refreshMergeState() error { hasConflicts, err := gui.setConflictsAndRender(gui.State.Panels.Merging.GetPath(), true) if err != nil { - return gui.surfaceError(err) + return gui.c.Error(err) } if !hasConflicts { @@ -303,3 +302,19 @@ func (gui *Gui) refreshMergeState() error { return nil } + +func (gui *Gui) switchToMerge(path string) error { + gui.takeOverMergeConflictScrolling() + + if gui.State.Panels.Merging.GetPath() != path { + hasConflicts, err := gui.setMergeStateWithLock(path) + if err != nil { + return err + } + if !hasConflicts { + return nil + } + } + + return gui.c.PushContext(gui.State.Contexts.Merging) +} diff --git a/pkg/gui/misc.go b/pkg/gui/misc.go new file mode 100644 index 000000000..f3e19961e --- /dev/null +++ b/pkg/gui/misc.go @@ -0,0 +1,19 @@ +package gui + +// this file is to put things where it's not obvious where they belong while this refactor takes place + +func (gui *Gui) getSuggestedRemote() string { + remotes := gui.State.Remotes + + if len(remotes) == 0 { + return "origin" + } + + for _, remote := range remotes { + if remote.Name == "origin" { + return remote.Name + } + } + + return remotes[0].Name +} diff --git a/pkg/gui/modes.go b/pkg/gui/modes.go index b60fafc8a..3f90f312d 100644 --- a/pkg/gui/modes.go +++ b/pkg/gui/modes.go @@ -21,7 +21,7 @@ func (gui *Gui) modeStatuses() []modeStatus { return gui.withResetButton( fmt.Sprintf( "%s %s", - gui.Tr.LcShowingGitDiff, + gui.c.Tr.LcShowingGitDiff, "git diff "+gui.diffStr(), ), style.FgMagenta, @@ -30,9 +30,9 @@ func (gui *Gui) modeStatuses() []modeStatus { reset: gui.exitDiffMode, }, { - isActive: gui.Git.Patch.PatchManager.Active, + isActive: gui.git.Patch.PatchManager.Active, description: func() string { - return gui.withResetButton(gui.Tr.LcBuildingPatch, style.FgYellow.SetBold()) + return gui.withResetButton(gui.c.Tr.LcBuildingPatch, style.FgYellow.SetBold()) }, reset: gui.handleResetPatch, }, @@ -42,7 +42,7 @@ func (gui *Gui) modeStatuses() []modeStatus { return gui.withResetButton( fmt.Sprintf( "%s '%s'", - gui.Tr.LcFilteringBy, + gui.c.Tr.LcFilteringBy, gui.State.Modes.Filtering.GetPath(), ), style.FgRed, @@ -65,10 +65,10 @@ func (gui *Gui) modeStatuses() []modeStatus { }, { isActive: func() bool { - return gui.Git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE + return gui.git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE }, description: func() string { - workingTreeState := gui.Git.Status.WorkingTreeState() + workingTreeState := gui.git.Status.WorkingTreeState() return gui.withResetButton( formatWorkingTreeState(workingTreeState), style.FgYellow, ) @@ -82,7 +82,7 @@ func (gui *Gui) modeStatuses() []modeStatus { description: func() string { return gui.withResetButton("bisecting", style.FgGreen) }, - reset: gui.resetBisect, + reset: gui.Controllers.Bisect.Reset, }, } } @@ -91,6 +91,6 @@ func (gui *Gui) withResetButton(content string, textStyle style.TextStyle) strin return textStyle.Sprintf( "%s %s", content, - style.AttrUnderline.Sprint(gui.Tr.ResetInParentheses), + style.AttrUnderline.Sprint(gui.c.Tr.ResetInParentheses), ) } diff --git a/pkg/gui/options_menu_panel.go b/pkg/gui/options_menu_panel.go index f02f96a95..2623e6df0 100644 --- a/pkg/gui/options_menu_panel.go +++ b/pkg/gui/options_menu_panel.go @@ -74,8 +74,8 @@ func (gui *Gui) handleCreateOptionsMenu() error { } } - return gui.PopupHandler.Menu(popup.CreateMenuOptions{ - Title: strings.Title(gui.Tr.LcMenu), + return gui.c.Menu(popup.CreateMenuOptions{ + Title: strings.Title(gui.c.Tr.LcMenu), Items: menuItems, HideCancel: true, }) diff --git a/pkg/gui/patch_building_panel.go b/pkg/gui/patch_building_panel.go index eb7728100..865e1162c 100644 --- a/pkg/gui/patch_building_panel.go +++ b/pkg/gui/patch_building_panel.go @@ -18,7 +18,7 @@ func (gui *Gui) getFromAndReverseArgsForDiff(to string) (string, bool) { } func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error { - if !gui.Git.Patch.PatchManager.Active() { + if !gui.git.Patch.PatchManager.Active() { return gui.handleEscapePatchBuildingPanel() } @@ -33,12 +33,12 @@ func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error { to := gui.State.CommitFileTreeViewModel.GetParent() from, reverse := gui.getFromAndReverseArgsForDiff(to) - diff, err := gui.Git.WorkingTree.ShowFileDiff(from, to, reverse, node.GetPath(), true) + diff, err := gui.git.WorkingTree.ShowFileDiff(from, to, reverse, node.GetPath(), true) if err != nil { return err } - secondaryDiff := gui.Git.Patch.PatchManager.RenderPatchForFile(node.GetPath(), true, false, true) + secondaryDiff := gui.git.Patch.PatchManager.RenderPatchForFile(node.GetPath(), true, false, true) if err != nil { return err } @@ -75,15 +75,15 @@ func (gui *Gui) onPatchBuildingFocus(selectedLineIdx int) error { func (gui *Gui) handleToggleSelectionForPatch() error { err := gui.withLBLActiveCheck(func(state *LblPanelState) error { - toggleFunc := gui.Git.Patch.PatchManager.AddFileLineRange + toggleFunc := gui.git.Patch.PatchManager.AddFileLineRange filename := gui.getSelectedCommitFileName() - includedLineIndices, err := gui.Git.Patch.PatchManager.GetFileIncLineIndices(filename) + includedLineIndices, err := gui.git.Patch.PatchManager.GetFileIncLineIndices(filename) if err != nil { return err } currentLineIsStaged := utils.IncludesInt(includedLineIndices, state.GetSelectedLineIdx()) if currentLineIsStaged { - toggleFunc = gui.Git.Patch.PatchManager.RemoveFileLineRange + toggleFunc = gui.git.Patch.PatchManager.RemoveFileLineRange } // add range of lines to those set for the file @@ -96,7 +96,7 @@ func (gui *Gui) handleToggleSelectionForPatch() error { if err := toggleFunc(node.GetPath(), firstLineIdx, lastLineIdx); err != nil { // might actually want to return an error here - gui.Log.Error(err) + gui.c.Log.Error(err) } return nil @@ -116,12 +116,12 @@ func (gui *Gui) handleToggleSelectionForPatch() error { func (gui *Gui) handleEscapePatchBuildingPanel() error { gui.escapeLineByLinePanel() - if gui.Git.Patch.PatchManager.IsEmpty() { - gui.Git.Patch.PatchManager.Reset() + if gui.git.Patch.PatchManager.IsEmpty() { + gui.git.Patch.PatchManager.Reset() } if gui.currentContext().GetKey() == gui.State.Contexts.PatchBuilding.GetKey() { - return gui.pushContext(gui.State.Contexts.CommitFiles) + return gui.c.PushContext(gui.State.Contexts.CommitFiles) } else { // need to re-focus in case the secondary view should now be hidden return gui.currentContext().HandleFocus() @@ -129,8 +129,8 @@ func (gui *Gui) handleEscapePatchBuildingPanel() error { } func (gui *Gui) secondaryPatchPanelUpdateOpts() *viewUpdateOpts { - if gui.Git.Patch.PatchManager.Active() { - patch := gui.Git.Patch.PatchManager.RenderAggregatedPatchColored(false) + if gui.git.Patch.PatchManager.Active() { + patch := gui.git.Patch.PatchManager.RenderAggregatedPatchColored(false) return &viewUpdateOpts{ title: "Custom Patch", diff --git a/pkg/gui/patch_options_panel.go b/pkg/gui/patch_options_panel.go index 915572c16..5c321819a 100644 --- a/pkg/gui/patch_options_panel.go +++ b/pkg/gui/patch_options_panel.go @@ -9,8 +9,8 @@ import ( ) func (gui *Gui) handleCreatePatchOptionsMenu() error { - if !gui.Git.Patch.PatchManager.Active() { - return gui.PopupHandler.ErrorMsg(gui.Tr.NoPatchError) + if !gui.git.Patch.PatchManager.Active() { + return gui.c.ErrorMsg(gui.c.Tr.NoPatchError) } menuItems := []*popup.MenuItem{ @@ -28,10 +28,10 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error { }, } - if gui.Git.Patch.PatchManager.CanRebase && gui.Git.Status.WorkingTreeState() == enums.REBASE_MODE_NONE { + if gui.git.Patch.PatchManager.CanRebase && gui.git.Status.WorkingTreeState() == enums.REBASE_MODE_NONE { menuItems = append(menuItems, []*popup.MenuItem{ { - DisplayString: fmt.Sprintf("remove patch from original commit (%s)", gui.Git.Patch.PatchManager.To), + DisplayString: fmt.Sprintf("remove patch from original commit (%s)", gui.git.Patch.PatchManager.To), OnPress: gui.handleDeletePatchFromCommit, }, { @@ -46,7 +46,7 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error { if gui.currentContext().GetKey() == gui.State.Contexts.BranchCommits.GetKey() { selectedCommit := gui.getSelectedLocalCommit() - if selectedCommit != nil && gui.Git.Patch.PatchManager.To != selectedCommit.Sha { + if selectedCommit != nil && gui.git.Patch.PatchManager.To != selectedCommit.Sha { // adding this option to index 1 menuItems = append( menuItems[:1], @@ -63,12 +63,12 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error { } } - return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: gui.Tr.PatchOptionsTitle, Items: menuItems}) + return gui.c.Menu(popup.CreateMenuOptions{Title: gui.c.Tr.PatchOptionsTitle, Items: menuItems}) } func (gui *Gui) getPatchCommitIndex() int { for index, commit := range gui.State.Commits { - if commit.Sha == gui.Git.Patch.PatchManager.To { + if commit.Sha == gui.git.Patch.PatchManager.To { return index } } @@ -76,8 +76,8 @@ func (gui *Gui) getPatchCommitIndex() int { } func (gui *Gui) validateNormalWorkingTreeState() (bool, error) { - if gui.Git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE { - return false, gui.PopupHandler.ErrorMsg(gui.Tr.CantPatchWhileRebasingError) + if gui.git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE { + return false, gui.c.ErrorMsg(gui.c.Tr.CantPatchWhileRebasingError) } return true, nil } @@ -98,11 +98,11 @@ func (gui *Gui) handleDeletePatchFromCommit() error { return err } - return gui.PopupHandler.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { + return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() - gui.logAction(gui.Tr.Actions.RemovePatchFromCommit) - err := gui.Git.Patch.DeletePatchesFromCommit(gui.State.Commits, commitIndex) - return gui.handleGenericMergeCommandResult(err) + gui.c.LogAction(gui.c.Tr.Actions.RemovePatchFromCommit) + err := gui.git.Patch.DeletePatchesFromCommit(gui.State.Commits, commitIndex) + return gui.checkMergeOrRebase(err) }) } @@ -115,11 +115,11 @@ func (gui *Gui) handleMovePatchToSelectedCommit() error { return err } - return gui.PopupHandler.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { + return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() - gui.logAction(gui.Tr.Actions.MovePatchToSelectedCommit) - err := gui.Git.Patch.MovePatchToSelectedCommit(gui.State.Commits, commitIndex, gui.State.Panels.Commits.SelectedLineIdx) - return gui.handleGenericMergeCommandResult(err) + gui.c.LogAction(gui.c.Tr.Actions.MovePatchToSelectedCommit) + err := gui.git.Patch.MovePatchToSelectedCommit(gui.State.Commits, commitIndex, gui.State.Panels.Commits.SelectedLineIdx) + return gui.checkMergeOrRebase(err) }) } @@ -133,18 +133,18 @@ func (gui *Gui) handleMovePatchIntoWorkingTree() error { } pull := func(stash bool) error { - return gui.PopupHandler.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { + return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() - gui.logAction(gui.Tr.Actions.MovePatchIntoIndex) - err := gui.Git.Patch.MovePatchIntoIndex(gui.State.Commits, commitIndex, stash) - return gui.handleGenericMergeCommandResult(err) + gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoIndex) + err := gui.git.Patch.MovePatchIntoIndex(gui.State.Commits, commitIndex, stash) + return gui.checkMergeOrRebase(err) }) } - if len(gui.trackedFiles()) > 0 { - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.MustStashTitle, - Prompt: gui.Tr.MustStashWarning, + if gui.workingTreeHelper.IsWorkingTreeDirty() { + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.MustStashTitle, + Prompt: gui.c.Tr.MustStashWarning, HandleConfirm: func() error { return pull(true) }, @@ -163,11 +163,11 @@ func (gui *Gui) handlePullPatchIntoNewCommit() error { return err } - return gui.PopupHandler.WithWaitingStatus(gui.Tr.RebasingStatus, func() error { + return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() - gui.logAction(gui.Tr.Actions.MovePatchIntoNewCommit) - err := gui.Git.Patch.PullPatchIntoNewCommit(gui.State.Commits, commitIndex) - return gui.handleGenericMergeCommandResult(err) + gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoNewCommit) + err := gui.git.Patch.PullPatchIntoNewCommit(gui.State.Commits, commitIndex) + return gui.checkMergeOrRebase(err) }) } @@ -176,21 +176,21 @@ func (gui *Gui) handleApplyPatch(reverse bool) error { return err } - action := gui.Tr.Actions.ApplyPatch + action := gui.c.Tr.Actions.ApplyPatch if reverse { action = "Apply patch in reverse" } - gui.logAction(action) - if err := gui.Git.Patch.PatchManager.ApplyPatches(reverse); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(action) + if err := gui.git.Patch.PatchManager.ApplyPatches(reverse); err != nil { + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) } func (gui *Gui) handleResetPatch() error { - gui.Git.Patch.PatchManager.Reset() + gui.git.Patch.PatchManager.Reset() if gui.currentContextKeyIgnoringPopups() == MAIN_PATCH_BUILDING_CONTEXT_KEY { - if err := gui.pushContext(gui.State.Contexts.CommitFiles); err != nil { + if err := gui.c.PushContext(gui.State.Contexts.CommitFiles); err != nil { return err } } diff --git a/pkg/gui/popup/popup_handler.go b/pkg/gui/popup/popup_handler.go index adc276d5f..bba0e52a8 100644 --- a/pkg/gui/popup/popup_handler.go +++ b/pkg/gui/popup/popup_handler.go @@ -19,6 +19,8 @@ type IPopupHandler interface { WithLoaderPanel(message string, f func() error) error WithWaitingStatus(message string, f func() error) error Menu(opts CreateMenuOptions) error + Toast(message string) + GetPromptInput() string } type CreateMenuOptions struct { @@ -74,6 +76,8 @@ type RealPopupHandler struct { closePopupFn func() error createMenuFn func(CreateMenuOptions) error withWaitingStatusFn func(message string, f func() error) error + toastFn func(message string) + getPromptInputFn func() string } var _ IPopupHandler = &RealPopupHandler{} @@ -85,6 +89,8 @@ func NewPopupHandler( closePopupFn func() error, createMenuFn func(CreateMenuOptions) error, withWaitingStatusFn func(message string, f func() error) error, + toastFn func(message string), + getPromptInputFn func() string, ) *RealPopupHandler { return &RealPopupHandler{ Common: common, @@ -94,6 +100,8 @@ func NewPopupHandler( closePopupFn: closePopupFn, createMenuFn: createMenuFn, withWaitingStatusFn: withWaitingStatusFn, + toastFn: toastFn, + getPromptInputFn: getPromptInputFn, } } @@ -101,6 +109,10 @@ func (self *RealPopupHandler) Menu(opts CreateMenuOptions) error { return self.createMenuFn(opts) } +func (self *RealPopupHandler) Toast(message string) { + self.toastFn(message) +} + func (self *RealPopupHandler) WithWaitingStatus(message string, f func() error) error { return self.withWaitingStatusFn(message, f) } @@ -188,6 +200,12 @@ func (self *RealPopupHandler) WithLoaderPanel(message string, f func() error) er return nil } +// returns the content that has currently been typed into the prompt. Useful for +// asyncronously updating the suggestions list under the prompt. +func (self *RealPopupHandler) GetPromptInput() string { + return self.getPromptInputFn() +} + type TestPopupHandler struct { OnErrorMsg func(message string) error OnAsk func(opts AskOpts) error @@ -221,3 +239,11 @@ func (self *TestPopupHandler) WithWaitingStatus(message string, f func() error) func (self *TestPopupHandler) Menu(opts CreateMenuOptions) error { panic("not yet implemented") } + +func (self *TestPopupHandler) Toast(message string) { + panic("not yet implemented") +} + +func (self *TestPopupHandler) CurrentInput() string { + panic("not yet implemented") +} diff --git a/pkg/gui/pty.go b/pkg/gui/pty.go index b6c3069f2..a183be880 100644 --- a/pkg/gui/pty.go +++ b/pkg/gui/pty.go @@ -41,7 +41,7 @@ func (gui *Gui) onResize() error { // command. func (gui *Gui) newPtyTask(view *gocui.View, cmd *exec.Cmd, prefix string) error { width, _ := gui.Views.Main.Size() - pager := gui.Git.Config.GetPager(width) + pager := gui.git.Config.GetPager(width) if pager == "" { // if we're not using a custom pager we don't need to use a pty @@ -60,7 +60,7 @@ func (gui *Gui) newPtyTask(view *gocui.View, cmd *exec.Cmd, prefix string) error start := func() (*exec.Cmd, io.Reader) { ptmx, err := pty.StartWithSize(cmd, gui.desiredPtySize()) if err != nil { - gui.Log.Error(err) + gui.c.Log.Error(err) } gui.State.Ptmx = ptmx diff --git a/pkg/gui/pull_request_menu_panel.go b/pkg/gui/pull_request_menu_panel.go index 5c2a3df8d..9973daeca 100644 --- a/pkg/gui/pull_request_menu_panel.go +++ b/pkg/gui/pull_request_menu_panel.go @@ -18,17 +18,17 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB menuItemsForBranch := func(branch *models.Branch) []*popup.MenuItem { return []*popup.MenuItem{ { - DisplayStrings: fromToDisplayStrings(branch.Name, gui.Tr.LcDefaultBranch), + DisplayStrings: fromToDisplayStrings(branch.Name, gui.c.Tr.LcDefaultBranch), OnPress: func() error { return gui.createPullRequest(branch.Name, "") }, }, { - DisplayStrings: fromToDisplayStrings(branch.Name, gui.Tr.LcSelectBranch), + DisplayStrings: fromToDisplayStrings(branch.Name, gui.c.Tr.LcSelectBranch), OnPress: func() error { - return gui.PopupHandler.Prompt(popup.PromptOpts{ + return gui.c.Prompt(popup.PromptOpts{ Title: branch.Name + " 鈫", - FindSuggestionsFunc: gui.getBranchNameSuggestionsFunc(), + FindSuggestionsFunc: gui.suggestionsHelper.GetBranchNameSuggestionsFunc(), HandleConfirm: func(targetBranchName string) error { return gui.createPullRequest(branch.Name, targetBranchName) }}, @@ -52,27 +52,27 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB menuItems = append(menuItems, menuItemsForBranch(selectedBranch)...) - return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: fmt.Sprintf(gui.Tr.CreatePullRequestOptions), Items: menuItems}) + return gui.c.Menu(popup.CreateMenuOptions{Title: fmt.Sprintf(gui.c.Tr.CreatePullRequestOptions), Items: menuItems}) } func (gui *Gui) createPullRequest(from string, to string) error { hostingServiceMgr := gui.getHostingServiceMgr() url, err := hostingServiceMgr.GetPullRequestURL(from, to) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } - gui.logAction(gui.Tr.Actions.OpenPullRequest) + gui.c.LogAction(gui.c.Tr.Actions.OpenPullRequest) if err := gui.OSCommand.OpenLink(url); err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } return nil } func (gui *Gui) getHostingServiceMgr() *hosting_service.HostingServiceMgr { - remoteUrl := gui.Git.Config.GetRemoteURL() - configServices := gui.UserConfig.Services + remoteUrl := gui.git.Config.GetRemoteURL() + configServices := gui.c.UserConfig.Services return hosting_service.NewHostingServiceMgr(gui.Log, gui.Tr, remoteUrl, configServices) } diff --git a/pkg/gui/quitting.go b/pkg/gui/quitting.go index 4e9242640..edf402159 100644 --- a/pkg/gui/quitting.go +++ b/pkg/gui/quitting.go @@ -44,7 +44,7 @@ func (gui *Gui) handleTopLevelReturn() error { parentContext, hasParent := currentContext.GetParentContext() if hasParent && currentContext != nil && parentContext != nil { // TODO: think about whether this should be marked as a return rather than adding to the stack - return gui.pushContext(parentContext) + return gui.c.PushContext(parentContext) } for _, mode := range gui.modeStatuses() { @@ -60,7 +60,7 @@ func (gui *Gui) handleTopLevelReturn() error { return gui.dispatchSwitchToRepo(path, true) } - if gui.UserConfig.QuitOnTopLevelReturn { + if gui.c.UserConfig.QuitOnTopLevelReturn { return gui.handleQuit() } @@ -72,10 +72,10 @@ func (gui *Gui) quit() error { return gui.createUpdateQuitConfirmation() } - if gui.UserConfig.ConfirmOnQuit { - return gui.PopupHandler.Ask(popup.AskOpts{ + if gui.c.UserConfig.ConfirmOnQuit { + return gui.c.Ask(popup.AskOpts{ Title: "", - Prompt: gui.Tr.ConfirmQuit, + Prompt: gui.c.Tr.ConfirmQuit, HandleConfirm: func() error { return gocui.ErrQuit }, diff --git a/pkg/gui/rebase_options_panel.go b/pkg/gui/rebase_options_panel.go index b4a37e956..467665f84 100644 --- a/pkg/gui/rebase_options_panel.go +++ b/pkg/gui/rebase_options_panel.go @@ -20,7 +20,7 @@ const ( func (gui *Gui) handleCreateRebaseOptionsMenu() error { options := []string{REBASE_OPTION_CONTINUE, REBASE_OPTION_ABORT} - if gui.Git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING { + if gui.git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING { options = append(options, REBASE_OPTION_SKIP) } @@ -37,23 +37,23 @@ func (gui *Gui) handleCreateRebaseOptionsMenu() error { } var title string - if gui.Git.Status.WorkingTreeState() == enums.REBASE_MODE_MERGING { - title = gui.Tr.MergeOptionsTitle + if gui.git.Status.WorkingTreeState() == enums.REBASE_MODE_MERGING { + title = gui.c.Tr.MergeOptionsTitle } else { - title = gui.Tr.RebaseOptionsTitle + title = gui.c.Tr.RebaseOptionsTitle } - return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: title, Items: menuItems}) + return gui.c.Menu(popup.CreateMenuOptions{Title: title, Items: menuItems}) } func (gui *Gui) genericMergeCommand(command string) error { - status := gui.Git.Status.WorkingTreeState() + status := gui.git.Status.WorkingTreeState() if status != enums.REBASE_MODE_MERGING && status != enums.REBASE_MODE_REBASING { - return gui.PopupHandler.ErrorMsg(gui.Tr.NotMergingOrRebasing) + return gui.c.ErrorMsg(gui.c.Tr.NotMergingOrRebasing) } - gui.logAction(fmt.Sprintf("Merge/Rebase: %s", command)) + gui.c.LogAction(fmt.Sprintf("Merge/Rebase: %s", command)) commandType := "" switch status { @@ -68,14 +68,14 @@ func (gui *Gui) genericMergeCommand(command string) error { // we should end up with a command like 'git merge --continue' // it's impossible for a rebase to require a commit so we'll use a subprocess only if it's a merge - if status == enums.REBASE_MODE_MERGING && command != REBASE_OPTION_ABORT && gui.UserConfig.Git.Merging.ManualCommit { + if status == enums.REBASE_MODE_MERGING && command != REBASE_OPTION_ABORT && gui.c.UserConfig.Git.Merging.ManualCommit { // TODO: see if we should be calling more of the code from gui.Git.Rebase.GenericMergeOrRebaseAction return gui.runSubprocessWithSuspenseAndRefresh( - gui.Git.Rebase.GenericMergeOrRebaseActionCmdObj(commandType, command), + gui.git.Rebase.GenericMergeOrRebaseActionCmdObj(commandType, command), ) } - result := gui.Git.Rebase.GenericMergeOrRebaseAction(commandType, command) - if err := gui.handleGenericMergeCommandResult(result); err != nil { + result := gui.git.Rebase.GenericMergeOrRebaseAction(commandType, command) + if err := gui.checkMergeOrRebase(result); err != nil { return err } return nil @@ -98,8 +98,8 @@ func isMergeConflictErr(errStr string) bool { return false } -func (gui *Gui) handleGenericMergeCommandResult(result error) error { - if err := gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC}); err != nil { +func (gui *Gui) checkMergeOrRebase(result error) error { + if err := gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil { return err } if result == nil { @@ -112,12 +112,12 @@ func (gui *Gui) handleGenericMergeCommandResult(result error) error { // assume in this case that we're already done return nil } else if isMergeConflictErr(result.Error()) { - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.FoundConflictsTitle, - Prompt: gui.Tr.FoundConflicts, + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.FoundConflictsTitle, + Prompt: gui.c.Tr.FoundConflicts, HandlersManageFocus: true, HandleConfirm: func() error { - return gui.pushContext(gui.State.Contexts.Files) + return gui.c.PushContext(gui.State.Contexts.Files) }, HandleClose: func() error { if err := gui.returnFromContext(); err != nil { @@ -128,16 +128,16 @@ func (gui *Gui) handleGenericMergeCommandResult(result error) error { }, }) } else { - return gui.PopupHandler.ErrorMsg(result.Error()) + return gui.c.ErrorMsg(result.Error()) } } func (gui *Gui) abortMergeOrRebaseWithConfirm() error { // prompt user to confirm that they want to abort, then do it mode := gui.workingTreeStateNoun() - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: fmt.Sprintf(gui.Tr.AbortTitle, mode), - Prompt: fmt.Sprintf(gui.Tr.AbortPrompt, mode), + return gui.c.Ask(popup.AskOpts{ + Title: fmt.Sprintf(gui.c.Tr.AbortTitle, mode), + Prompt: fmt.Sprintf(gui.c.Tr.AbortPrompt, mode), HandleConfirm: func() error { return gui.genericMergeCommand(REBASE_OPTION_ABORT) }, @@ -145,7 +145,7 @@ func (gui *Gui) abortMergeOrRebaseWithConfirm() error { } func (gui *Gui) workingTreeStateNoun() string { - workingTreeState := gui.Git.Status.WorkingTreeState() + workingTreeState := gui.git.Status.WorkingTreeState() switch workingTreeState { case enums.REBASE_MODE_NONE: return "" diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index ec6a1ffc7..428faa9c9 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -13,7 +13,7 @@ import ( ) func (gui *Gui) handleCreateRecentReposMenu() error { - recentRepoPaths := gui.Config.GetAppState().RecentRepos + recentRepoPaths := gui.c.GetAppState().RecentRepos reposCount := utils.Min(len(recentRepoPaths), 20) // we won't show the current repo hence the -1 @@ -34,11 +34,11 @@ func (gui *Gui) handleCreateRecentReposMenu() error { } } - return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: gui.Tr.RecentRepos, Items: menuItems}) + return gui.c.Menu(popup.CreateMenuOptions{Title: gui.c.Tr.RecentRepos, Items: menuItems}) } func (gui *Gui) handleShowAllBranchLogs() error { - cmdObj := gui.Git.Branch.AllBranchesLogCmdObj() + cmdObj := gui.git.Branch.AllBranchesLogCmdObj() task := NewRunPtyTask(cmdObj.GetCmd()) return gui.refreshMainViews(refreshMainOpts{ @@ -58,7 +58,7 @@ func (gui *Gui) dispatchSwitchToRepo(path string, reuse bool) error { if err := os.Chdir(path); err != nil { if os.IsNotExist(err) { - return gui.PopupHandler.ErrorMsg(gui.Tr.ErrRepositoryMovedOrDeleted) + return gui.c.ErrorMsg(gui.c.Tr.ErrRepositoryMovedOrDeleted) } return err } @@ -71,11 +71,16 @@ func (gui *Gui) dispatchSwitchToRepo(path string, reuse bool) error { return err } - newGitCommand, err := commands.NewGitCommand(gui.Common, gui.OSCommand, git_config.NewStdCachedGitConfig(gui.Log)) + newGitCommand, err := commands.NewGitCommand( + gui.Common, + gui.OSCommand, + git_config.NewStdCachedGitConfig(gui.Log), + gui.Mutexes.FetchMutex, + ) if err != nil { return err } - gui.Git = newGitCommand + gui.git = newGitCommand // these two mutexes are used by our background goroutines (triggered via `gui.goEvery`. We don't want to // switch to a repo while one of these goroutines is in the process of updating something @@ -97,23 +102,23 @@ func (gui *Gui) dispatchSwitchToRepo(path string, reuse bool) error { // updateRecentRepoList registers the fact that we opened lazygit in this repo, // so that we can open the same repo via the 'recent repos' menu func (gui *Gui) updateRecentRepoList() error { - if gui.Git.Status.IsBareRepo() { + if gui.git.Status.IsBareRepo() { // we could totally do this but it would require storing both the git-dir and the // worktree in our recent repos list, which is a change that would need to be // backwards compatible - gui.Log.Info("Not appending bare repo to recent repo list") + gui.c.Log.Info("Not appending bare repo to recent repo list") return nil } - recentRepos := gui.Config.GetAppState().RecentRepos + recentRepos := gui.c.GetAppState().RecentRepos currentRepo, err := os.Getwd() if err != nil { return err } known, recentRepos := newRecentReposList(recentRepos, currentRepo) gui.IsNewRepo = known - gui.Config.GetAppState().RecentRepos = recentRepos - return gui.Config.SaveAppState() + gui.c.GetAppState().RecentRepos = recentRepos + return gui.c.SaveAppState() } // newRecentReposList returns a new repo list with a new entry but only when it doesn't exist yet diff --git a/pkg/gui/ref_helper.go b/pkg/gui/ref_helper.go new file mode 100644 index 000000000..c8cccb74a --- /dev/null +++ b/pkg/gui/ref_helper.go @@ -0,0 +1,137 @@ +package gui + +import ( + "fmt" + "strings" + + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" + "github.com/jesseduffield/lazygit/pkg/gui/controllers" + "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/style" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type RefHelper struct { + c *controllers.ControllerCommon + git *commands.GitCommand + + State *GuiRepoState +} + +func NewRefHelper( + c *controllers.ControllerCommon, + git *commands.GitCommand, + state *GuiRepoState, +) *RefHelper { + return &RefHelper{ + c: c, + git: git, + State: state, + } +} + +var _ controllers.IRefHelper = &RefHelper{} + +func (self *RefHelper) CheckoutRef(ref string, options types.CheckoutRefOptions) error { + waitingStatus := options.WaitingStatus + if waitingStatus == "" { + waitingStatus = self.c.Tr.CheckingOutStatus + } + + cmdOptions := git_commands.CheckoutOptions{Force: false, EnvVars: options.EnvVars} + + onSuccess := func() { + self.State.Panels.Branches.SelectedLineIdx = 0 + self.State.Panels.Commits.SelectedLineIdx = 0 + // loading a heap of commits is slow so we limit them whenever doing a reset + self.State.Panels.Commits.LimitCommits = true + } + + return self.c.WithWaitingStatus(waitingStatus, func() error { + if err := self.git.Branch.Checkout(ref, cmdOptions); err != nil { + // note, this will only work for english-language git commands. If we force git to use english, and the error isn't this one, then the user will receive an english command they may not understand. I'm not sure what the best solution to this is. Running the command once in english and a second time in the native language is one option + + if options.OnRefNotFound != nil && strings.Contains(err.Error(), "did not match any file(s) known to git") { + return options.OnRefNotFound(ref) + } + + if strings.Contains(err.Error(), "Please commit your changes or stash them before you switch branch") { + // offer to autostash changes + return self.c.Ask(popup.AskOpts{ + + Title: self.c.Tr.AutoStashTitle, + Prompt: self.c.Tr.AutoStashPrompt, + HandleConfirm: func() error { + if err := self.git.Stash.Save(self.c.Tr.StashPrefix + ref); err != nil { + return self.c.Error(err) + } + if err := self.git.Branch.Checkout(ref, cmdOptions); err != nil { + return self.c.Error(err) + } + + onSuccess() + if err := self.git.Stash.Pop(0); err != nil { + if err := self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI}); err != nil { + return err + } + return self.c.Error(err) + } + return self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI}) + }, + }) + } + + if err := self.c.Error(err); err != nil { + return err + } + } + onSuccess() + + return self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI}) + }) +} + +func (self *RefHelper) ResetToRef(ref string, strength string, envVars []string) error { + if err := self.git.Commit.ResetToCommit(ref, strength, envVars); err != nil { + return self.c.Error(err) + } + + self.State.Panels.Commits.SelectedLineIdx = 0 + self.State.Panels.ReflogCommits.SelectedLineIdx = 0 + // loading a heap of commits is slow so we limit them whenever doing a reset + self.State.Panels.Commits.LimitCommits = true + + if err := self.c.PushContext(self.State.Contexts.BranchCommits); err != nil { + return err + } + + if err := self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES, types.BRANCHES, types.REFLOG, types.COMMITS}}); err != nil { + return err + } + + return nil +} + +func (self *RefHelper) CreateGitResetMenu(ref string) error { + strengths := []string{"soft", "mixed", "hard"} + menuItems := make([]*popup.MenuItem, len(strengths)) + for i, strength := range strengths { + strength := strength + menuItems[i] = &popup.MenuItem{ + DisplayStrings: []string{ + fmt.Sprintf("%s reset", strength), + style.FgRed.Sprintf("reset --%s %s", strength, ref), + }, + OnPress: func() error { + self.c.LogAction("Reset") + return self.ResetToRef(ref, strength, []string{}) + }, + } + } + + return self.c.Menu(popup.CreateMenuOptions{ + Title: fmt.Sprintf("%s %s", self.c.Tr.LcResetTo, ref), + Items: menuItems, + }) +} diff --git a/pkg/gui/reflog_panel.go b/pkg/gui/reflog_panel.go index 3ccbdb7c8..f562036ad 100644 --- a/pkg/gui/reflog_panel.go +++ b/pkg/gui/reflog_panel.go @@ -2,7 +2,9 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) // list panel functions @@ -23,7 +25,7 @@ func (gui *Gui) reflogCommitsRenderToMain() error { if commit == nil { task = NewRenderStringTask("No reflog history") } else { - cmdObj := gui.Git.Commit.ShowCmdObj(commit.Sha, gui.State.Modes.Filtering.GetPath()) + cmdObj := gui.git.Commit.ShowCmdObj(commit.Sha, gui.State.Modes.Filtering.GetPath()) task = NewRunPtyTask(cmdObj.GetCmd()) } @@ -53,10 +55,10 @@ func (gui *Gui) refreshReflogCommits() error { } refresh := func(stateCommits *[]*models.Commit, filterPath string) error { - commits, onlyObtainedNewReflogCommits, err := gui.Git.Loaders.ReflogCommits. + commits, onlyObtainedNewReflogCommits, err := gui.git.Loaders.ReflogCommits. GetReflogCommits(lastReflogCommit, filterPath) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } if onlyObtainedNewReflogCommits { @@ -79,21 +81,21 @@ func (gui *Gui) refreshReflogCommits() error { state.FilteredReflogCommits = state.ReflogCommits } - return gui.postRefreshUpdate(gui.State.Contexts.ReflogCommits) + return gui.c.PostRefreshUpdate(gui.State.Contexts.ReflogCommits) } -func (gui *Gui) handleCheckoutReflogCommit() error { +func (gui *Gui) CheckoutReflogCommit() error { commit := gui.getSelectedReflogCommit() if commit == nil { return nil } - err := gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.LcCheckoutCommit, - Prompt: gui.Tr.SureCheckoutThisCommit, + err := gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.LcCheckoutCommit, + Prompt: gui.c.Tr.SureCheckoutThisCommit, HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.CheckoutReflogCommit) - return gui.handleCheckoutRef(commit.Sha, handleCheckoutRefOptions{}) + gui.c.LogAction(gui.c.Tr.Actions.CheckoutReflogCommit) + return gui.refHelper.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) }, }) if err != nil { @@ -108,7 +110,7 @@ func (gui *Gui) handleCheckoutReflogCommit() error { func (gui *Gui) handleCreateReflogResetMenu() error { commit := gui.getSelectedReflogCommit() - return gui.createResetMenu(commit.Sha) + return gui.refHelper.CreateGitResetMenu(commit.Sha) } func (gui *Gui) handleViewReflogCommitFiles() error { @@ -117,5 +119,10 @@ func (gui *Gui) handleViewReflogCommitFiles() error { return nil } - return gui.switchToCommitFilesContext(commit.Sha, false, gui.State.Contexts.ReflogCommits, "commits") + return gui.SwitchToCommitFilesContext(controllers.SwitchToCommitFilesContextOpts{ + RefName: commit.Sha, + CanRebase: false, + Context: gui.State.Contexts.ReflogCommits, + WindowName: "commits", + }) } diff --git a/pkg/gui/remote_branches_panel.go b/pkg/gui/remote_branches_panel.go index 1ee402097..29e2e2f03 100644 --- a/pkg/gui/remote_branches_panel.go +++ b/pkg/gui/remote_branches_panel.go @@ -26,7 +26,7 @@ func (gui *Gui) remoteBranchesRenderToMain() error { if remoteBranch == nil { task = NewRenderStringTask("No branches for this remote") } else { - cmdObj := gui.Git.Branch.GetGraphCmdObj(remoteBranch.FullName()) + cmdObj := gui.git.Branch.GetGraphCmdObj(remoteBranch.FullName()) task = NewRunCommandTask(cmdObj.GetCmd()) } @@ -39,7 +39,7 @@ func (gui *Gui) remoteBranchesRenderToMain() error { } func (gui *Gui) handleRemoteBranchesEscape() error { - return gui.pushContext(gui.State.Contexts.Remotes) + return gui.c.PushContext(gui.State.Contexts.Remotes) } func (gui *Gui) handleMergeRemoteBranch() error { @@ -52,20 +52,20 @@ func (gui *Gui) handleDeleteRemoteBranch() error { if remoteBranch == nil { return nil } - message := fmt.Sprintf("%s '%s'?", gui.Tr.DeleteRemoteBranchMessage, remoteBranch.FullName()) + message := fmt.Sprintf("%s '%s'?", gui.c.Tr.DeleteRemoteBranchMessage, remoteBranch.FullName()) - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.DeleteRemoteBranch, + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.DeleteRemoteBranch, Prompt: message, HandleConfirm: func() error { - return gui.PopupHandler.WithWaitingStatus(gui.Tr.DeletingStatus, func() error { - gui.logAction(gui.Tr.Actions.DeleteRemoteBranch) - err := gui.Git.Remote.DeleteRemoteBranch(remoteBranch.RemoteName, remoteBranch.Name) + return gui.c.WithWaitingStatus(gui.c.Tr.DeletingStatus, func() error { + gui.c.LogAction(gui.c.Tr.Actions.DeleteRemoteBranch) + err := gui.git.Remote.DeleteRemoteBranch(remoteBranch.RemoteName, remoteBranch.Name) if err != nil { - _ = gui.PopupHandler.Error(err) + _ = gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) + return gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) }) }, }) @@ -81,23 +81,23 @@ func (gui *Gui) handleSetBranchUpstream() error { checkedOutBranch := gui.getCheckedOutBranch() message := utils.ResolvePlaceholderString( - gui.Tr.SetUpstreamMessage, + gui.c.Tr.SetUpstreamMessage, map[string]string{ "checkedOut": checkedOutBranch.Name, "selected": selectedBranch.FullName(), }, ) - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.SetUpstreamTitle, + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.SetUpstreamTitle, Prompt: message, HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.SetBranchUpstream) - if err := gui.Git.Branch.SetUpstream(selectedBranch.RemoteName, selectedBranch.Name, checkedOutBranch.Name); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.SetBranchUpstream) + if err := gui.git.Branch.SetUpstream(selectedBranch.RemoteName, selectedBranch.Name, checkedOutBranch.Name); err != nil { + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) + return gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) }, }) } @@ -108,5 +108,5 @@ func (gui *Gui) handleCreateResetToRemoteBranchMenu() error { return nil } - return gui.createResetMenu(selectedBranch.FullName()) + return gui.refHelper.CreateGitResetMenu(selectedBranch.FullName()) } diff --git a/pkg/gui/remotes_panel.go b/pkg/gui/remotes_panel.go index bc06f77f0..1c086e2fc 100644 --- a/pkg/gui/remotes_panel.go +++ b/pkg/gui/remotes_panel.go @@ -5,10 +5,8 @@ import ( "strings" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/jesseduffield/lazygit/pkg/utils" ) // list panel functions @@ -42,9 +40,9 @@ func (gui *Gui) remotesRenderToMain() error { func (gui *Gui) refreshRemotes() error { prevSelectedRemote := gui.getSelectedRemote() - remotes, err := gui.Git.Loaders.Remotes.GetRemotes() + remotes, err := gui.git.Loaders.Remotes.GetRemotes() if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } gui.State.Remotes = remotes @@ -59,133 +57,5 @@ func (gui *Gui) refreshRemotes() error { } } - return gui.postRefreshUpdate(gui.mustContextForContextKey(ContextKey(gui.Views.Branches.Context))) -} - -func (gui *Gui) handleRemoteEnter() error { - // naive implementation: get the branches and render them to the list, change the context - remote := gui.getSelectedRemote() - if remote == nil { - return nil - } - - gui.State.RemoteBranches = remote.Branches - - newSelectedLine := 0 - if len(remote.Branches) == 0 { - newSelectedLine = -1 - } - gui.State.Panels.RemoteBranches.SelectedLineIdx = newSelectedLine - - return gui.pushContext(gui.State.Contexts.RemoteBranches) -} - -func (gui *Gui) handleAddRemote() error { - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: gui.Tr.LcNewRemoteName, - HandleConfirm: func(remoteName string) error { - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: gui.Tr.LcNewRemoteUrl, - HandleConfirm: func(remoteUrl string) error { - gui.logAction(gui.Tr.Actions.AddRemote) - if err := gui.Git.Remote.AddRemote(remoteName, remoteUrl); err != nil { - return err - } - return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.REMOTES}}) - }, - }) - }, - }) - -} - -func (gui *Gui) handleRemoveRemote() error { - remote := gui.getSelectedRemote() - if remote == nil { - return nil - } - - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.LcRemoveRemote, - Prompt: gui.Tr.LcRemoveRemotePrompt + " '" + remote.Name + "'?", - HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.RemoveRemote) - if err := gui.Git.Remote.RemoveRemote(remote.Name); err != nil { - return gui.PopupHandler.Error(err) - } - - return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) - }, - }) -} - -func (gui *Gui) handleEditRemote() error { - remote := gui.getSelectedRemote() - if remote == nil { - return nil - } - - editNameMessage := utils.ResolvePlaceholderString( - gui.Tr.LcEditRemoteName, - map[string]string{ - "remoteName": remote.Name, - }, - ) - - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: editNameMessage, - InitialContent: remote.Name, - HandleConfirm: func(updatedRemoteName string) error { - if updatedRemoteName != remote.Name { - gui.logAction(gui.Tr.Actions.UpdateRemote) - if err := gui.Git.Remote.RenameRemote(remote.Name, updatedRemoteName); err != nil { - return gui.PopupHandler.Error(err) - } - } - - editUrlMessage := utils.ResolvePlaceholderString( - gui.Tr.LcEditRemoteUrl, - map[string]string{ - "remoteName": updatedRemoteName, - }, - ) - - urls := remote.Urls - url := "" - if len(urls) > 0 { - url = urls[0] - } - - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: editUrlMessage, - InitialContent: url, - HandleConfirm: func(updatedRemoteUrl string) error { - gui.logAction(gui.Tr.Actions.UpdateRemote) - if err := gui.Git.Remote.UpdateRemoteUrl(updatedRemoteName, updatedRemoteUrl); err != nil { - return gui.PopupHandler.Error(err) - } - return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) - }, - }) - }, - }) -} - -func (gui *Gui) handleFetchRemote() error { - remote := gui.getSelectedRemote() - if remote == nil { - return nil - } - - return gui.PopupHandler.WithWaitingStatus(gui.Tr.FetchingRemoteStatus, func() error { - gui.Mutexes.FetchMutex.Lock() - defer gui.Mutexes.FetchMutex.Unlock() - - err := gui.Git.Sync.FetchRemote(remote.Name) - if err != nil { - _ = gui.PopupHandler.Error(err) - } - - return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) - }) + return gui.c.PostRefreshUpdate(gui.mustContextForContextKey(types.ContextKey(gui.Views.Branches.Context))) } diff --git a/pkg/gui/reset_menu_panel.go b/pkg/gui/reset_menu_panel.go deleted file mode 100644 index d920765f9..000000000 --- a/pkg/gui/reset_menu_panel.go +++ /dev/null @@ -1,53 +0,0 @@ -package gui - -import ( - "fmt" - - "github.com/jesseduffield/lazygit/pkg/gui/popup" - "github.com/jesseduffield/lazygit/pkg/gui/style" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - -func (gui *Gui) resetToRef(ref string, strength string, envVars []string) error { - if err := gui.Git.Commit.ResetToCommit(ref, strength, envVars); err != nil { - return gui.PopupHandler.Error(err) - } - - gui.State.Panels.Commits.SelectedLineIdx = 0 - gui.State.Panels.ReflogCommits.SelectedLineIdx = 0 - // loading a heap of commits is slow so we limit them whenever doing a reset - gui.State.Panels.Commits.LimitCommits = true - - if err := gui.pushContext(gui.State.Contexts.BranchCommits); err != nil { - return err - } - - if err := gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES, types.BRANCHES, types.REFLOG, types.COMMITS}}); err != nil { - return err - } - - return nil -} - -func (gui *Gui) createResetMenu(ref string) error { - strengths := []string{"soft", "mixed", "hard"} - menuItems := make([]*popup.MenuItem, len(strengths)) - for i, strength := range strengths { - strength := strength - menuItems[i] = &popup.MenuItem{ - DisplayStrings: []string{ - fmt.Sprintf("%s reset", strength), - style.FgRed.Sprintf("reset --%s %s", strength, ref), - }, - OnPress: func() error { - gui.logAction("Reset") - return gui.resetToRef(ref, strength, []string{}) - }, - } - } - - return gui.PopupHandler.Menu(popup.CreateMenuOptions{ - Title: fmt.Sprintf("%s %s", gui.Tr.LcResetTo, ref), - Items: menuItems, - }) -} diff --git a/pkg/gui/searching.go b/pkg/gui/searching.go index dd7697363..25a3ff63a 100644 --- a/pkg/gui/searching.go +++ b/pkg/gui/searching.go @@ -17,7 +17,7 @@ func (gui *Gui) handleOpenSearch(viewName string) error { gui.Views.Search.ClearTextArea() - if err := gui.pushContext(gui.State.Contexts.Search); err != nil { + if err := gui.c.PushContext(gui.State.Contexts.Search); err != nil { return err } @@ -43,7 +43,7 @@ func (gui *Gui) handleSearch() error { } func (gui *Gui) onSelectItemWrapper(innerFunc func(int) error) func(int, int, int) error { - keybindingConfig := gui.UserConfig.Keybinding + keybindingConfig := gui.c.UserConfig.Keybinding return func(y int, index int, total int) error { if total == 0 { diff --git a/pkg/gui/staging_panel.go b/pkg/gui/staging_panel.go index f4cd98ea2..f04f1e3ff 100644 --- a/pkg/gui/staging_panel.go +++ b/pkg/gui/staging_panel.go @@ -28,16 +28,16 @@ func (gui *Gui) refreshStagingPanel(forceSecondaryFocused bool, selectedLineIdx } if secondaryFocused { - gui.Views.Main.Title = gui.Tr.StagedChanges - gui.Views.Secondary.Title = gui.Tr.UnstagedChanges + gui.Views.Main.Title = gui.c.Tr.StagedChanges + gui.Views.Secondary.Title = gui.c.Tr.UnstagedChanges } else { - gui.Views.Main.Title = gui.Tr.UnstagedChanges - gui.Views.Secondary.Title = gui.Tr.StagedChanges + gui.Views.Main.Title = gui.c.Tr.UnstagedChanges + gui.Views.Secondary.Title = gui.c.Tr.StagedChanges } // note for custom diffs, we'll need to send a flag here saying not to use the custom diff - diff := gui.Git.WorkingTree.WorktreeFileDiff(file, true, secondaryFocused, false) - secondaryDiff := gui.Git.WorkingTree.WorktreeFileDiff(file, true, !secondaryFocused, false) + diff := gui.git.WorkingTree.WorktreeFileDiff(file, true, secondaryFocused, false) + secondaryDiff := gui.git.WorkingTree.WorktreeFileDiff(file, true, !secondaryFocused, false) // if we have e.g. a deleted file with nothing else to the diff will have only // 4-5 lines in which case we'll swap panels @@ -97,7 +97,7 @@ func (gui *Gui) handleTogglePanel() error { func (gui *Gui) handleStagingEscape() error { gui.escapeLineByLinePanel() - return gui.pushContext(gui.State.Contexts.Files) + return gui.c.PushContext(gui.State.Contexts.Files) } func (gui *Gui) handleToggleStagedSelection() error { @@ -113,10 +113,10 @@ func (gui *Gui) handleResetSelection() error { return gui.applySelection(true, state) } - if !gui.UserConfig.Gui.SkipUnstageLineWarning { - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.UnstageLinesTitle, - Prompt: gui.Tr.UnstageLinesPrompt, + if !gui.c.UserConfig.Gui.SkipUnstageLineWarning { + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.UnstageLinesTitle, + Prompt: gui.c.Tr.UnstageLinesPrompt, HandleConfirm: func() error { return gui.withLBLActiveCheck(func(state *LblPanelState) error { return gui.applySelection(true, state) @@ -148,17 +148,17 @@ func (gui *Gui) applySelection(reverse bool, state *LblPanelState) error { if !reverse || state.SecondaryFocused { applyFlags = append(applyFlags, "cached") } - gui.logAction(gui.Tr.Actions.ApplyPatch) - err := gui.Git.WorkingTree.ApplyPatch(patch, applyFlags...) + gui.c.LogAction(gui.c.Tr.Actions.ApplyPatch) + err := gui.git.WorkingTree.ApplyPatch(patch, applyFlags...) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } if state.SelectingRange() { state.SetLineSelectMode() } - if err := gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}); err != nil { + if err := gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}}); err != nil { return err } if err := gui.refreshStagingPanel(false, -1); err != nil { diff --git a/pkg/gui/stash_panel.go b/pkg/gui/stash_panel.go index f8121bf94..994548b0e 100644 --- a/pkg/gui/stash_panel.go +++ b/pkg/gui/stash_panel.go @@ -2,6 +2,7 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/popup" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -21,9 +22,9 @@ func (gui *Gui) stashRenderToMain() error { var task updateTask stashEntry := gui.getSelectedStashEntry() if stashEntry == nil { - task = NewRenderStringTask(gui.Tr.NoStashEntries) + task = NewRenderStringTask(gui.c.Tr.NoStashEntries) } else { - task = NewRunPtyTask(gui.Git.Stash.ShowStashEntryCmdObj(stashEntry.Index).GetCmd()) + task = NewRunPtyTask(gui.git.Stash.ShowStashEntryCmdObj(stashEntry.Index).GetCmd()) } return gui.refreshMainViews(refreshMainOpts{ @@ -35,7 +36,7 @@ func (gui *Gui) stashRenderToMain() error { } func (gui *Gui) refreshStashEntries() error { - gui.State.StashEntries = gui.Git.Loaders.Stash. + gui.State.StashEntries = gui.git.Loaders.Stash. GetStashEntries(gui.State.Modes.Filtering.GetPath()) return gui.postRefreshUpdate(gui.State.Contexts.Stash) @@ -49,14 +50,14 @@ func (gui *Gui) handleStashApply() error { return nil } - skipStashWarning := gui.UserConfig.Gui.SkipStashWarning + skipStashWarning := gui.c.UserConfig.Gui.SkipStashWarning apply := func() error { - gui.logAction(gui.Tr.Actions.Stash) - err := gui.Git.Stash.Apply(stashEntry.Index) + gui.c.LogAction(gui.c.Tr.Actions.Stash) + err := gui.git.Stash.Apply(stashEntry.Index) _ = gui.postStashRefresh() if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } return nil } @@ -65,9 +66,9 @@ func (gui *Gui) handleStashApply() error { return apply() } - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.StashApply, - Prompt: gui.Tr.SureApplyStashEntry, + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.StashApply, + Prompt: gui.c.Tr.SureApplyStashEntry, HandleConfirm: func() error { return apply() }, @@ -80,14 +81,14 @@ func (gui *Gui) handleStashPop() error { return nil } - skipStashWarning := gui.UserConfig.Gui.SkipStashWarning + skipStashWarning := gui.c.UserConfig.Gui.SkipStashWarning pop := func() error { - gui.logAction(gui.Tr.Actions.Stash) - err := gui.Git.Stash.Pop(stashEntry.Index) + gui.c.LogAction(gui.c.Tr.Actions.Stash) + err := gui.git.Stash.Pop(stashEntry.Index) _ = gui.postStashRefresh() if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } return nil } @@ -96,9 +97,9 @@ func (gui *Gui) handleStashPop() error { return pop() } - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.StashPop, - Prompt: gui.Tr.SurePopStashEntry, + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.StashPop, + Prompt: gui.c.Tr.SurePopStashEntry, HandleConfirm: func() error { return pop() }, @@ -111,15 +112,15 @@ func (gui *Gui) handleStashDrop() error { return nil } - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.StashDrop, - Prompt: gui.Tr.SureDropStashEntry, + return gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.StashDrop, + Prompt: gui.c.Tr.SureDropStashEntry, HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.Stash) - err := gui.Git.Stash.Drop(stashEntry.Index) - _ = gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{STASH}}) + gui.c.LogAction(gui.c.Tr.Actions.Stash) + err := gui.git.Stash.Drop(stashEntry.Index) + _ = gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}}) if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } return nil }, @@ -127,25 +128,7 @@ func (gui *Gui) handleStashDrop() error { } func (gui *Gui) postStashRefresh() error { - return gui.refreshSidePanels(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}}) -} - -func (gui *Gui) handleStashSave(stashFunc func(message string) error) error { - if len(gui.trackedFiles()) == 0 && len(gui.stagedFiles()) == 0 { - return gui.PopupHandler.ErrorMsg(gui.Tr.NoTrackedStagedFilesStash) - } - - return gui.prompt(promptOpts{ - title: gui.Tr.StashChanges, - handleConfirm: func(stashComment string) error { - err := stashFunc(stashComment) - _ = gui.postStashRefresh() - if err != nil { - return gui.PopupHandler.Error(err) - } - return nil - }, - }) + return gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}}) } func (gui *Gui) handleViewStashFiles() error { @@ -154,5 +137,10 @@ func (gui *Gui) handleViewStashFiles() error { return nil } - return gui.switchToCommitFilesContext(stashEntry.RefName(), false, gui.State.Contexts.Stash, "stash") + return gui.SwitchToCommitFilesContext(controllers.SwitchToCommitFilesContextOpts{ + RefName: stashEntry.RefName(), + CanRebase: false, + Context: gui.State.Contexts.Stash, + WindowName: "stash", + }) } diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go index d9fff2913..15c15987e 100644 --- a/pkg/gui/status_panel.go +++ b/pkg/gui/status_panel.go @@ -18,7 +18,7 @@ func (gui *Gui) refreshStatus() { gui.Mutexes.RefreshingStatusMutex.Lock() defer gui.Mutexes.RefreshingStatusMutex.Unlock() - currentBranch := gui.currentBranch() + currentBranch := gui.getCheckedOutBranch() if currentBranch == nil { // need to wait for branches to refresh return @@ -29,7 +29,7 @@ func (gui *Gui) refreshStatus() { status += presentation.ColoredBranchStatus(currentBranch) + " " } - workingTreeState := gui.Git.Status.WorkingTreeState() + workingTreeState := gui.git.Status.WorkingTreeState() if workingTreeState != enums.REBASE_MODE_NONE { status += style.FgYellow.Sprintf("(%s) ", formatWorkingTreeState(workingTreeState)) } @@ -50,7 +50,7 @@ func cursorInSubstring(cx int, prefix string, substring string) bool { } func (gui *Gui) handleCheckForUpdate() error { - return gui.PopupHandler.WithWaitingStatus(gui.Tr.CheckingForUpdates, func() error { + return gui.c.WithWaitingStatus(gui.c.Tr.CheckingForUpdates, func() error { gui.Updater.CheckForNewUpdate(gui.onUserUpdateCheckFinish, true) return nil }) @@ -62,20 +62,20 @@ func (gui *Gui) handleStatusClick() error { return nil } - currentBranch := gui.currentBranch() + currentBranch := gui.getCheckedOutBranch() if currentBranch == nil { // need to wait for branches to refresh return nil } - if err := gui.pushContext(gui.State.Contexts.Status); err != nil { + if err := gui.c.PushContext(gui.State.Contexts.Status); err != nil { return err } cx, _ := gui.Views.Status.Cursor() upstreamStatus := presentation.BranchStatus(currentBranch) repoName := utils.GetCurrentRepoName() - workingTreeState := gui.Git.Status.WorkingTreeState() + workingTreeState := gui.git.Status.WorkingTreeState() switch workingTreeState { case enums.REBASE_MODE_REBASING, enums.REBASE_MODE_MERGING: workingTreeStatus := fmt.Sprintf("(%s)", formatWorkingTreeState(workingTreeState)) @@ -135,7 +135,7 @@ func (gui *Gui) askForConfigFile(action func(file string) error) error { confPaths := gui.Config.GetUserConfigPaths() switch len(confPaths) { case 0: - return errors.New(gui.Tr.NoConfigFileFoundErr) + return errors.New(gui.c.Tr.NoConfigFileFoundErr) case 1: return action(confPaths[0]) default: @@ -149,8 +149,8 @@ func (gui *Gui) askForConfigFile(action func(file string) error) error { }, } } - return gui.PopupHandler.Menu(popup.CreateMenuOptions{ - Title: gui.Tr.SelectConfigFile, + return gui.c.Menu(popup.CreateMenuOptions{ + Title: gui.c.Tr.SelectConfigFile, Items: menuItems, HideCancel: true, }) @@ -158,11 +158,11 @@ func (gui *Gui) askForConfigFile(action func(file string) error) error { } func (gui *Gui) handleOpenConfig() error { - return gui.askForConfigFile(gui.openFile) + return gui.askForConfigFile(gui.fileHelper.OpenFile) } func (gui *Gui) handleEditConfig() error { - return gui.askForConfigFile(gui.editFile) + return gui.askForConfigFile(gui.fileHelper.EditFile) } func lazygitTitle() string { diff --git a/pkg/gui/style/style_test.go b/pkg/gui/style/style_test.go index 360ad00e6..c8157efd6 100644 --- a/pkg/gui/style/style_test.go +++ b/pkg/gui/style/style_test.go @@ -135,7 +135,7 @@ func TestMerge(t *testing.T) { "\x1b[38;2;255;0;255;48;2;255;255;0;1;4mfoo\x1b[0m", }, { - "mix color-16 with rgb colors", + "mix color-16 (background) with rgb (foreground)", []TextStyle{New().SetFg(rgbYellow), BgRed}, TextStyle{ fg: &rgbYellow, @@ -147,6 +147,19 @@ func TestMerge(t *testing.T) { }, "\x1b[38;2;255;255;0;48;2;197;30;20mfoo\x1b[0m", }, + { + "mix color-16 (foreground) with rgb (background)", + []TextStyle{FgRed, New().SetBg(rgbYellow)}, + TextStyle{ + fg: &Color{basic: &fgRed}, + bg: &rgbYellow, + Style: color.NewRGBStyle( + fgRed.RGB(), + rgbYellowLib, + ).SetOpts(color.Opts{}), + }, + "\x1b[38;2;197;30;20;48;2;255;255;0mfoo\x1b[0m", + }, } for _, s := range scenarios { diff --git a/pkg/gui/sub_commits_panel.go b/pkg/gui/sub_commits_panel.go index 97f57d158..c3b83d122 100644 --- a/pkg/gui/sub_commits_panel.go +++ b/pkg/gui/sub_commits_panel.go @@ -3,7 +3,9 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/loaders" "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/popup" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) // list panel functions @@ -24,7 +26,7 @@ func (gui *Gui) subCommitsRenderToMain() error { if commit == nil { task = NewRenderStringTask("No commits") } else { - cmdObj := gui.Git.Commit.ShowCmdObj(commit.Sha, gui.State.Modes.Filtering.GetPath()) + cmdObj := gui.git.Commit.ShowCmdObj(commit.Sha, gui.State.Modes.Filtering.GetPath()) task = NewRunPtyTask(cmdObj.GetCmd()) } @@ -43,19 +45,19 @@ func (gui *Gui) handleCheckoutSubCommit() error { return nil } - err := gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.LcCheckoutCommit, - Prompt: gui.Tr.SureCheckoutThisCommit, + err := gui.c.Ask(popup.AskOpts{ + Title: gui.c.Tr.LcCheckoutCommit, + Prompt: gui.c.Tr.SureCheckoutThisCommit, HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.CheckoutCommit) - return gui.handleCheckoutRef(commit.Sha, handleCheckoutRefOptions{}) + gui.c.LogAction(gui.c.Tr.Actions.CheckoutCommit) + return gui.refHelper.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) }, }) if err != nil { return err } - gui.State.Panels.SubCommits.SelectedLineIdx = 0 + gui.State.Contexts.SubCommits.GetPanelState().SetSelectedLineIdx(0) return nil } @@ -63,7 +65,7 @@ func (gui *Gui) handleCheckoutSubCommit() error { func (gui *Gui) handleCreateSubCommitResetMenu() error { commit := gui.getSelectedSubCommit() - return gui.createResetMenu(commit.Sha) + return gui.refHelper.CreateGitResetMenu(commit.Sha) } func (gui *Gui) handleViewSubCommitFiles() error { @@ -72,12 +74,17 @@ func (gui *Gui) handleViewSubCommitFiles() error { return nil } - return gui.switchToCommitFilesContext(commit.Sha, false, gui.State.Contexts.SubCommits, "branches") + return gui.SwitchToCommitFilesContext(controllers.SwitchToCommitFilesContextOpts{ + RefName: commit.Sha, + CanRebase: false, + Context: gui.State.Contexts.SubCommits, + WindowName: "branches", + }) } func (gui *Gui) switchToSubCommitsContext(refName string) error { // need to populate my sub commits - commits, err := gui.Git.Loaders.Commits.GetCommits( + commits, err := gui.git.Loaders.Commits.GetCommits( loaders.GetCommitsOptions{ Limit: gui.State.Panels.Commits.LimitCommits, FilterPath: gui.State.Modes.Filtering.GetPath(), @@ -91,10 +98,10 @@ func (gui *Gui) switchToSubCommitsContext(refName string) error { gui.State.SubCommits = commits gui.State.Panels.SubCommits.refName = refName - gui.State.Panels.SubCommits.SelectedLineIdx = 0 + gui.State.Contexts.SubCommits.GetPanelState().SetSelectedLineIdx(0) gui.State.Contexts.SubCommits.SetParentContext(gui.currentSideListContext()) - return gui.pushContext(gui.State.Contexts.SubCommits) + return gui.c.PushContext(gui.State.Contexts.SubCommits) } func (gui *Gui) handleSwitchToSubCommits() error { diff --git a/pkg/gui/submodules_panel.go b/pkg/gui/submodules_panel.go index e63634bc6..7c29c7840 100644 --- a/pkg/gui/submodules_panel.go +++ b/pkg/gui/submodules_panel.go @@ -30,11 +30,11 @@ func (gui *Gui) submodulesRenderToMain() error { style.FgCyan.Sprint(submodule.Url), ) - file := gui.fileForSubmodule(submodule) + file := gui.workingTreeHelper.FileForSubmodule(submodule) if file == nil { task = NewRenderStringTask(prefix) } else { - cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(file, false, !file.HasUnstagedChanges && file.HasStagedChanges, gui.IgnoreWhitespaceInDiffView) + cmdObj := gui.git.WorkingTree.WorktreeFileDiffCmdObj(file, false, !file.HasUnstagedChanges && file.HasStagedChanges, gui.IgnoreWhitespaceInDiffView) task = NewRunCommandTaskWithPrefix(cmdObj.GetCmd(), prefix) } } @@ -48,7 +48,7 @@ func (gui *Gui) submodulesRenderToMain() error { } func (gui *Gui) refreshStateSubmoduleConfigs() error { - configs, err := gui.Git.Submodule.GetConfigs() + configs, err := gui.git.Submodule.GetConfigs() if err != nil { return err } diff --git a/pkg/gui/find_suggestions.go b/pkg/gui/suggestions_helper.go similarity index 61% rename from pkg/gui/find_suggestions.go rename to pkg/gui/suggestions_helper.go index 75215d673..8a871cf20 100644 --- a/pkg/gui/find_suggestions.go +++ b/pkg/gui/suggestions_helper.go @@ -4,6 +4,7 @@ import ( "fmt" "os" + "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -21,9 +22,30 @@ import ( // finding suggestions in this file, so that it's easy to see if a function already // exists for fetching a particular model. -func (gui *Gui) getRemoteNames() []string { - result := make([]string, len(gui.State.Remotes)) - for i, remote := range gui.State.Remotes { +type SuggestionsHelper struct { + c *controllers.ControllerCommon + + State *GuiRepoState + refreshSuggestionsFn func() +} + +var _ controllers.ISuggestionsHelper = &SuggestionsHelper{} + +func NewSuggestionsHelper( + c *controllers.ControllerCommon, + state *GuiRepoState, + refreshSuggestionsFn func(), +) *SuggestionsHelper { + return &SuggestionsHelper{ + c: c, + State: state, + refreshSuggestionsFn: refreshSuggestionsFn, + } +} + +func (self *SuggestionsHelper) getRemoteNames() []string { + result := make([]string, len(self.State.Remotes)) + for i, remote := range self.State.Remotes { result[i] = remote.Name } return result @@ -40,22 +62,22 @@ func matchesToSuggestions(matches []string) []*types.Suggestion { return suggestions } -func (gui *Gui) getRemoteSuggestionsFunc() func(string) []*types.Suggestion { - remoteNames := gui.getRemoteNames() +func (self *SuggestionsHelper) GetRemoteSuggestionsFunc() func(string) []*types.Suggestion { + remoteNames := self.getRemoteNames() return fuzzySearchFunc(remoteNames) } -func (gui *Gui) getBranchNames() []string { - result := make([]string, len(gui.State.Branches)) - for i, branch := range gui.State.Branches { +func (self *SuggestionsHelper) getBranchNames() []string { + result := make([]string, len(self.State.Branches)) + for i, branch := range self.State.Branches { result[i] = branch.Name } return result } -func (gui *Gui) getBranchNameSuggestionsFunc() func(string) []*types.Suggestion { - branchNames := gui.getBranchNames() +func (self *SuggestionsHelper) GetBranchNameSuggestionsFunc() func(string) []*types.Suggestion { + branchNames := self.getBranchNames() return func(input string) []*types.Suggestion { var matchingBranchNames []string @@ -78,13 +100,13 @@ func (gui *Gui) getBranchNameSuggestionsFunc() func(string) []*types.Suggestion } // here we asynchronously fetch the latest set of paths in the repo and store in -// gui.State.FilesTrie. On the main thread we'll be doing a fuzzy search via -// gui.State.FilesTrie. So if we've looked for a file previously, we'll start with +// self.State.FilesTrie. On the main thread we'll be doing a fuzzy search via +// self.State.FilesTrie. So if we've looked for a file previously, we'll start with // the old trie and eventually it'll be swapped out for the new one. // Notably, unlike other suggestion functions we're not showing all the options // if nothing has been typed because there'll be too much to display efficiently -func (gui *Gui) getFilePathSuggestionsFunc() func(string) []*types.Suggestion { - _ = gui.PopupHandler.WithWaitingStatus(gui.Tr.LcLoadingFileSuggestions, func() error { +func (self *SuggestionsHelper) GetFilePathSuggestionsFunc() func(string) []*types.Suggestion { + _ = self.c.WithWaitingStatus(self.c.Tr.LcLoadingFileSuggestions, func() error { trie := patricia.NewTrie() // load every non-gitignored file in the repo ignore, err := gitignore.FromGit() @@ -101,22 +123,16 @@ func (gui *Gui) getFilePathSuggestionsFunc() func(string) []*types.Suggestion { return nil }) // cache the trie for future use - gui.State.FilesTrie = trie + self.State.FilesTrie = trie - // refresh the selections view - gui.suggestionsAsyncHandler.Do(func() func() { - // assuming here that the confirmation view is what we're typing into. - // This assumption may prove false over time - suggestions := gui.findSuggestions(gui.Views.Confirmation.TextArea.GetContent()) - return func() { gui.setSuggestions(suggestions) } - }) + self.refreshSuggestionsFn() return err }) return func(input string) []*types.Suggestion { matchingNames := []string{} - _ = gui.State.FilesTrie.VisitFuzzy(patricia.Prefix(input), true, func(prefix patricia.Prefix, item patricia.Item, skipped int) error { + _ = self.State.FilesTrie.VisitFuzzy(patricia.Prefix(input), true, func(prefix patricia.Prefix, item patricia.Item, skipped int) error { matchingNames = append(matchingNames, item.(string)) return nil }) @@ -136,9 +152,9 @@ func (gui *Gui) getFilePathSuggestionsFunc() func(string) []*types.Suggestion { } } -func (gui *Gui) getRemoteBranchNames(separator string) []string { +func (self *SuggestionsHelper) getRemoteBranchNames(separator string) []string { result := []string{} - for _, remote := range gui.State.Remotes { + for _, remote := range self.State.Remotes { for _, branch := range remote.Branches { result = append(result, fmt.Sprintf("%s%s%s", remote.Name, separator, branch.Name)) } @@ -146,22 +162,22 @@ func (gui *Gui) getRemoteBranchNames(separator string) []string { return result } -func (gui *Gui) getRemoteBranchesSuggestionsFunc(separator string) func(string) []*types.Suggestion { - return fuzzySearchFunc(gui.getRemoteBranchNames(separator)) +func (self *SuggestionsHelper) GetRemoteBranchesSuggestionsFunc(separator string) func(string) []*types.Suggestion { + return fuzzySearchFunc(self.getRemoteBranchNames(separator)) } -func (gui *Gui) getTagNames() []string { - result := make([]string, len(gui.State.Tags)) - for i, tag := range gui.State.Tags { +func (self *SuggestionsHelper) getTagNames() []string { + result := make([]string, len(self.State.Tags)) + for i, tag := range self.State.Tags { result[i] = tag.Name } return result } -func (gui *Gui) getRefsSuggestionsFunc() func(string) []*types.Suggestion { - remoteBranchNames := gui.getRemoteBranchNames("/") - localBranchNames := gui.getBranchNames() - tagNames := gui.getTagNames() +func (self *SuggestionsHelper) GetRefsSuggestionsFunc() func(string) []*types.Suggestion { + remoteBranchNames := self.getRemoteBranchNames("/") + localBranchNames := self.getBranchNames() + tagNames := self.getTagNames() additionalRefNames := []string{"HEAD", "FETCH_HEAD", "MERGE_HEAD", "ORIG_HEAD"} refNames := append(append(append(remoteBranchNames, localBranchNames...), tagNames...), additionalRefNames...) @@ -169,9 +185,9 @@ func (gui *Gui) getRefsSuggestionsFunc() func(string) []*types.Suggestion { return fuzzySearchFunc(refNames) } -func (gui *Gui) getCustomCommandsHistorySuggestionsFunc() func(string) []*types.Suggestion { +func (self *SuggestionsHelper) GetCustomCommandsHistorySuggestionsFunc() func(string) []*types.Suggestion { // reversing so that we display the latest command first - history := utils.Reverse(gui.Config.GetAppState().CustomCommandsHistory) + history := utils.Reverse(self.c.GetAppState().CustomCommandsHistory) return fuzzySearchFunc(history) } diff --git a/pkg/gui/tags_panel.go b/pkg/gui/tags_panel.go index 9f516a006..9e00dd122 100644 --- a/pkg/gui/tags_panel.go +++ b/pkg/gui/tags_panel.go @@ -2,36 +2,28 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/popup" - "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/jesseduffield/lazygit/pkg/utils" ) -func (gui *Gui) getSelectedTag() *models.Tag { - selectedLine := gui.State.Panels.Tags.SelectedLineIdx - if selectedLine == -1 || len(gui.State.Tags) == 0 { +func (self *Gui) getSelectedTag() *models.Tag { + selectedLine := self.State.Panels.Tags.SelectedLineIdx + if selectedLine == -1 || len(self.State.Tags) == 0 { return nil } - return gui.State.Tags[selectedLine] + return self.State.Tags[selectedLine] } -func (gui *Gui) handleCreateTag() error { - // leaving commit SHA blank so that we're just creating the tag for the current commit - return gui.createTagMenu("") -} - -func (gui *Gui) tagsRenderToMain() error { +func (self *Gui) tagsRenderToMain() error { var task updateTask - tag := gui.getSelectedTag() + tag := self.getSelectedTag() if tag == nil { task = NewRenderStringTask("No tags") } else { - cmdObj := gui.Git.Branch.GetGraphCmdObj(tag.Name) + cmdObj := self.git.Branch.GetGraphCmdObj(tag.Name) task = NewRunCommandTask(cmdObj.GetCmd()) } - return gui.refreshMainViews(refreshMainOpts{ + return self.refreshMainViews(refreshMainOpts{ main: &viewUpdateOpts{ title: "Tag", task: task, @@ -40,85 +32,13 @@ func (gui *Gui) tagsRenderToMain() error { } // this is a controller: it can't access tags directly. Or can it? It should be able to get but not set. But that's exactly what I'm doing here, setting it. but through a mutator which encapsulates the event. -func (gui *Gui) refreshTags() error { - tags, err := gui.Git.Loaders.Tags.GetTags() +func (self *Gui) refreshTags() error { + tags, err := self.git.Loaders.Tags.GetTags() if err != nil { - return gui.PopupHandler.Error(err) + return self.c.Error(err) } - gui.State.Tags = tags + self.State.Tags = tags - return gui.postRefreshUpdate(gui.State.Contexts.Tags) -} - -func (gui *Gui) withSelectedTag(f func(tag *models.Tag) error) func() error { - return func() error { - tag := gui.getSelectedTag() - if tag == nil { - return nil - } - - return f(tag) - } -} - -// tag-specific handlers - -func (gui *Gui) handleCheckoutTag(tag *models.Tag) error { - gui.logAction(gui.Tr.Actions.CheckoutTag) - if err := gui.handleCheckoutRef(tag.Name, handleCheckoutRefOptions{}); err != nil { - return err - } - return gui.pushContext(gui.State.Contexts.Branches) -} - -func (gui *Gui) handleDeleteTag(tag *models.Tag) error { - prompt := utils.ResolvePlaceholderString( - gui.Tr.DeleteTagPrompt, - map[string]string{ - "tagName": tag.Name, - }, - ) - - return gui.PopupHandler.Ask(popup.AskOpts{ - Title: gui.Tr.DeleteTagTitle, - Prompt: prompt, - HandleConfirm: func() error { - gui.logAction(gui.Tr.Actions.DeleteTag) - if err := gui.Git.Tag.Delete(tag.Name); err != nil { - return gui.PopupHandler.Error(err) - } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}}) - }, - }) -} - -func (gui *Gui) handlePushTag(tag *models.Tag) error { - title := utils.ResolvePlaceholderString( - gui.Tr.PushTagTitle, - map[string]string{ - "tagName": tag.Name, - }, - ) - - return gui.PopupHandler.Prompt(popup.PromptOpts{ - Title: title, - InitialContent: "origin", - FindSuggestionsFunc: gui.getRemoteSuggestionsFunc(), - HandleConfirm: func(response string) error { - return gui.PopupHandler.WithWaitingStatus(gui.Tr.PushingTagStatus, func() error { - gui.logAction(gui.Tr.Actions.PushTag) - err := gui.Git.Tag.Push(response, tag.Name) - if err != nil { - _ = gui.PopupHandler.Error(err) - } - - return nil - }) - }, - }) -} - -func (gui *Gui) handleCreateResetToTagMenu(tag *models.Tag) error { - return gui.createResetMenu(tag.Name) + return self.postRefreshUpdate(self.State.Contexts.Tags) } diff --git a/pkg/gui/tasks_adapter.go b/pkg/gui/tasks_adapter.go index 4c268c14d..d619c58ba 100644 --- a/pkg/gui/tasks_adapter.go +++ b/pkg/gui/tasks_adapter.go @@ -11,7 +11,7 @@ import ( func (gui *Gui) newCmdTask(view *gocui.View, cmd *exec.Cmd, prefix string) error { cmdStr := strings.Join(cmd.Args, " ") - gui.Log.WithField( + gui.c.Log.WithField( "command", cmdStr, ).Debug("RunCommand") @@ -24,19 +24,19 @@ func (gui *Gui) newCmdTask(view *gocui.View, cmd *exec.Cmd, prefix string) error start := func() (*exec.Cmd, io.Reader) { r, err := cmd.StdoutPipe() if err != nil { - gui.Log.Warn(err) + gui.c.Log.Warn(err) } cmd.Stderr = cmd.Stdout if err := cmd.Start(); err != nil { - gui.Log.Warn(err) + gui.c.Log.Warn(err) } return cmd, r } if err := manager.NewTask(manager.NewCmdTask(start, prefix, height+oy+10, nil), cmdStr); err != nil { - gui.Log.Warn(err) + gui.c.Log.Warn(err) } return nil diff --git a/pkg/gui/types/common_commands.go b/pkg/gui/types/common_commands.go new file mode 100644 index 000000000..74bfd603b --- /dev/null +++ b/pkg/gui/types/common_commands.go @@ -0,0 +1,7 @@ +package types + +type CheckoutRefOptions struct { + WaitingStatus string + EnvVars []string + OnRefNotFound func(ref string) error +} diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go new file mode 100644 index 000000000..833d1cba6 --- /dev/null +++ b/pkg/gui/types/context.go @@ -0,0 +1,87 @@ +package types + +import "github.com/jesseduffield/lazygit/pkg/config" + +type ContextKind int + +const ( + SIDE_CONTEXT ContextKind = iota + MAIN_CONTEXT + TEMPORARY_POPUP + PERSISTENT_POPUP + EXTRAS_CONTEXT +) + +type Context interface { + HandleFocus(opts ...OnFocusOpts) error + HandleFocusLost() error + HandleRender() error + HandleRenderToMain() error + GetKind() ContextKind + GetViewName() string + GetWindowName() string + SetWindowName(string) + GetKey() ContextKey + SetParentContext(Context) + + // we return a bool here to tell us whether or not the returned value just wraps a nil + GetParentContext() (Context, bool) + GetOptionsMap() map[string]string +} + +type OnFocusOpts struct { + ClickedViewName string + ClickedViewLineIdx int +} + +type ContextKey string + +type HasKeybindings interface { + Keybindings( + getKey func(key string) interface{}, + config config.KeybindingConfig, + guards KeybindingGuards, + ) []*Binding +} + +type IController interface { + HasKeybindings + Context() Context +} + +type IListContext interface { + HasKeybindings + GetSelectedItem() (ListItem, bool) + GetSelectedItemId() string + + HandlePrevLine() error + HandleNextLine() error + HandleScrollLeft() error + HandleScrollRight() error + HandleNextPage() error + HandleGotoTop() error + HandleGotoBottom() error + HandlePrevPage() error + HandleClick(onClick func() error) error + + OnSearchSelect(selectedLineIdx int) error + FocusLine() + HandleRenderToMain() error + + GetPanelState() IListPanelState + + Context +} + +type IListPanelState interface { + SetSelectedLineIdx(int) + GetSelectedLineIdx() int +} + +type ListItem interface { + // ID is a SHA when the item is a commit, a filename when the item is a file, 'stash@{4}' when it's a stash entry, 'my_branch' when it's a branch + ID() string + + // Description is something we would show in a message e.g. '123as14: push blah' for a commit + Description() string +} diff --git a/pkg/gui/types/keybindings.go b/pkg/gui/types/keybindings.go index abe3f84d0..7d1befc1b 100644 --- a/pkg/gui/types/keybindings.go +++ b/pkg/gui/types/keybindings.go @@ -16,3 +16,12 @@ type Binding struct { Tag string // e.g. 'navigation'. Used for grouping things in the cheatsheet OpensMenu bool } + +// A guard is a decorator which checks something before executing a handler +// and potentially early-exits if some precondition hasn't been met. +type Guard func(func() error) func() error + +type KeybindingGuards struct { + OutsideFilterMode Guard + NoPopupPanel Guard +} diff --git a/pkg/gui/types/refresh.go b/pkg/gui/types/refresh.go index d0cbe02ba..3a7e6db17 100644 --- a/pkg/gui/types/refresh.go +++ b/pkg/gui/types/refresh.go @@ -5,6 +5,7 @@ type RefreshableView int const ( COMMITS RefreshableView = iota + REBASE_COMMITS BRANCHES FILES STASH diff --git a/pkg/gui/updates.go b/pkg/gui/updates.go index 5eb08dae3..f3dc14b1d 100644 --- a/pkg/gui/updates.go +++ b/pkg/gui/updates.go @@ -8,7 +8,7 @@ import ( ) func (gui *Gui) showUpdatePrompt(newVersion string) error { - return gui.PopupHandler.Ask(popup.AskOpts{ + return gui.c.Ask(popup.AskOpts{ Title: "New version available!", Prompt: fmt.Sprintf("Download version %s? (enter/esc)", newVersion), HandleConfirm: func() error { @@ -20,10 +20,10 @@ func (gui *Gui) showUpdatePrompt(newVersion string) error { func (gui *Gui) onUserUpdateCheckFinish(newVersion string, err error) error { if err != nil { - return gui.PopupHandler.Error(err) + return gui.c.Error(err) } if newVersion == "" { - return gui.PopupHandler.ErrorMsg("New version not found") + return gui.c.ErrorMsg("New version not found") } return gui.showUpdatePrompt(newVersion) } @@ -31,13 +31,13 @@ func (gui *Gui) onUserUpdateCheckFinish(newVersion string, err error) error { func (gui *Gui) onBackgroundUpdateCheckFinish(newVersion string, err error) error { if err != nil { // ignoring the error for now so that I'm not annoying users - gui.Log.Error(err.Error()) + gui.c.Log.Error(err.Error()) return nil } if newVersion == "" { return nil } - if gui.UserConfig.Update.Method == "background" { + if gui.c.UserConfig.Update.Method == "background" { gui.startUpdating(newVersion) return nil } @@ -56,7 +56,7 @@ func (gui *Gui) onUpdateFinish(statusId int, err error) error { gui.OnUIThread(func() error { _ = gui.renderString(gui.Views.AppStatus, "") if err != nil { - return gui.PopupHandler.ErrorMsg("Update failed: " + err.Error()) + return gui.c.ErrorMsg("Update failed: " + err.Error()) } return nil }) @@ -65,7 +65,7 @@ func (gui *Gui) onUpdateFinish(statusId int, err error) error { } func (gui *Gui) createUpdateQuitConfirmation() error { - return gui.PopupHandler.Ask(popup.AskOpts{ + return gui.c.Ask(popup.AskOpts{ Title: "Currently Updating", Prompt: "An update is in progress. Are you sure you want to quit?", HandleConfirm: func() error { diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index 089cee454..29dd70048 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -59,14 +59,14 @@ func arrToMap(arr []types.RefreshableView) map[types.RefreshableView]bool { return output } -func (gui *Gui) refreshSidePanels(options types.RefreshOptions) error { +func (gui *Gui) Refresh(options types.RefreshOptions) error { if options.Scope == nil { - gui.Log.Infof( + gui.c.Log.Infof( "refreshing all scopes in %s mode", getModeName(options.Mode), ) } else { - gui.Log.Infof( + gui.c.Log.Infof( "refreshing the following scopes in %s mode: %s", getModeName(options.Mode), strings.Join(getScopeNames(options.Scope), ","), @@ -78,69 +78,55 @@ func (gui *Gui) refreshSidePanels(options types.RefreshOptions) error { f := func() { var scopeMap map[types.RefreshableView]bool if len(options.Scope) == 0 { - scopeMap = arrToMap([]types.RefreshableView{types.COMMITS, types.BRANCHES, types.FILES, types.STASH, types.REFLOG, types.TAGS, types.REMOTES, types.STATUS, types.BISECT_INFO}) + scopeMap = arrToMap([]types.RefreshableView{ + types.COMMITS, + types.BRANCHES, + types.FILES, + types.STASH, + types.REFLOG, + types.TAGS, + types.REMOTES, + types.STATUS, + types.BISECT_INFO, + }) } else { scopeMap = arrToMap(options.Scope) } - if scopeMap[types.COMMITS] || scopeMap[types.BRANCHES] || scopeMap[types.REFLOG] || scopeMap[types.BISECT_INFO] { + refresh := func(f func()) { wg.Add(1) func() { if options.Mode == types.ASYNC { - go utils.Safe(func() { gui.refreshCommits() }) + go utils.Safe(f) } else { - gui.refreshCommits() + f() } wg.Done() }() } + if scopeMap[types.COMMITS] || scopeMap[types.BRANCHES] || scopeMap[types.REFLOG] || scopeMap[types.BISECT_INFO] { + refresh(gui.refreshCommits) + } else if scopeMap[types.REBASE_COMMITS] { + // the above block handles rebase commits so we only need to call this one + // if we've asked specifically for rebase commits and not those other things + refresh(func() { _ = gui.refreshRebaseCommits() }) + } + if scopeMap[types.FILES] || scopeMap[types.SUBMODULES] { - wg.Add(1) - func() { - if options.Mode == types.ASYNC { - go utils.Safe(func() { _ = gui.refreshFilesAndSubmodules() }) - } else { - _ = gui.refreshFilesAndSubmodules() - } - wg.Done() - }() + refresh(func() { _ = gui.refreshFilesAndSubmodules() }) } if scopeMap[types.STASH] { - wg.Add(1) - func() { - if options.Mode == types.ASYNC { - go utils.Safe(func() { _ = gui.refreshStashEntries() }) - } else { - _ = gui.refreshStashEntries() - } - wg.Done() - }() + refresh(func() { _ = gui.refreshStashEntries() }) } if scopeMap[types.TAGS] { - wg.Add(1) - func() { - if options.Mode == types.ASYNC { - go utils.Safe(func() { _ = gui.refreshTags() }) - } else { - _ = gui.refreshTags() - } - wg.Done() - }() + refresh(func() { _ = gui.refreshTags() }) } if scopeMap[types.REMOTES] { - wg.Add(1) - func() { - if options.Mode == types.ASYNC { - go utils.Safe(func() { _ = gui.refreshRemotes() }) - } else { - _ = gui.refreshRemotes() - } - wg.Done() - }() + refresh(func() { _ = gui.refreshRemotes() }) } wg.Wait() @@ -234,7 +220,7 @@ func (gui *Gui) resizePopupPanel(v *gocui.View, content string) error { return err } -func (gui *Gui) changeSelectedLine(panelState IListPanelState, total int, change int) { +func (gui *Gui) changeSelectedLine(panelState types.IListPanelState, total int, change int) { // TODO: find out why we're doing this line := panelState.GetSelectedLineIdx() @@ -253,7 +239,7 @@ func (gui *Gui) changeSelectedLine(panelState IListPanelState, total int, change panelState.SetSelectedLineIdx(newLine) } -func (gui *Gui) refreshSelectedLine(panelState IListPanelState, total int) { +func (gui *Gui) refreshSelectedLine(panelState types.IListPanelState, total int) { line := panelState.GetSelectedLineIdx() if line == -1 && total > 0 { @@ -274,16 +260,16 @@ func (gui *Gui) renderDisplayStringsAtPos(v *gocui.View, y int, displayStrings [ } func (gui *Gui) globalOptionsMap() map[string]string { - keybindingConfig := gui.UserConfig.Keybinding + keybindingConfig := gui.c.UserConfig.Keybinding return map[string]string{ - fmt.Sprintf("%s/%s", gui.getKeyDisplay(keybindingConfig.Universal.ScrollUpMain), gui.getKeyDisplay(keybindingConfig.Universal.ScrollDownMain)): gui.Tr.LcScroll, - fmt.Sprintf("%s %s %s %s", gui.getKeyDisplay(keybindingConfig.Universal.PrevBlock), gui.getKeyDisplay(keybindingConfig.Universal.NextBlock), gui.getKeyDisplay(keybindingConfig.Universal.PrevItem), gui.getKeyDisplay(keybindingConfig.Universal.NextItem)): gui.Tr.LcNavigate, - gui.getKeyDisplay(keybindingConfig.Universal.Return): gui.Tr.LcCancel, - gui.getKeyDisplay(keybindingConfig.Universal.Quit): gui.Tr.LcQuit, - gui.getKeyDisplay(keybindingConfig.Universal.OptionMenu): gui.Tr.LcMenu, - fmt.Sprintf("%s-%s", gui.getKeyDisplay(keybindingConfig.Universal.JumpToBlock[0]), gui.getKeyDisplay(keybindingConfig.Universal.JumpToBlock[len(keybindingConfig.Universal.JumpToBlock)-1])): gui.Tr.LcJump, - fmt.Sprintf("%s/%s", gui.getKeyDisplay(keybindingConfig.Universal.ScrollLeft), gui.getKeyDisplay(keybindingConfig.Universal.ScrollRight)): gui.Tr.LcScrollLeftRight, + fmt.Sprintf("%s/%s", gui.getKeyDisplay(keybindingConfig.Universal.ScrollUpMain), gui.getKeyDisplay(keybindingConfig.Universal.ScrollDownMain)): gui.c.Tr.LcScroll, + fmt.Sprintf("%s %s %s %s", gui.getKeyDisplay(keybindingConfig.Universal.PrevBlock), gui.getKeyDisplay(keybindingConfig.Universal.NextBlock), gui.getKeyDisplay(keybindingConfig.Universal.PrevItem), gui.getKeyDisplay(keybindingConfig.Universal.NextItem)): gui.c.Tr.LcNavigate, + gui.getKeyDisplay(keybindingConfig.Universal.Return): gui.c.Tr.LcCancel, + gui.getKeyDisplay(keybindingConfig.Universal.Quit): gui.c.Tr.LcQuit, + gui.getKeyDisplay(keybindingConfig.Universal.OptionMenu): gui.c.Tr.LcMenu, + fmt.Sprintf("%s-%s", gui.getKeyDisplay(keybindingConfig.Universal.JumpToBlock[0]), gui.getKeyDisplay(keybindingConfig.Universal.JumpToBlock[len(keybindingConfig.Universal.JumpToBlock)-1])): gui.c.Tr.LcJump, + fmt.Sprintf("%s/%s", gui.getKeyDisplay(keybindingConfig.Universal.ScrollLeft), gui.getKeyDisplay(keybindingConfig.Universal.ScrollRight)): gui.c.Tr.LcScrollLeftRight, } } @@ -302,9 +288,9 @@ func (gui *Gui) secondaryViewFocused() bool { } func (gui *Gui) onViewTabClick(viewName string, tabIndex int) error { - context := gui.State.ViewTabContextMap[viewName][tabIndex].contexts[0] + context := gui.State.ViewTabContextMap[viewName][tabIndex].Contexts[0] - return gui.pushContext(context) + return gui.c.PushContext(context) } func (gui *Gui) handleNextTab() error { diff --git a/pkg/gui/whitespace-toggle.go b/pkg/gui/whitespace-toggle.go index 7ded50c18..ad82bc036 100644 --- a/pkg/gui/whitespace-toggle.go +++ b/pkg/gui/whitespace-toggle.go @@ -3,11 +3,11 @@ package gui func (gui *Gui) toggleWhitespaceInDiffView() error { gui.IgnoreWhitespaceInDiffView = !gui.IgnoreWhitespaceInDiffView - toastMessage := gui.Tr.ShowingWhitespaceInDiffView + toastMessage := gui.c.Tr.ShowingWhitespaceInDiffView if gui.IgnoreWhitespaceInDiffView { - toastMessage = gui.Tr.IgnoringWhitespaceInDiffView + toastMessage = gui.c.Tr.IgnoringWhitespaceInDiffView } - gui.raiseToast(toastMessage) + gui.c.Toast(toastMessage) return gui.refreshFilesAndSubmodules() } diff --git a/pkg/gui/working_tree_helper.go b/pkg/gui/working_tree_helper.go new file mode 100644 index 000000000..964a4bc5a --- /dev/null +++ b/pkg/gui/working_tree_helper.go @@ -0,0 +1,50 @@ +package gui + +import ( + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/filetree" +) + +type WorkingTreeHelper struct { + fileTreeViewModel *filetree.FileTreeViewModel +} + +func NewWorkingTreeHelper(fileTreeViewModel *filetree.FileTreeViewModel) *WorkingTreeHelper { + return &WorkingTreeHelper{ + fileTreeViewModel: fileTreeViewModel, + } +} + +func (self *WorkingTreeHelper) AnyStagedFiles() bool { + files := self.fileTreeViewModel.GetAllFiles() + for _, file := range files { + if file.HasStagedChanges { + return true + } + } + return false +} + +func (self *WorkingTreeHelper) AnyTrackedFiles() bool { + files := self.fileTreeViewModel.GetAllFiles() + for _, file := range files { + if file.Tracked { + return true + } + } + return false +} + +func (self *WorkingTreeHelper) IsWorkingTreeDirty() bool { + return self.AnyStagedFiles() || self.AnyTrackedFiles() +} + +func (self *WorkingTreeHelper) FileForSubmodule(submodule *models.SubmoduleConfig) *models.File { + for _, file := range self.fileTreeViewModel.GetAllFiles() { + if file.IsSubmodule([]*models.SubmoduleConfig{submodule}) { + return file + } + } + + return nil +} diff --git a/pkg/gui/workspace_reset_options_panel.go b/pkg/gui/workspace_reset_options_panel.go index 6230e0966..2b9fd97d1 100644 --- a/pkg/gui/workspace_reset_options_panel.go +++ b/pkg/gui/workspace_reset_options_panel.go @@ -13,64 +13,64 @@ func (gui *Gui) handleCreateResetMenu() error { nukeStr := "reset --hard HEAD && git clean -fd" if len(gui.State.Submodules) > 0 { - nukeStr = fmt.Sprintf("%s (%s)", nukeStr, gui.Tr.LcAndResetSubmodules) + nukeStr = fmt.Sprintf("%s (%s)", nukeStr, gui.c.Tr.LcAndResetSubmodules) } menuItems := []*popup.MenuItem{ { DisplayStrings: []string{ - gui.Tr.LcDiscardAllChangesToAllFiles, + gui.c.Tr.LcDiscardAllChangesToAllFiles, red.Sprint(nukeStr), }, OnPress: func() error { - gui.logAction(gui.Tr.Actions.NukeWorkingTree) - if err := gui.Git.WorkingTree.ResetAndClean(); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.NukeWorkingTree) + if err := gui.git.WorkingTree.ResetAndClean(); err != nil { + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, { DisplayStrings: []string{ - gui.Tr.LcDiscardAnyUnstagedChanges, + gui.c.Tr.LcDiscardAnyUnstagedChanges, red.Sprint("git checkout -- ."), }, OnPress: func() error { - gui.logAction(gui.Tr.Actions.DiscardUnstagedFileChanges) - if err := gui.Git.WorkingTree.DiscardAnyUnstagedFileChanges(); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.DiscardUnstagedFileChanges) + if err := gui.git.WorkingTree.DiscardAnyUnstagedFileChanges(); err != nil { + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, { DisplayStrings: []string{ - gui.Tr.LcDiscardUntrackedFiles, + gui.c.Tr.LcDiscardUntrackedFiles, red.Sprint("git clean -fd"), }, OnPress: func() error { - gui.logAction(gui.Tr.Actions.RemoveUntrackedFiles) - if err := gui.Git.WorkingTree.RemoveUntrackedFiles(); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.RemoveUntrackedFiles) + if err := gui.git.WorkingTree.RemoveUntrackedFiles(); err != nil { + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, { DisplayStrings: []string{ - gui.Tr.LcSoftReset, + gui.c.Tr.LcSoftReset, red.Sprint("git reset --soft HEAD"), }, OnPress: func() error { - gui.logAction(gui.Tr.Actions.SoftReset) - if err := gui.Git.WorkingTree.ResetSoft("HEAD"); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.SoftReset) + if err := gui.git.WorkingTree.ResetSoft("HEAD"); err != nil { + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, { @@ -79,29 +79,29 @@ func (gui *Gui) handleCreateResetMenu() error { red.Sprint("git reset --mixed HEAD"), }, OnPress: func() error { - gui.logAction(gui.Tr.Actions.MixedReset) - if err := gui.Git.WorkingTree.ResetMixed("HEAD"); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.MixedReset) + if err := gui.git.WorkingTree.ResetMixed("HEAD"); err != nil { + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, { DisplayStrings: []string{ - gui.Tr.LcHardReset, + gui.c.Tr.LcHardReset, red.Sprint("git reset --hard HEAD"), }, OnPress: func() error { - gui.logAction(gui.Tr.Actions.HardReset) - if err := gui.Git.WorkingTree.ResetHard("HEAD"); err != nil { - return gui.PopupHandler.Error(err) + gui.c.LogAction(gui.c.Tr.Actions.HardReset) + if err := gui.git.WorkingTree.ResetHard("HEAD"); err != nil { + return gui.c.Error(err) } - return gui.refreshSidePanels(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) }, }, } - return gui.PopupHandler.Menu(popup.CreateMenuOptions{Title: "", Items: menuItems}) + return gui.c.Menu(popup.CreateMenuOptions{Title: "", Items: menuItems}) } diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index f3b90a194..5db081625 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -46,6 +46,7 @@ type TranslationSet struct { LcPush string LcPull string LcScroll string + LcFileFilter string LcCommitFileFilter string FilterStagedFiles string FilterUnstagedFiles string @@ -620,6 +621,7 @@ func EnglishTranslationSet() TranslationSet { LcScroll: "scroll", MergeConflictsTitle: "Merge Conflicts", LcCheckout: "checkout", + LcFileFilter: "Filter files (staged/unstaged)", LcCommitFileFilter: "Filter commit files", FilterStagedFiles: "Show only staged files", FilterUnstagedFiles: "Show only unstaged files", diff --git a/test/integration/commit/expected/.git_keep/index b/test/integration/commit/expected/.git_keep/index index 6bda11a963f4c74fd653e4a7b665088e83a5a447..e0cf626903ce39ebbbe5599b30490d4a4773273b 100644 GIT binary patch delta 178 zcmZ3 QWSPn=- R^M(C Q=zr?sBYia{uW08a0MrUP3jhEB delta 178 zcmZ3 t%%b2(YB4>Iy)B+?2qM>q?6aPTu%pEREgXBOoRIY2X3uB Date: Sun, 23 Jan 2022 14:40:28 +1100 Subject: [PATCH 025/385] fix some things --- docs/keybindings/Keybindings_en.md | 29 +- docs/keybindings/Keybindings_nl.md | 21 +- docs/keybindings/Keybindings_pl.md | 29 +- docs/keybindings/Keybindings_zh.md | 29 +- go.mod | 2 - go.sum | 3 - pkg/gui/context_config.go | 2 +- pkg/gui/context_test.go | 11 +- pkg/gui/controllers/bisect_controller.go | 20 +- pkg/gui/controllers/files_controller.go | 97 +++--- .../controllers/local_commits_controller.go | 38 +-- pkg/gui/controllers/menu_controller.go | 14 +- pkg/gui/controllers/remotes_controller.go | 26 +- pkg/gui/controllers/tags_controller.go | 20 +- pkg/gui/diff_context_size_test.go | 313 +++++++++--------- pkg/gui/files_panel.go | 18 +- pkg/gui/gui.go | 40 ++- pkg/gui/keybindings.go | 2 +- pkg/gui/list_context.go | 1 + pkg/gui/misc.go | 6 + pkg/gui/popup/popup_handler.go | 4 +- pkg/gui/ref_helper.go | 24 +- pkg/gui/suggestions_helper.go | 24 +- pkg/gui/working_tree_helper.go | 12 +- pkg/i18n/chinese.go | 1 - pkg/i18n/dutch.go | 1 - pkg/i18n/english.go | 2 - pkg/i18n/polish.go | 1 - .../mergeConflictsFiltered/test.json | 2 +- vendor/modules.txt | 3 - 30 files changed, 367 insertions(+), 428 deletions(-) diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index 09a933f81..82eafdb1d 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -10,21 +10,20 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct pgdown: scroll down main panel (fn+down) m: view merge/rebase options ctrl+p: view custom patch options - P: push - p: pull R: refresh x: open menu - z: undo (via reflog) (experimental) - ctrl+z: redo (via reflog) (experimental) +: next screen mode (normal/half/fullscreen) _: prev screen mode - :: execute custom command ctrl+s: view filter-by-path options W: open diff menu ctrl+e: open diff menu @: open command log menu }: Increase the size of the context shown around changes in the diff view {: Decrease the size of the context shown around changes in the diff view + z: undo (via reflog) (experimental) + ctrl+z: redo (via reflog) (experimental) + P: push + p: pull
- ctrl+b: Filter commit files -- ## Files Panel (Files)
+ d: view 'discard changes' options + D: view reset options + f: fetch + ctrl+o: copy the file name to the clipboard + ctrl+w: Toggle whether or not whitespace changes are shown in the diff view + space: toggle staged + ctrl+b: Filter files (staged/unstaged) c: commit changes w: commit changes without pre-commit hook A: amend last commit C: commit changes using git editor - d: view 'discard changes' options e: edit file o: open file i: add to .gitignore @@ -191,15 +190,11 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct s: stash changes S: view stash options a: stage/unstage all - D: view reset options enter: stage individual hunks/lines for file, or collapse/expand for directory - f: fetch - ctrl+o: copy the file name to the clipboard + :: execute custom command g: view upstream reset options `: toggle file tree view M: open external merge tool (git mergetool) - ctrl+w: Toggle whether or not whitespace changes are shown in the diff view - space: toggle staged## Files Panel (Submodules) diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index 5e0d62fac..0136a529b 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -10,12 +10,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct pgdown: scroll naar beneden vanaf hoofdpaneel (fn+down) m: bekijk merge/rebase opties ctrl+p: bekijk aangepaste patch opties - P: push - p: pull R: verversen x: open menu - z: ongedaan maken (via reflog) (experimenteel) - ctrl+z: redo (via reflog) (experimenteel) +: volgende scherm modus (normaal/half/groot) _: vorige scherm modus :: voer aangepaste commando uit @@ -25,6 +21,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct @: open command log menu }: Increase the size of the context shown around changes in the diff view {: Decrease the size of the context shown around changes in the diff view + z: ongedaan maken (via reflog) (experimenteel) + ctrl+z: redo (via reflog) (experimenteel) + P: push + p: pull ## Lijstpaneel Navigatie @@ -170,12 +170,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct @: open command log menu -## Bestanden Paneel - -
- ctrl+b: Commit dossiers filteren -- ## Bestanden Paneel (Bestanden)
@@ -183,7 +177,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct w: commit veranderingen zonder pre-commit hook A: wijzig laatste commit C: commit veranderingen met de git editor - d: bekijk 'veranderingen ongedaan maken' opties e: verander bestand o: open bestand i: voeg toe aan .gitignore @@ -191,15 +184,11 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct s: stash-bestanden S: bekijk stash opties a: toggle staged alle - D: bekijk reset opties enter: stage individuele hunks/lijnen - f: fetch - ctrl+o: kopieer de bestandsnaam naar het klembord + :: voor aangepaste commando uit g: bekijk upstream reset opties `: toggle bestandsboom weergave M: open external merge tool (git mergetool) - ctrl+w: Toggle whether or not whitespace changes are shown in the diff view - space: toggle staged## Bestanden Paneel (Submodules) diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index afdcdebcd..1d7f4f725 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -10,21 +10,20 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct pgdown: scroll down main panel (fn+down) m: widok scalenia/opcje zmiany bazy ctrl+p: view custom patch options - P: push - p: pull R: od艣wie偶 x: open menu - z: undo (via reflog) (experimental) - ctrl+z: redo (via reflog) (experimental) +: next screen mode (normal/half/fullscreen) _: prev screen mode - :: wykonaj w艂asn膮 komend臋 ctrl+s: view filter-by-path options W: open diff menu ctrl+e: open diff menu @: open command log menu }: Increase the size of the context shown around changes in the diff view {: Decrease the size of the context shown around changes in the diff view + z: undo (via reflog) (experimental) + ctrl+z: redo (via reflog) (experimental) + P: push + p: pull ## List Panel Navigation @@ -170,20 +169,20 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct @: open command log menu -## Pliki Panel - -
- ctrl+b: Filtrowanie commit贸w -- ## Pliki Panel (Pliki)
+ d: poka偶 opcje porzucania zmian + D: wy艣wietl opcje resetu + f: pobierz + ctrl+o: copy the file name to the clipboard + ctrl+w: Toggle whether or not whitespace changes are shown in the diff view + space: prze艂膮cz stan poczekalni + ctrl+b: Filter files (staged/unstaged) c: Zatwierd藕 zmiany w: zatwierd藕 zmiany bez skryptu pre-commit A: Zmie艅 ostatni commit C: Zatwierd藕 zmiany u偶ywaj膮c edytora - d: poka偶 opcje porzucania zmian e: edytuj plik o: otw贸rz plik i: dodaj do .gitignore @@ -191,15 +190,11 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct s: przechowaj zmiany S: wy艣wietl opcje schowka a: prze艂膮cz stan poczekalni wszystkich - D: wy艣wietl opcje resetu enter: zatwierd藕 pojedyncze linie - f: pobierz - ctrl+o: copy the file name to the clipboard + :: wykonaj w艂asn膮 komend臋 g: view upstream reset options `: toggle file tree view M: open external merge tool (git mergetool) - ctrl+w: Toggle whether or not whitespace changes are shown in the diff view - space: prze艂膮cz stan poczekalni## Pliki Panel (Submodules) diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index 61b2c287f..cba13cfc4 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -10,21 +10,20 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct pgdown: 鍚戜笅婊氬姩涓婚潰鏉 (fn+down) m: 鏌ョ湅 鍚堝苟/鍙樺熀 閫夐」 ctrl+p: 鏌ョ湅鑷畾涔夎ˉ涓侀夐」 - P: 鎺ㄩ - p: 鎷夊彇 R: 鍒锋柊 x: 鎵撳紑鑿滃崟 - z: 锛堥氳繃 reflog锛夋挙閿銆屽疄楠屽姛鑳姐 - ctrl+z: 锛堥氳繃 reflog锛夐噸鍋氥屽疄楠屽姛鑳姐 +: 涓嬩竴灞忔ā寮忥紙姝e父/鍗婂睆/鍏ㄥ睆锛 _: 涓婁竴灞忔ā寮 - :: 鎵ц鑷畾涔夊懡浠 ctrl+s: 鏌ョ湅鎸夎矾寰勮繃婊ら夐」 W: 鎵撳紑 diff 鑿滃崟 ctrl+e: 鎵撳紑 diff 鑿滃崟 @: 鎵撳紑鍛戒护鏃ュ織鑿滃崟 }: Increase the size of the context shown around changes in the diff view {: Decrease the size of the context shown around changes in the diff view + z: 锛堥氳繃 reflog锛夋挙閿銆屽疄楠屽姛鑳姐 + ctrl+z: 锛堥氳繃 reflog锛夐噸鍋氥屽疄楠屽姛鑳姐 + P: 鎺ㄩ + p: 鎷夊彇 ## 鍒楄〃闈㈡澘瀵艰埅 @@ -170,20 +169,20 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct @: 鎵撳紑鍛戒护鏃ュ織鑿滃崟 -## 鏂囦欢 闈㈡澘 - -
- ctrl+b: 杩囨护鎻愪氦鏂囦欢 -- ## 鏂囦欢 闈㈡澘 (鏂囦欢)
+ d: 鏌ョ湅'鏀惧純鏇存敼鈥橀夐」 + D: 鏌ョ湅閲嶇疆閫夐」 + f: 鎶撳彇 + ctrl+o: 灏嗘枃浠跺悕澶嶅埗鍒板壀璐存澘 + ctrl+w: 鍒囨崲鏄惁鍦ㄥ樊寮傝鍥句腑鏄剧ず绌虹櫧鏇存敼 + space: 鍒囨崲鏆傚瓨鐘舵 + ctrl+b: Filter files (staged/unstaged) c: 鎻愪氦鏇存敼 w: 鎻愪氦鏇存敼鑰屾棤闇棰勫厛鎻愪氦閽╁瓙 A: 淇ˉ鏈鍚庝竴娆℃彁浜 C: 鎻愪氦鏇存敼锛堜娇鐢ㄧ紪杈戝櫒缂栬緫鎻愪氦淇℃伅锛 - d: 鏌ョ湅'鏀惧純鏇存敼鈥橀夐」 e: 缂栬緫鏂囦欢 o: 鎵撳紑鏂囦欢 i: 娣诲姞鍒 .gitignore @@ -191,15 +190,11 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct s: 灏嗘墍鏈夋洿鏀瑰姞鍏ヨ串钘 S: 鏌ョ湅闅愯棌閫夐」 a: 鍒囨崲鎵鏈夋枃浠剁殑鏆傚瓨鐘舵 - D: 鏌ョ湅閲嶇疆閫夐」 enter: 鏆傚瓨鍗曚釜 鍧/琛 鐢ㄤ簬鏂囦欢, 鎴 鎶樺彔/灞曞紑 鐩綍 - f: 鎶撳彇 - ctrl+o: 灏嗘枃浠跺悕澶嶅埗鍒板壀璐存澘 + :: 鎵ц鑷畾涔夊懡浠 g: 鏌ョ湅涓婃父閲嶇疆閫夐」 `: 鍒囨崲鏂囦欢鏍戣鍥 M: 鎵撳紑鍚堝苟宸ュ叿 - ctrl+w: 鍒囨崲鏄惁鍦ㄥ樊寮傝鍥句腑鏄剧ず绌虹櫧鏇存敼 - space: 鍒囨崲鏆傚瓨鐘舵## 鏂囦欢 闈㈡澘 (瀛愭ā鍧) diff --git a/go.mod b/go.mod index 6d72ea3b8..f4f67183d 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,6 @@ require ( github.com/gdamore/tcell/v2 v2.4.1-0.20220313203054-2a1a1b586447 // indirect github.com/go-errors/errors v1.4.1 github.com/go-logfmt/logfmt v0.5.0 // indirect - github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 // indirect github.com/golang/protobuf v1.3.2 // indirect github.com/google/go-cmp v0.5.6 // indirect github.com/gookit/color v1.4.2 @@ -45,6 +44,5 @@ require ( golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - golang.org/x/text v0.3.7 // indirect gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0 ) diff --git a/go.sum b/go.sum index fe2bffe74..e0e58cd81 100644 --- a/go.sum +++ b/go.sum @@ -33,7 +33,6 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= -github.com/gdamore/tcell/v2 v2.4.0 h1:W6dxJEmaxYvhICFoTY3WrLLEXsQ11SaFnKGVEXW57KM= github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU= github.com/gdamore/tcell/v2 v2.4.1-0.20210926162909-66f061b1fc9b h1:eoaSI4eEwM5eTx/HvmRSwmicxuMhL73AyoEfM1oCJLc= github.com/gdamore/tcell/v2 v2.4.1-0.20210926162909-66f061b1fc9b/go.mod h1:ZPwXnysybtQqdqKcWMWXux9aGdtMHe+kr+cwEZEe+A4= @@ -55,8 +54,6 @@ github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4= -github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= diff --git a/pkg/gui/context_config.go b/pkg/gui/context_config.go index b3e94e15f..b27514381 100644 --- a/pkg/gui/context_config.go +++ b/pkg/gui/context_config.go @@ -145,7 +145,7 @@ func (gui *Gui) contextTree() context.ContextTree { }, Merging: &BasicContext{ OnFocus: OnFocusWrapper(func() error { return gui.renderConflictsWithLock(true) }), - Kind: MAIN_CONTEXT, + Kind: types.MAIN_CONTEXT, ViewName: "main", Key: MAIN_MERGING_CONTEXT_KEY, OnGetOptionsMap: gui.getMergingOptions, diff --git a/pkg/gui/context_test.go b/pkg/gui/context_test.go index 7f03f7484..3a0aa120a 100644 --- a/pkg/gui/context_test.go +++ b/pkg/gui/context_test.go @@ -4,15 +4,16 @@ import ( "testing" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/stretchr/testify/assert" ) func TestCanDeactivatePopupContextsWithoutViews(t *testing.T) { - contexts := []func(gui *Gui) Context{ - func(gui *Gui) Context { return gui.State.Contexts.Credentials }, - func(gui *Gui) Context { return gui.State.Contexts.Confirmation }, - func(gui *Gui) Context { return gui.State.Contexts.CommitMessage }, - func(gui *Gui) Context { return gui.State.Contexts.Search }, + contexts := []func(gui *Gui) types.Context{ + func(gui *Gui) types.Context { return gui.State.Contexts.Credentials }, + func(gui *Gui) types.Context { return gui.State.Contexts.Confirmation }, + func(gui *Gui) types.Context { return gui.State.Contexts.CommitMessage }, + func(gui *Gui) types.Context { return gui.State.Contexts.Search }, } for _, c := range contexts { diff --git a/pkg/gui/controllers/bisect_controller.go b/pkg/gui/controllers/bisect_controller.go index 674e79f76..06602a445 100644 --- a/pkg/gui/controllers/bisect_controller.go +++ b/pkg/gui/controllers/bisect_controller.go @@ -13,9 +13,9 @@ import ( ) type BisectController struct { - c *ControllerCommon - context types.IListContext - git *commands.GitCommand + c *ControllerCommon + getContext func() types.IListContext + git *commands.GitCommand getSelectedLocalCommit func() *models.Commit getCommits func() []*models.Commit @@ -25,16 +25,16 @@ var _ types.IController = &BisectController{} func NewBisectController( c *ControllerCommon, - context types.IListContext, + getContext func() types.IListContext, git *commands.GitCommand, getSelectedLocalCommit func() *models.Commit, getCommits func() []*models.Commit, ) *BisectController { return &BisectController{ - c: c, - context: context, - git: git, + c: c, + getContext: getContext, + git: git, getSelectedLocalCommit: getSelectedLocalCommit, getCommits: getCommits, @@ -249,8 +249,8 @@ func (self *BisectController) selectCurrentBisectCommit() { // find index of commit with that sha, move cursor to that. for i, commit := range self.getCommits() { if commit.Sha == info.GetCurrentSha() { - self.context.GetPanelState().SetSelectedLineIdx(i) - _ = self.context.HandleFocus() + self.getContext().GetPanelState().SetSelectedLineIdx(i) + _ = self.getContext().HandleFocus() break } } @@ -269,5 +269,5 @@ func (self *BisectController) checkSelected(callback func(*models.Commit) error) } func (self *BisectController) Context() types.Context { - return self.context + return self.getContext() } diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index 10d378f9f..8f4641147 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -22,14 +22,14 @@ type FilesController struct { // case I would actually prefer a _zero_ letter variable name in the form of // struct embedding, but Go does not allow hiding public fields in an embedded struct // to the client - c *ControllerCommon - context types.IListContext - git *commands.GitCommand - os *oscommands.OSCommand + c *ControllerCommon + getContext func() types.IListContext + git *commands.GitCommand + os *oscommands.OSCommand getSelectedFileNode func() *filetree.FileNode - allContexts context.ContextTree - fileTreeViewModel *filetree.FileTreeViewModel + getContexts func() context.ContextTree + getViewModel func() *filetree.FileTreeViewModel enterSubmodule func(submodule *models.SubmoduleConfig) error getSubmodules func() []*models.SubmoduleConfig setCommitMessage func(message string) @@ -49,12 +49,12 @@ var _ types.IController = &FilesController{} func NewFilesController( c *ControllerCommon, - context types.IListContext, + getContext func() types.IListContext, git *commands.GitCommand, os *oscommands.OSCommand, getSelectedFileNode func() *filetree.FileNode, - allContexts context.ContextTree, - fileTreeViewModel *filetree.FileTreeViewModel, + allContexts func() context.ContextTree, + getViewModel func() *filetree.FileTreeViewModel, enterSubmodule func(submodule *models.SubmoduleConfig) error, getSubmodules func() []*models.SubmoduleConfig, setCommitMessage func(message string), @@ -70,12 +70,12 @@ func NewFilesController( ) *FilesController { return &FilesController{ c: c, - context: context, + getContext: getContext, git: git, os: os, getSelectedFileNode: getSelectedFileNode, - allContexts: allContexts, - fileTreeViewModel: fileTreeViewModel, + getContexts: allContexts, + getViewModel: getViewModel, enterSubmodule: enterSubmodule, getSubmodules: getSubmodules, setCommitMessage: setCommitMessage, @@ -100,7 +100,7 @@ func (self *FilesController) Keybindings(getKey func(key string) interface{}, co }, { Key: gocui.MouseLeft, - Handler: func() error { return self.context.HandleClick(self.checkSelectedFileNode(self.press)) }, + Handler: func() error { return self.getContext().HandleClick(self.checkSelectedFileNode(self.press)) }, }, { Key: getKey("
- d: view 'discard changes' options D: view reset options f: fetch ctrl+o: copy the file name to the clipboard @@ -186,6 +185,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct e: edit file o: open file i: add to .gitignore + d: view 'discard changes' options r: refresh files s: stash changes S: view stash options diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index 0136a529b..b25c18fc5 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -180,6 +180,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct e: verander bestand o: open bestand i: voeg toe aan .gitignore + d: bekijk 'veranderingen ongedaan maken' opties r: refresh bestanden s: stash-bestanden S: bekijk stash opties diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index 1d7f4f725..afc1d3c9c 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -172,7 +172,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Pliki Panel (Pliki)+## Bestanden Paneel (Bestanden) + +- d: poka偶 opcje porzucania zmian D: wy艣wietl opcje resetu f: pobierz ctrl+o: copy the file name to the clipboard @@ -186,6 +185,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct e: edytuj plik o: otw贸rz plik i: dodaj do .gitignore + d: poka偶 opcje porzucania zmian r: od艣wie偶 pliki s: przechowaj zmiany S: wy艣wietl opcje schowka diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index cba13cfc4..cec585c66 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -172,7 +172,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## 鏂囦欢 闈㈡澘 (鏂囦欢)diff --git a/pkg/gui/controllers/commits_files_controller.go b/pkg/gui/controllers/commits_files_controller.go index 978d6c6a7..65b930ef6 100644 --- a/pkg/gui/controllers/commits_files_controller.go +++ b/pkg/gui/controllers/commits_files_controller.go @@ -52,6 +52,11 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) [] Handler: self.checkSelected(self.toggleForPatch), Description: self.c.Tr.LcToggleAddToPatch, }, + { + Key: opts.GetKey(opts.Config.Files.ToggleStagedAll), + Handler: self.checkSelected(self.toggleAllForPatch), + Description: self.c.Tr.LcToggleAllInPatch, + }, { Key: opts.GetKey(opts.Config.Universal.GoInto), Handler: self.checkSelected(self.enter), @@ -150,35 +155,37 @@ func (self *CommitFilesController) edit(node *filetree.CommitFileNode) error { } func (self *CommitFilesController) toggleForPatch(node *filetree.CommitFileNode) error { - toggleTheFile := func() error { - if !self.git.Patch.PatchManager.Active() { - if err := self.startPatchManager(); err != nil { - return err + toggle := func() error { + return self.c.WithWaitingStatus(self.c.Tr.LcUpdatingPatch, func() error { + if !self.git.Patch.PatchManager.Active() { + if err := self.startPatchManager(); err != nil { + return err + } } - } - // if there is any file that hasn't been fully added we'll fully add everything, - // otherwise we'll remove everything - adding := node.AnyFile(func(file *models.CommitFile) bool { - return self.git.Patch.PatchManager.GetFileStatus(file.Name, self.context().GetRefName()) != patch.WHOLE - }) + // if there is any file that hasn't been fully added we'll fully add everything, + // otherwise we'll remove everything + adding := node.AnyFile(func(file *models.CommitFile) bool { + return self.git.Patch.PatchManager.GetFileStatus(file.Name, self.context().GetRefName()) != patch.WHOLE + }) - err := node.ForEachFile(func(file *models.CommitFile) error { - if adding { - return self.git.Patch.PatchManager.AddFileWhole(file.Name) - } else { - return self.git.Patch.PatchManager.RemoveFile(file.Name) + err := node.ForEachFile(func(file *models.CommitFile) error { + if adding { + return self.git.Patch.PatchManager.AddFileWhole(file.Name) + } else { + return self.git.Patch.PatchManager.RemoveFile(file.Name) + } + }) + if err != nil { + return self.c.Error(err) } + + if self.git.Patch.PatchManager.IsEmpty() { + self.git.Patch.PatchManager.Reset() + } + + return self.c.PostRefreshUpdate(self.context()) }) - if err != nil { - return self.c.Error(err) - } - - if self.git.Patch.PatchManager.IsEmpty() { - self.git.Patch.PatchManager.Reset() - } - - return self.c.PostRefreshUpdate(self.context()) } if self.git.Patch.PatchManager.Active() && self.git.Patch.PatchManager.To != self.context().GetRefName() { @@ -187,12 +194,18 @@ func (self *CommitFilesController) toggleForPatch(node *filetree.CommitFileNode) Prompt: self.c.Tr.DiscardPatchConfirm, HandleConfirm: func() error { self.git.Patch.PatchManager.Reset() - return toggleTheFile() + return toggle() }, }) } - return toggleTheFile() + return toggle() +} + +func (self *CommitFilesController) toggleAllForPatch(_ *filetree.CommitFileNode) error { + // not a fan of type assertions but this will be fixed very soon thanks to generics + root := self.context().CommitFileTreeViewModel.Tree().(*filetree.CommitFileNode) + return self.toggleForPatch(root) } func (self *CommitFilesController) startPatchManager() error { diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index aba4e9368..db25cf0a6 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -275,6 +275,8 @@ type TranslationSet struct { DiscardPatchConfirm string CantPatchWhileRebasingError string LcToggleAddToPatch string + LcToggleAllInPatch string + LcUpdatingPatch string ViewPatchOptions string PatchOptionsTitle string NoPatchError string @@ -846,6 +848,8 @@ func EnglishTranslationSet() TranslationSet { DiscardPatchConfirm: "You can only build a patch from one commit/stash-entry at a time. Discard current patch?", CantPatchWhileRebasingError: "You cannot build a patch or run patch commands while in a merging or rebasing state", LcToggleAddToPatch: "toggle file included in patch", + LcToggleAllInPatch: "toggle all files included in patch", + LcUpdatingPatch: "updating patch", ViewPatchOptions: "view custom patch options", PatchOptionsTitle: "Patch Options", NoPatchError: "No patch created yet. To start building a patch, use 'space' on a commit file or enter to add specific lines", diff --git a/pkg/integration/integration.go b/pkg/integration/integration.go index 86049a230..bb2d7a0b0 100644 --- a/pkg/integration/integration.go +++ b/pkg/integration/integration.go @@ -94,8 +94,7 @@ func RunTests( continue } - fnWrapper(test, func(t *testing.T) error { - t.Helper() + fnWrapper(test, func(t *testing.T) error { //nolint: thelper speeds := getTestSpeeds(test.Speed, mode, speedEnv) testPath := filepath.Join(testDir, test.Name) actualRepoDir := filepath.Join(testPath, "actual") diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/COMMIT_EDITMSG b/test/integration/patchBuildingToggleAll/expected/.git_keep/COMMIT_EDITMSG new file mode 100644 index 000000000..907b30816 --- /dev/null +++ b/test/integration/patchBuildingToggleAll/expected/.git_keep/COMMIT_EDITMSG @@ -0,0 +1 @@ +blah diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/FETCH_HEAD b/test/integration/patchBuildingToggleAll/expected/.git_keep/FETCH_HEAD new file mode 100644 index 000000000..e69de29bb diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/HEAD b/test/integration/patchBuildingToggleAll/expected/.git_keep/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/test/integration/patchBuildingToggleAll/expected/.git_keep/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/config b/test/integration/patchBuildingToggleAll/expected/.git_keep/config new file mode 100644 index 000000000..8ae104545 --- /dev/null +++ b/test/integration/patchBuildingToggleAll/expected/.git_keep/config @@ -0,0 +1,10 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true +[user] + email = CI@example.com + name = CI diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/description b/test/integration/patchBuildingToggleAll/expected/.git_keep/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/test/integration/patchBuildingToggleAll/expected/.git_keep/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/index b/test/integration/patchBuildingToggleAll/expected/.git_keep/index new file mode 100644 index 0000000000000000000000000000000000000000..291d34ebebffe18e21251c8c853556342abe66a3 GIT binary patch literal 163 zcmZ?q402{*U|<4b#w2TjQs$!- d: 鏌ョ湅'鏀惧純鏇存敼鈥橀夐」 D: 鏌ョ湅閲嶇疆閫夐」 f: 鎶撳彇 ctrl+o: 灏嗘枃浠跺悕澶嶅埗鍒板壀璐存澘 @@ -186,6 +185,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct e: 缂栬緫鏂囦欢 o: 鎵撳紑鏂囦欢 i: 娣诲姞鍒 .gitignore + d: 鏌ョ湅'鏀惧純鏇存敼鈥橀夐」 r: 鍒锋柊鏂囦欢 s: 灏嗘墍鏈夋洿鏀瑰姞鍏ヨ串钘 S: 鏌ョ湅闅愯棌閫夐」 diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index b80ef9656..93b9a2862 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -270,10 +270,6 @@ type MergingPanelState struct { UserVerticalScrolling bool } -type filePanelState struct { - listPanelState -} - // TODO: consider splitting this out into the window and the branches view type branchPanelState struct { listPanelState diff --git a/pkg/gui/presentation/files_test.go b/pkg/gui/presentation/files_test.go index 8e9baf4e5..441ec7b69 100644 --- a/pkg/gui/presentation/files_test.go +++ b/pkg/gui/presentation/files_test.go @@ -127,7 +127,7 @@ M file1 for _, s := range scenarios { s := s t.Run(s.name, func(t *testing.T) { - viewModel := filetree.NewCommitFileTreeViewModel(s.files, utils.NewDummyLog(), true) + viewModel := filetree.NewCommitFileTreeViewModel(func() []*models.CommitFile { return s.files }, utils.NewDummyLog(), true) for _, path := range s.collapsedPaths { viewModel.ToggleCollapsed(path) } From e2f5fe101621c0162791d6ea312ef8093616f59c Mon Sep 17 00:00:00 2001 From: Jesse Duffield## Bestanden Paneel (Submodules) diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index afc1d3c9c..cb6192968 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -20,6 +20,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct @: open command log menu }: Increase the size of the context shown around changes in the diff view {: Decrease the size of the context shown around changes in the diff view + :: wykonaj w艂asn膮 komend臋 z: undo (via reflog) (experimental) ctrl+z: redo (via reflog) (experimental) P: push @@ -41,6 +42,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Ga艂臋zie Panel (Branches Tab)Date: Sun, 30 Jan 2022 16:43:58 +1100 Subject: [PATCH 043/385] pretty sure we can rely on our views existing before our contexts do --- pkg/gui/context_test.go | 41 ----------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 pkg/gui/context_test.go diff --git a/pkg/gui/context_test.go b/pkg/gui/context_test.go deleted file mode 100644 index 3a0aa120a..000000000 --- a/pkg/gui/context_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package gui - -import ( - "testing" - - "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/stretchr/testify/assert" -) - -func TestCanDeactivatePopupContextsWithoutViews(t *testing.T) { - contexts := []func(gui *Gui) types.Context{ - func(gui *Gui) types.Context { return gui.State.Contexts.Credentials }, - func(gui *Gui) types.Context { return gui.State.Contexts.Confirmation }, - func(gui *Gui) types.Context { return gui.State.Contexts.CommitMessage }, - func(gui *Gui) types.Context { return gui.State.Contexts.Search }, - } - - for _, c := range contexts { - gui := NewDummyGui() - context := c(gui) - gui.g = &gocui.Gui{} - - _ = gui.deactivateContext(context) - - // This really only checks a prerequisit, not the effect of deactivateContext - view, _ := gui.g.View(context.GetViewName()) - assert.Nil(t, view, string(context.GetKey())) - } -} - -func TestCanDeactivateCommitFilesContextsWithoutViews(t *testing.T) { - gui := NewDummyGui() - gui.g = &gocui.Gui{} - - _ = gui.deactivateContext(gui.State.Contexts.CommitFiles) - - // This really only checks a prerequisite, not the effect of deactivateContext - view, _ := gui.g.View(gui.State.Contexts.CommitFiles.GetViewName()) - assert.Nil(t, view) -} From 0a8cff6ab68dc92b98136c4ebe5c6bc7f8f1b3c7 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 30 Jan 2022 20:03:08 +1100 Subject: [PATCH 044/385] some more refactoring --- pkg/gui/branches_panel.go | 63 +----- pkg/gui/cherry_picking.go | 187 ----------------- pkg/gui/commit_files_panel.go | 2 +- pkg/gui/context.go | 8 +- pkg/gui/context/commit_files_context.go | 10 +- pkg/gui/context/tags_context.go | 14 +- pkg/gui/context/working_tree_context.go | 10 +- pkg/gui/controllers/cherry_pick_helper.go | 156 ++++++++++++++ .../controllers/local_commits_controller.go | 71 +++++-- pkg/gui/controllers/rebase_helper.go | 192 ++++++++++++++++++ pkg/gui/controllers/sync_controller.go | 8 +- pkg/gui/controllers/types.go | 1 + pkg/gui/diffing.go | 10 +- pkg/gui/files_panel.go | 14 -- pkg/gui/gui.go | 20 +- pkg/gui/keybindings.go | 55 ++--- pkg/gui/list_context.go | 9 +- pkg/gui/list_context_config.go | 62 ++++-- pkg/gui/modes.go | 4 +- pkg/gui/modes/cherrypicking/cherry_picking.go | 4 +- pkg/gui/patch_options_panel.go | 8 +- pkg/gui/rebase_options_panel.go | 156 -------------- pkg/gui/reflog_panel.go | 19 ++ pkg/gui/refresh.go | 2 +- pkg/gui/{ref_helper.go => refs_helper.go} | 46 ++++- pkg/gui/remote_branches_panel.go | 13 ++ pkg/gui/stash_panel.go | 9 + pkg/gui/status_panel.go | 2 +- pkg/gui/sub_commits_panel.go | 28 +++ pkg/gui/types/common.go | 2 - pkg/gui/types/context.go | 2 +- 31 files changed, 647 insertions(+), 540 deletions(-) delete mode 100644 pkg/gui/cherry_picking.go create mode 100644 pkg/gui/controllers/cherry_pick_helper.go create mode 100644 pkg/gui/controllers/rebase_helper.go delete mode 100644 pkg/gui/rebase_options_panel.go rename pkg/gui/{ref_helper.go => refs_helper.go} (76%) diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index fa60b5ed7..9cf0d740a 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -7,7 +7,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -240,7 +239,7 @@ func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error { HandleConfirm: func() error { gui.c.LogAction(gui.c.Tr.Actions.Merge) err := gui.git.Branch.Merge(branchName, git_commands.MergeOpts{}) - return gui.checkMergeOrRebase(err) + return gui.helpers.rebase.CheckMergeOrRebase(err) }, }) } @@ -274,7 +273,7 @@ func (gui *Gui) handleRebaseOntoBranch(selectedBranchName string) error { HandleConfirm: func() error { gui.c.LogAction(gui.c.Tr.Actions.RebaseBranch) err := gui.git.Rebase.RebaseBranch(selectedBranchName) - return gui.checkMergeOrRebase(err) + return gui.helpers.rebase.CheckMergeOrRebase(err) }, }) } @@ -391,55 +390,6 @@ func (gui *Gui) handleRenameBranch() error { }) } -func (gui *Gui) handleNewBranchOffCurrentItem() error { - ctx := gui.currentSideListContext() - - item, ok := ctx.GetSelectedItem() - if !ok { - return nil - } - - message := utils.ResolvePlaceholderString( - gui.c.Tr.NewBranchNameBranchOff, - map[string]string{ - "branchName": item.Description(), - }, - ) - - prefilledName := "" - if ctx.GetKey() == context.REMOTE_BRANCHES_CONTEXT_KEY { - // will set to the remote's branch name without the remote name - prefilledName = strings.SplitAfterN(item.ID(), "/", 2)[1] - } - - return gui.c.Prompt(types.PromptOpts{ - Title: message, - InitialContent: prefilledName, - HandleConfirm: func(response string) error { - gui.c.LogAction(gui.c.Tr.Actions.CreateBranch) - if err := gui.git.Branch.New(sanitizedBranchName(response), item.ID()); err != nil { - return err - } - - // if we're currently in the branch commits context then the selected commit - // is about to go to the top of the list - if ctx.GetKey() == context.BRANCH_COMMITS_CONTEXT_KEY { - ctx.GetPanelState().SetSelectedLineIdx(0) - } - - if ctx.GetKey() != gui.State.Contexts.Branches.GetKey() { - if err := gui.c.PushContext(gui.State.Contexts.Branches); err != nil { - return err - } - } - - gui.State.Panels.Branches.SelectedLineIdx = 0 - - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) - }, - }) -} - // sanitizedBranchName will remove all spaces in favor of a dash "-" to meet // git's branch naming requirement. func sanitizedBranchName(input string) string { @@ -454,3 +404,12 @@ func (gui *Gui) handleEnterBranch() error { return gui.switchToSubCommitsContext(branch.RefName()) } + +func (gui *Gui) handleNewBranchOffBranch() error { + selectedBranch := gui.getSelectedBranch() + if selectedBranch == nil { + return nil + } + + return gui.helpers.refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), "") +} diff --git a/pkg/gui/cherry_picking.go b/pkg/gui/cherry_picking.go deleted file mode 100644 index 3cc7fca6d..000000000 --- a/pkg/gui/cherry_picking.go +++ /dev/null @@ -1,187 +0,0 @@ -package gui - -import ( - "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - -// you can only copy from one context at a time, because the order and position of commits matter - -func (gui *Gui) resetCherryPickingIfNecessary(context types.Context) error { - oldContextKey := types.ContextKey(gui.State.Modes.CherryPicking.ContextKey) - - if oldContextKey != context.GetKey() { - // need to reset the cherry picking mode - gui.State.Modes.CherryPicking.ContextKey = string(context.GetKey()) - gui.State.Modes.CherryPicking.CherryPickedCommits = make([]*models.Commit, 0) - - return gui.rerenderContextViewIfPresent(oldContextKey) - } - - return nil -} - -func (gui *Gui) handleCopyCommit() error { - // get currently selected commit, add the sha to state. - context := gui.currentSideListContext() - if context == nil { - return nil - } - - if err := gui.resetCherryPickingIfNecessary(context); err != nil { - return err - } - - item, ok := context.GetSelectedItem() - if !ok { - return nil - } - commit, ok := item.(*models.Commit) - if !ok { - return nil - } - - // we will un-copy it if it's already copied - for index, cherryPickedCommit := range gui.State.Modes.CherryPicking.CherryPickedCommits { - if commit.Sha == cherryPickedCommit.Sha { - gui.State.Modes.CherryPicking.CherryPickedCommits = append(gui.State.Modes.CherryPicking.CherryPickedCommits[0:index], gui.State.Modes.CherryPicking.CherryPickedCommits[index+1:]...) - return context.HandleRender() - } - } - - gui.addCommitToCherryPickedCommits(context.GetPanelState().GetSelectedLineIdx()) - return context.HandleRender() -} - -func (gui *Gui) cherryPickedCommitShaMap() map[string]bool { - commitShaMap := map[string]bool{} - for _, commit := range gui.State.Modes.CherryPicking.CherryPickedCommits { - commitShaMap[commit.Sha] = true - } - return commitShaMap -} - -func (gui *Gui) commitsListForContext() []*models.Commit { - ctx := gui.currentSideListContext() - if ctx == nil { - return nil - } - - // using a switch statement, but we should use polymorphism - switch ctx.GetKey() { - case context.BRANCH_COMMITS_CONTEXT_KEY: - return gui.State.Commits - case context.REFLOG_COMMITS_CONTEXT_KEY: - return gui.State.FilteredReflogCommits - case context.SUB_COMMITS_CONTEXT_KEY: - return gui.State.SubCommits - default: - gui.c.Log.Errorf("no commit list for context %s", ctx.GetKey()) - return nil - } -} - -func (gui *Gui) addCommitToCherryPickedCommits(index int) { - commitShaMap := gui.cherryPickedCommitShaMap() - commitsList := gui.commitsListForContext() - commitShaMap[commitsList[index].Sha] = true - - newCommits := []*models.Commit{} - for _, commit := range commitsList { - if commitShaMap[commit.Sha] { - // duplicating just the things we need to put in the rebase TODO list - newCommits = append(newCommits, &models.Commit{Name: commit.Name, Sha: commit.Sha}) - } - } - - gui.State.Modes.CherryPicking.CherryPickedCommits = newCommits -} - -func (gui *Gui) handleCopyCommitRange() error { - // get currently selected commit, add the sha to state. - context := gui.currentSideListContext() - if context == nil { - return nil - } - - if err := gui.resetCherryPickingIfNecessary(context); err != nil { - return err - } - - commitShaMap := gui.cherryPickedCommitShaMap() - commitsList := gui.commitsListForContext() - selectedLineIdx := context.GetPanelState().GetSelectedLineIdx() - - if selectedLineIdx > len(commitsList)-1 { - return nil - } - - // find the last commit that is copied that's above our position - // if there are none, startIndex = 0 - startIndex := 0 - for index, commit := range commitsList[0:selectedLineIdx] { - if commitShaMap[commit.Sha] { - startIndex = index - } - } - - for index := startIndex; index <= selectedLineIdx; index++ { - gui.addCommitToCherryPickedCommits(index) - } - - return context.HandleRender() -} - -// HandlePasteCommits begins a cherry-pick rebase with the commits the user has copied -func (gui *Gui) HandlePasteCommits() error { - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.CherryPick, - Prompt: gui.c.Tr.SureCherryPick, - HandleConfirm: func() error { - return gui.c.WithWaitingStatus(gui.c.Tr.CherryPickingStatus, func() error { - gui.c.LogAction(gui.c.Tr.Actions.CherryPick) - err := gui.git.Rebase.CherryPickCommits(gui.State.Modes.CherryPicking.CherryPickedCommits) - return gui.checkMergeOrRebase(err) - }) - }, - }) -} - -func (gui *Gui) exitCherryPickingMode() error { - contextKey := types.ContextKey(gui.State.Modes.CherryPicking.ContextKey) - - gui.State.Modes.CherryPicking.ContextKey = "" - gui.State.Modes.CherryPicking.CherryPickedCommits = nil - - if contextKey == "" { - gui.c.Log.Warn("context key blank when trying to exit cherry picking mode") - return nil - } - - return gui.rerenderContextViewIfPresent(contextKey) -} - -func (gui *Gui) rerenderContextViewIfPresent(contextKey types.ContextKey) error { - if contextKey == "" { - return nil - } - - context := gui.mustContextForContextKey(contextKey) - - viewName := context.GetViewName() - - view, err := gui.g.View(viewName) - if err != nil { - gui.c.Log.Error(err) - return nil - } - - if types.ContextKey(view.Context) == contextKey { - if err := context.HandleRender(); err != nil { - return err - } - } - - return nil -} diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index e4932d080..8e6410b9e 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -83,7 +83,7 @@ func (gui *Gui) handleDiscardOldFileChange() error { return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { gui.c.LogAction(gui.c.Tr.Actions.DiscardOldFileChange) if err := gui.git.Rebase.DiscardOldFileChanges(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, fileName); err != nil { - if err := gui.checkMergeOrRebase(err); err != nil { + if err := gui.helpers.rebase.CheckMergeOrRebase(err); err != nil { return err } } diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 1c115c04b..09b669b04 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -464,13 +464,7 @@ func (gui *Gui) getSideContextSelectedItemId() string { return "" } - item, ok := currentSideContext.GetSelectedItem() - - if ok { - return item.ID() - } - - return "" + return currentSideContext.GetSelectedItemId() } // currently unused diff --git a/pkg/gui/context/commit_files_context.go b/pkg/gui/context/commit_files_context.go index 84a5cd67c..dd557f6b2 100644 --- a/pkg/gui/context/commit_files_context.go +++ b/pkg/gui/context/commit_files_context.go @@ -62,7 +62,11 @@ func NewCommitFilesContext( return self } -func (self *CommitFilesContext) GetSelectedItem() (types.ListItem, bool) { - item := self.CommitFileTreeViewModel.GetSelectedFileNode() - return item, item != nil +func (self *CommitFilesContext) GetSelectedItemId() string { + item := self.GetSelectedFileNode() + if item == nil { + return "" + } + + return item.ID() } diff --git a/pkg/gui/context/tags_context.go b/pkg/gui/context/tags_context.go index c7b468972..fc6e1bde1 100644 --- a/pkg/gui/context/tags_context.go +++ b/pkg/gui/context/tags_context.go @@ -62,6 +62,15 @@ func NewTagsContext( return self } +func (self *TagsContext) GetSelectedItemId() string { + item := self.GetSelectedTag() + if item == nil { + return "" + } + + return item.ID() +} + type TagsViewModel struct { *traits.ListCursor getModel func() []*models.Tag @@ -79,11 +88,6 @@ func (self *TagsViewModel) GetSelectedTag() *models.Tag { return self.getModel()[self.GetSelectedLineIdx()] } -func (self *TagsViewModel) GetSelectedItem() (types.ListItem, bool) { - item := self.GetSelectedTag() - return item, item != nil -} - func NewTagsViewModel(getModel func() []*models.Tag) *TagsViewModel { self := &TagsViewModel{ getModel: getModel, diff --git a/pkg/gui/context/working_tree_context.go b/pkg/gui/context/working_tree_context.go index 68f197259..fafddf9e8 100644 --- a/pkg/gui/context/working_tree_context.go +++ b/pkg/gui/context/working_tree_context.go @@ -62,7 +62,11 @@ func NewWorkingTreeContext( return self } -func (self *WorkingTreeContext) GetSelectedItem() (types.ListItem, bool) { - item := self.FileTreeViewModel.GetSelectedFileNode() - return item, item != nil +func (self *WorkingTreeContext) GetSelectedItemId() string { + item := self.GetSelectedFileNode() + if item == nil { + return "" + } + + return item.ID() } diff --git a/pkg/gui/controllers/cherry_pick_helper.go b/pkg/gui/controllers/cherry_pick_helper.go new file mode 100644 index 000000000..3bce03132 --- /dev/null +++ b/pkg/gui/controllers/cherry_pick_helper.go @@ -0,0 +1,156 @@ +package controllers + +import ( + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type CherryPickHelper struct { + c *types.ControllerCommon + + git *commands.GitCommand + + getContexts func() context.ContextTree + getData func() *cherrypicking.CherryPicking + + rebaseHelper *RebaseHelper +} + +// I'm using the analogy of copy+paste in the terminology here because it's intuitively what's going on, +// even if in truth we're running git cherry-pick + +func NewCherryPickHelper( + c *types.ControllerCommon, + git *commands.GitCommand, + getContexts func() context.ContextTree, + getData func() *cherrypicking.CherryPicking, + rebaseHelper *RebaseHelper, +) *CherryPickHelper { + return &CherryPickHelper{ + c: c, + git: git, + getContexts: getContexts, + getData: getData, + rebaseHelper: rebaseHelper, + } +} + +func (self *CherryPickHelper) Copy(commit *models.Commit, commitsList []*models.Commit, context types.Context) error { + if err := self.resetIfNecessary(context); err != nil { + return err + } + + // we will un-copy it if it's already copied + for index, cherryPickedCommit := range self.getData().CherryPickedCommits { + if commit.Sha == cherryPickedCommit.Sha { + self.getData().CherryPickedCommits = append( + self.getData().CherryPickedCommits[0:index], + self.getData().CherryPickedCommits[index+1:]..., + ) + return self.rerender() + } + } + + self.add(commit, commitsList) + return self.rerender() +} + +func (self *CherryPickHelper) CopyRange(selectedIndex int, commitsList []*models.Commit, context types.Context) error { + if err := self.resetIfNecessary(context); err != nil { + return err + } + + commitShaMap := self.CherryPickedCommitShaMap() + + // find the last commit that is copied that's above our position + // if there are none, startIndex = 0 + startIndex := 0 + for index, commit := range commitsList[0:selectedIndex] { + if commitShaMap[commit.Sha] { + startIndex = index + } + } + + for index := startIndex; index <= selectedIndex; index++ { + commit := commitsList[index] + self.add(commit, commitsList) + } + + return self.rerender() +} + +// HandlePasteCommits begins a cherry-pick rebase with the commits the user has copied. +// Only to be called from the branch commits controller +func (self *CherryPickHelper) Paste() error { + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.CherryPick, + Prompt: self.c.Tr.SureCherryPick, + HandleConfirm: func() error { + return self.c.WithWaitingStatus(self.c.Tr.CherryPickingStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.CherryPick) + err := self.git.Rebase.CherryPickCommits(self.getData().CherryPickedCommits) + return self.rebaseHelper.CheckMergeOrRebase(err) + }) + }, + }) +} + +func (self *CherryPickHelper) Reset() error { + self.getData().ContextKey = "" + self.getData().CherryPickedCommits = nil + + return self.rerender() +} + +func (self *CherryPickHelper) CherryPickedCommitShaMap() map[string]bool { + commitShaMap := map[string]bool{} + for _, commit := range self.getData().CherryPickedCommits { + commitShaMap[commit.Sha] = true + } + return commitShaMap +} + +func (self *CherryPickHelper) add(selectedCommit *models.Commit, commitsList []*models.Commit) { + commitShaMap := self.CherryPickedCommitShaMap() + commitShaMap[selectedCommit.Sha] = true + + newCommits := []*models.Commit{} + for _, commit := range commitsList { + if commitShaMap[commit.Sha] { + // duplicating just the things we need to put in the rebase TODO list + newCommits = append(newCommits, &models.Commit{Name: commit.Name, Sha: commit.Sha}) + } + } + + self.getData().CherryPickedCommits = newCommits +} + +// you can only copy from one context at a time, because the order and position of commits matter +func (self *CherryPickHelper) resetIfNecessary(context types.Context) error { + oldContextKey := types.ContextKey(self.getData().ContextKey) + + if oldContextKey != context.GetKey() { + // need to reset the cherry picking mode + self.getData().ContextKey = string(context.GetKey()) + self.getData().CherryPickedCommits = make([]*models.Commit, 0) + } + + return nil +} + +func (self *CherryPickHelper) rerender() error { + for _, context := range []types.Context{ + self.getContexts().BranchCommits, + self.getContexts().ReflogCommits, + self.getContexts().SubCommits, + } { + if err := self.c.PostRefreshUpdate(context); err != nil { + return err + } + } + + return nil +} diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index 9e1cacca7..3e30619be 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -24,17 +24,19 @@ type ( ) type LocalCommitsController struct { - c *types.ControllerCommon - getContext func() types.IListContext - os *oscommands.OSCommand - git *commands.GitCommand - tagsHelper *TagsHelper - refsHelper IRefsHelper + c *types.ControllerCommon + getContext func() types.IListContext + os *oscommands.OSCommand + git *commands.GitCommand + tagsHelper *TagsHelper + refsHelper IRefsHelper + cherryPickHelper *CherryPickHelper + rebaseHelper *RebaseHelper getSelectedLocalCommit func() *models.Commit getCommits func() []*models.Commit getSelectedLocalCommitIdx func() int - checkMergeOrRebase CheckMergeOrRebase + CheckMergeOrRebase CheckMergeOrRebase pullFiles PullFilesFn getHostingServiceMgr GetHostingServiceMgrFn switchToCommitFilesContext SwitchToCommitFilesContextFn @@ -54,10 +56,12 @@ func NewLocalCommitsController( git *commands.GitCommand, tagsHelper *TagsHelper, refsHelper IRefsHelper, + cherryPickHelper *CherryPickHelper, + rebaseHelper *RebaseHelper, getSelectedLocalCommit func() *models.Commit, getCommits func() []*models.Commit, getSelectedLocalCommitIdx func() int, - checkMergeOrRebase CheckMergeOrRebase, + CheckMergeOrRebase CheckMergeOrRebase, pullFiles PullFilesFn, getHostingServiceMgr GetHostingServiceMgrFn, switchToCommitFilesContext SwitchToCommitFilesContextFn, @@ -74,10 +78,12 @@ func NewLocalCommitsController( git: git, tagsHelper: tagsHelper, refsHelper: refsHelper, + cherryPickHelper: cherryPickHelper, + rebaseHelper: rebaseHelper, getSelectedLocalCommit: getSelectedLocalCommit, getCommits: getCommits, getSelectedLocalCommitIdx: getSelectedLocalCommitIdx, - checkMergeOrRebase: checkMergeOrRebase, + CheckMergeOrRebase: CheckMergeOrRebase, pullFiles: pullFiles, getHostingServiceMgr: getHostingServiceMgr, switchToCommitFilesContext: switchToCommitFilesContext, @@ -160,6 +166,27 @@ func (self *LocalCommitsController) Keybindings( Handler: self.checkSelected(self.handleCommitRevert), Description: self.c.Tr.LcRevertCommit, }, + { + Key: getKey(config.Universal.New), + Modifier: gocui.ModNone, + Handler: self.checkSelected(self.newBranch), + Description: self.c.Tr.LcCreateNewBranchFromCommit, + }, + { + Key: getKey(config.Commits.CherryPickCopy), + Handler: self.checkSelected(self.copy), + Description: self.c.Tr.LcCherryPickCopy, + }, + { + Key: getKey(config.Commits.CherryPickCopyRange), + Handler: self.checkSelected(self.copyRange), + Description: self.c.Tr.LcCherryPickCopyRange, + }, + { + Key: getKey(config.Commits.PasteCommits), + Handler: guards.OutsideFilterMode(self.paste), + Description: self.c.Tr.LcPasteCommits, + }, // overriding these navigation keybindings because we might need to load // more commits on demand { @@ -380,7 +407,7 @@ func (self *LocalCommitsController) pick() error { func (self *LocalCommitsController) interactiveRebase(action string) error { err := self.git.Rebase.InteractiveRebase(self.getCommits(), self.getSelectedLocalCommitIdx(), action) - return self.checkMergeOrRebase(err) + return self.CheckMergeOrRebase(err) } // handleMidRebaseCommand sees if the selected commit is in fact a rebasing @@ -448,7 +475,7 @@ func (self *LocalCommitsController) handleCommitMoveDown() error { // TODO: use MoveSelectedLine _ = self.getContext().HandleNextLine() } - return self.checkMergeOrRebase(err) + return self.CheckMergeOrRebase(err) }) } @@ -483,7 +510,7 @@ func (self *LocalCommitsController) handleCommitMoveUp() error { if err == nil { _ = self.getContext().HandlePrevLine() } - return self.checkMergeOrRebase(err) + return self.CheckMergeOrRebase(err) }) } @@ -495,7 +522,7 @@ func (self *LocalCommitsController) handleCommitAmendTo() error { return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func() error { self.c.LogAction(self.c.Tr.Actions.AmendCommit) err := self.git.Rebase.AmendTo(self.getSelectedLocalCommit().Sha) - return self.checkMergeOrRebase(err) + return self.CheckMergeOrRebase(err) }) }, }) @@ -601,7 +628,7 @@ func (self *LocalCommitsController) handleSquashAllAboveFixupCommits(commit *mod return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func() error { self.c.LogAction(self.c.Tr.Actions.SquashAllAboveFixupCommits) err := self.git.Rebase.SquashAllAboveFixupCommits(commit.Sha) - return self.checkMergeOrRebase(err) + return self.CheckMergeOrRebase(err) }) }, }) @@ -781,3 +808,19 @@ func (self *LocalCommitsController) checkSelected(callback func(*models.Commit) func (self *LocalCommitsController) Context() types.Context { return self.getContext() } + +func (self *LocalCommitsController) newBranch(commit *models.Commit) error { + return self.refsHelper.NewBranch(commit.RefName(), commit.Description(), "") +} + +func (self *LocalCommitsController) copy(commit *models.Commit) error { + return self.cherryPickHelper.Copy(commit, self.getCommits(), self.getContext()) +} + +func (self *LocalCommitsController) copyRange(*models.Commit) error { + return self.cherryPickHelper.CopyRange(self.getContext().GetPanelState().GetSelectedLineIdx(), self.getCommits(), self.getContext()) +} + +func (self *LocalCommitsController) paste() error { + return self.cherryPickHelper.Paste() +} diff --git a/pkg/gui/controllers/rebase_helper.go b/pkg/gui/controllers/rebase_helper.go new file mode 100644 index 000000000..6515895c1 --- /dev/null +++ b/pkg/gui/controllers/rebase_helper.go @@ -0,0 +1,192 @@ +package controllers + +import ( + "fmt" + "strings" + + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/types/enums" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type RebaseHelper struct { + c *types.ControllerCommon + getContexts func() context.ContextTree + git *commands.GitCommand + takeOverMergeConflictScrolling func() +} + +func NewRebaseHelper( + c *types.ControllerCommon, + getContexts func() context.ContextTree, + git *commands.GitCommand, + takeOverMergeConflictScrolling func(), +) *RebaseHelper { + return &RebaseHelper{ + c: c, + getContexts: getContexts, + git: git, + takeOverMergeConflictScrolling: takeOverMergeConflictScrolling, + } +} + +type RebaseOption string + +const ( + REBASE_OPTION_CONTINUE string = "continue" + REBASE_OPTION_ABORT string = "abort" + REBASE_OPTION_SKIP string = "skip" +) + +func (self *RebaseHelper) CreateRebaseOptionsMenu() error { + options := []string{REBASE_OPTION_CONTINUE, REBASE_OPTION_ABORT} + + if self.git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING { + options = append(options, REBASE_OPTION_SKIP) + } + + menuItems := make([]*types.MenuItem, len(options)) + for i, option := range options { + // note to self. Never, EVER, close over loop variables in a function + option := option + menuItems[i] = &types.MenuItem{ + DisplayString: option, + OnPress: func() error { + return self.genericMergeCommand(option) + }, + } + } + + var title string + if self.git.Status.WorkingTreeState() == enums.REBASE_MODE_MERGING { + title = self.c.Tr.MergeOptionsTitle + } else { + title = self.c.Tr.RebaseOptionsTitle + } + + return self.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems}) +} + +func (self *RebaseHelper) genericMergeCommand(command string) error { + status := self.git.Status.WorkingTreeState() + + if status != enums.REBASE_MODE_MERGING && status != enums.REBASE_MODE_REBASING { + return self.c.ErrorMsg(self.c.Tr.NotMergingOrRebasing) + } + + self.c.LogAction(fmt.Sprintf("Merge/Rebase: %s", command)) + + commandType := "" + switch status { + case enums.REBASE_MODE_MERGING: + commandType = "merge" + case enums.REBASE_MODE_REBASING: + commandType = "rebase" + default: + // shouldn't be possible to land here + } + + // we should end up with a command like 'git merge --continue' + + // it's impossible for a rebase to require a commit so we'll use a subprocess only if it's a merge + if status == enums.REBASE_MODE_MERGING && command != REBASE_OPTION_ABORT && self.c.UserConfig.Git.Merging.ManualCommit { + // TODO: see if we should be calling more of the code from self.Git.Rebase.GenericMergeOrRebaseAction + return self.c.RunSubprocessAndRefresh( + self.git.Rebase.GenericMergeOrRebaseActionCmdObj(commandType, command), + ) + } + result := self.git.Rebase.GenericMergeOrRebaseAction(commandType, command) + if err := self.CheckMergeOrRebase(result); err != nil { + return err + } + return nil +} + +var conflictStrings = []string{ + "Failed to merge in the changes", + "When you have resolved this problem", + "fix conflicts", + "Resolve all conflicts manually", +} + +func isMergeConflictErr(errStr string) bool { + for _, str := range conflictStrings { + if strings.Contains(errStr, str) { + return true + } + } + + return false +} + +func (self *RebaseHelper) CheckMergeOrRebase(result error) error { + if err := self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil { + return err + } + if result == nil { + return nil + } else if strings.Contains(result.Error(), "No changes - did you forget to use") { + return self.genericMergeCommand(REBASE_OPTION_SKIP) + } else if strings.Contains(result.Error(), "The previous cherry-pick is now empty") { + return self.genericMergeCommand(REBASE_OPTION_CONTINUE) + } else if strings.Contains(result.Error(), "No rebase in progress?") { + // assume in this case that we're already done + return nil + } else if isMergeConflictErr(result.Error()) { + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.FoundConflictsTitle, + Prompt: self.c.Tr.FoundConflicts, + HandlersManageFocus: true, + HandleConfirm: func() error { + return self.c.PushContext(self.getContexts().Files) + }, + HandleClose: func() error { + if err := self.c.PopContext(); err != nil { + return err + } + + return self.genericMergeCommand(REBASE_OPTION_ABORT) + }, + }) + } else { + return self.c.ErrorMsg(result.Error()) + } +} + +func (self *RebaseHelper) AbortMergeOrRebaseWithConfirm() error { + // prompt user to confirm that they want to abort, then do it + mode := self.workingTreeStateNoun() + return self.c.Ask(types.AskOpts{ + Title: fmt.Sprintf(self.c.Tr.AbortTitle, mode), + Prompt: fmt.Sprintf(self.c.Tr.AbortPrompt, mode), + HandleConfirm: func() error { + return self.genericMergeCommand(REBASE_OPTION_ABORT) + }, + }) +} + +func (self *RebaseHelper) workingTreeStateNoun() string { + workingTreeState := self.git.Status.WorkingTreeState() + switch workingTreeState { + case enums.REBASE_MODE_NONE: + return "" + case enums.REBASE_MODE_MERGING: + return "merge" + default: + return "rebase" + } +} + +// PromptToContinueRebase asks the user if they want to continue the rebase/merge that's in progress +func (self *RebaseHelper) PromptToContinueRebase() error { + self.takeOverMergeConflictScrolling() + + return self.c.Ask(types.AskOpts{ + Title: "continue", + Prompt: self.c.Tr.ConflictsResolved, + HandleConfirm: func() error { + return self.genericMergeCommand(REBASE_OPTION_CONTINUE) + }, + }) +} diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go index e84e3f731..582d8a9de 100644 --- a/pkg/gui/controllers/sync_controller.go +++ b/pkg/gui/controllers/sync_controller.go @@ -22,7 +22,7 @@ type SyncController struct { getCheckedOutBranch func() *models.Branch suggestionsHelper ISuggestionsHelper getSuggestedRemote func() string - checkMergeOrRebase func(error) error + CheckMergeOrRebase func(error) error } var _ types.IController = &SyncController{} @@ -33,7 +33,7 @@ func NewSyncController( getCheckedOutBranch func() *models.Branch, suggestionsHelper ISuggestionsHelper, getSuggestedRemote func() string, - checkMergeOrRebase func(error) error, + CheckMergeOrRebase func(error) error, ) *SyncController { return &SyncController{ c: c, @@ -42,7 +42,7 @@ func NewSyncController( getCheckedOutBranch: getCheckedOutBranch, suggestionsHelper: suggestionsHelper, getSuggestedRemote: getSuggestedRemote, - checkMergeOrRebase: checkMergeOrRebase, + CheckMergeOrRebase: CheckMergeOrRebase, } } @@ -191,7 +191,7 @@ func (self *SyncController) pullWithLock(opts PullFilesOptions) error { }, ) - return self.checkMergeOrRebase(err) + return self.CheckMergeOrRebase(err) } type pushOpts struct { diff --git a/pkg/gui/controllers/types.go b/pkg/gui/controllers/types.go index ec0b71a90..c3466e536 100644 --- a/pkg/gui/controllers/types.go +++ b/pkg/gui/controllers/types.go @@ -9,6 +9,7 @@ type IRefsHelper interface { CheckoutRef(ref string, options types.CheckoutRefOptions) error CreateGitResetMenu(ref string) error ResetToRef(ref string, strength string, envVars []string) error + NewBranch(from string, fromDescription string, suggestedBranchname string) error } type ISuggestionsHelper interface { diff --git a/pkg/gui/diffing.go b/pkg/gui/diffing.go index 385139b76..9b636e196 100644 --- a/pkg/gui/diffing.go +++ b/pkg/gui/diffing.go @@ -53,15 +53,11 @@ func (gui *Gui) currentDiffTerminals() []string { } return nil default: - context := gui.currentSideListContext() - if context == nil { + itemId := gui.getSideContextSelectedItemId() + if itemId == "" { return nil } - item, ok := context.GetSelectedItem() - if !ok { - return nil - } - return []string{item.ID()} + return []string{itemId} } } diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index 1ec32e708..0ffdcfc6c 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -4,7 +4,6 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/filetree" - "github.com/jesseduffield/lazygit/pkg/gui/types" ) // list panel functions @@ -77,19 +76,6 @@ func (gui *Gui) filesRenderToMain() error { return gui.refreshMainViews(refreshOpts) } -// promptToContinueRebase asks the user if they want to continue the rebase/merge that's in progress -func (gui *Gui) promptToContinueRebase() error { - gui.takeOverMergeConflictScrolling() - - return gui.PopupHandler.Ask(types.AskOpts{ - Title: "continue", - Prompt: gui.Tr.ConflictsResolved, - HandleConfirm: func() error { - return gui.genericMergeCommand(REBASE_OPTION_CONTINUE) - }, - }) -} - func (gui *Gui) onFocusFile() error { gui.takeOverMergeConflictScrolling() return nil diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 93b9a2862..490ffca53 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -74,6 +74,8 @@ type Helpers struct { files *FilesHelper workingTree *WorkingTreeHelper tags *controllers.TagsHelper + rebase *controllers.RebaseHelper + cherryPick *controllers.CherryPickHelper } type Repo string @@ -373,7 +375,7 @@ const ( type Modes struct { Filtering filtering.Filtering - CherryPicking cherrypicking.CherryPicking + CherryPicking *cherrypicking.CherryPicking Diffing diffing.Diffing } @@ -556,10 +558,12 @@ func (gui *Gui) setControllers() { getState := func() *GuiRepoState { return gui.State } getContexts := func() context.ContextTree { return gui.State.Contexts } // TODO: have a getGit function too + rebaseHelper := controllers.NewRebaseHelper(controllerCommon, getContexts, gui.git, gui.takeOverMergeConflictScrolling) gui.helpers = &Helpers{ refs: NewRefsHelper( controllerCommon, gui.git, + getContexts, getState, ), bisect: controllers.NewBisectHelper(controllerCommon, gui.git), @@ -567,6 +571,14 @@ func (gui *Gui) setControllers() { files: NewFilesHelper(controllerCommon, gui.git, osCommand), workingTree: NewWorkingTreeHelper(func() []*models.File { return gui.State.Files }), tags: controllers.NewTagsHelper(controllerCommon, gui.git), + rebase: rebaseHelper, + cherryPick: controllers.NewCherryPickHelper( + controllerCommon, + gui.git, + getContexts, + func() *cherrypicking.CherryPicking { return gui.State.Modes.CherryPicking }, + rebaseHelper, + ), } syncController := controllers.NewSyncController( @@ -575,7 +587,7 @@ func (gui *Gui) setControllers() { gui.getCheckedOutBranch, gui.helpers.suggestions, gui.getSuggestedRemote, - gui.checkMergeOrRebase, + gui.helpers.rebase.CheckMergeOrRebase, ) gui.Controllers = Controllers{ @@ -624,10 +636,12 @@ func (gui *Gui) setControllers() { gui.git, gui.helpers.tags, gui.helpers.refs, + gui.helpers.cherryPick, + gui.helpers.rebase, gui.getSelectedLocalCommit, func() []*models.Commit { return gui.State.Commits }, func() int { return gui.State.Panels.Commits.SelectedLineIdx }, - gui.checkMergeOrRebase, + gui.helpers.rebase.CheckMergeOrRebase, syncController.HandlePull, gui.getHostingServiceMgr, gui.SwitchToCommitFilesContext, diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 4d8eddb48..123e6f5b5 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -276,7 +276,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { { ViewName: "", Key: gui.getKey(config.Universal.CreateRebaseOptionsMenu), - Handler: gui.handleCreateRebaseOptionsMenu, + Handler: gui.helpers.rebase.CreateRebaseOptionsMenu, Description: gui.c.Tr.ViewMergeRebaseOptions, OpensMenu: true, }, @@ -423,7 +423,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { ViewName: "branches", Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.New), - Handler: gui.handleNewBranchOffCurrentItem, + Handler: gui.handleNewBranchOffBranch, Description: gui.c.Tr.LcNewBranch, }, { @@ -513,13 +513,6 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Handler: gui.handleEnterRemoteBranch, Description: gui.c.Tr.LcViewCommits, }, - { - ViewName: "commits", - Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.CherryPickCopy), - Handler: gui.handleCopyCommit, - Description: gui.c.Tr.LcCherryPickCopy, - }, { ViewName: "commits", Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)}, @@ -527,33 +520,11 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Handler: gui.handleCopySelectedSideContextItemToClipboard, Description: gui.c.Tr.LcCopyCommitShaToClipboard, }, - { - ViewName: "commits", - Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.CherryPickCopyRange), - Handler: gui.handleCopyCommitRange, - Description: gui.c.Tr.LcCherryPickCopyRange, - }, - { - ViewName: "commits", - Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.PasteCommits), - Handler: guards.OutsideFilterMode(gui.HandlePasteCommits), - Description: gui.c.Tr.LcPasteCommits, - }, - { - ViewName: "commits", - Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.New), - Modifier: gocui.ModNone, - Handler: gui.handleNewBranchOffCurrentItem, - Description: gui.c.Tr.LcCreateNewBranchFromCommit, - }, { ViewName: "commits", Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.ResetCherryPick), - Handler: gui.exitCherryPickingMode, + Handler: gui.helpers.cherryPick.Reset, Description: gui.c.Tr.LcResetCherryPick, }, { @@ -582,21 +553,21 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { ViewName: "commits", Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.CherryPickCopy), - Handler: guards.OutsideFilterMode(gui.handleCopyCommit), + Handler: guards.OutsideFilterMode(gui.handleCopyReflogCommit), Description: gui.c.Tr.LcCherryPickCopy, }, { ViewName: "commits", Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.CherryPickCopyRange), - Handler: guards.OutsideFilterMode(gui.handleCopyCommitRange), + Handler: guards.OutsideFilterMode(gui.handleCopyReflogCommitRange), Description: gui.c.Tr.LcCherryPickCopyRange, }, { ViewName: "commits", Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.ResetCherryPick), - Handler: gui.exitCherryPickingMode, + Handler: gui.helpers.cherryPick.Reset, Description: gui.c.Tr.LcResetCherryPick, }, { @@ -632,28 +603,28 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.New), - Handler: gui.handleNewBranchOffCurrentItem, + Handler: gui.handleNewBranchOffSubCommit, Description: gui.c.Tr.LcNewBranch, }, { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.CherryPickCopy), - Handler: gui.handleCopyCommit, + Handler: gui.handleCopySubCommit, Description: gui.c.Tr.LcCherryPickCopy, }, { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.CherryPickCopyRange), - Handler: gui.handleCopyCommitRange, + Handler: gui.handleCopySubCommitRange, Description: gui.c.Tr.LcCherryPickCopyRange, }, { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.ResetCherryPick), - Handler: gui.exitCherryPickingMode, + Handler: gui.helpers.cherryPick.Reset, Description: gui.c.Tr.LcResetCherryPick, }, { @@ -690,7 +661,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { { ViewName: "stash", Key: gui.getKey(config.Universal.New), - Handler: gui.handleNewBranchOffCurrentItem, + Handler: gui.handleNewBranchOffStashEntry, Description: gui.c.Tr.LcNewBranch, }, { @@ -1220,14 +1191,14 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.Select), // gonna use the exact same handler as the 'n' keybinding because everybody wants this to happen when they checkout a remote branch - Handler: gui.handleNewBranchOffCurrentItem, + Handler: gui.handleNewBranchOffRemoteBranch, Description: gui.c.Tr.LcCheckout, }, { ViewName: "branches", Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, Key: gui.getKey(config.Universal.New), - Handler: gui.handleNewBranchOffCurrentItem, + Handler: gui.handleNewBranchOffRemoteBranch, Description: gui.c.Tr.LcNewBranch, }, { diff --git a/pkg/gui/list_context.go b/pkg/gui/list_context.go index fbdf78c50..f2da7aaac 100644 --- a/pkg/gui/list_context.go +++ b/pkg/gui/list_context.go @@ -16,9 +16,8 @@ type ListContext struct { OnRenderToMain func(...types.OnFocusOpts) error OnFocusLost func() error - // the boolean here tells us whether the item is nil. This is needed because you can't work it out on the calling end once the pointer is wrapped in an interface (unless you want to use reflection) - SelectedItem func() (types.ListItem, bool) - OnGetPanelState func() types.IListPanelState + OnGetSelectedItemId func() string + OnGetPanelState func() types.IListPanelState // if this is true, we'll call GetDisplayStrings for just the visible part of the // view and re-render that. This is useful when you need to render different // content based on the selection (e.g. for showing the selected commit) @@ -56,8 +55,8 @@ func formatListFooter(selectedLineIdx int, length int) string { return fmt.Sprintf("%d of %d", selectedLineIdx+1, length) } -func (self *ListContext) GetSelectedItem() (types.ListItem, bool) { - return self.SelectedItem() +func (self *ListContext) GetSelectedItemId() string { + return self.OnGetSelectedItemId() } // OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index 8137ace82..cbbf98cca 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -63,9 +63,12 @@ func (gui *Gui) branchesListContext() types.IListContext { GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref) }, - SelectedItem: func() (types.ListItem, bool) { + OnGetSelectedItemId: func() string { item := gui.getSelectedBranch() - return item, item != nil + if item == nil { + return "" + } + return item.ID() }, } } @@ -85,9 +88,12 @@ func (gui *Gui) remotesListContext() types.IListContext { GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetRemoteListDisplayStrings(gui.State.Remotes, gui.State.Modes.Diffing.Ref) }, - SelectedItem: func() (types.ListItem, bool) { + OnGetSelectedItemId: func() string { item := gui.getSelectedRemote() - return item, item != nil + if item == nil { + return "" + } + return item.ID() }, } } @@ -107,9 +113,12 @@ func (gui *Gui) remoteBranchesListContext() types.IListContext { GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetRemoteBranchListDisplayStrings(gui.State.RemoteBranches, gui.State.Modes.Diffing.Ref) }, - SelectedItem: func() (types.ListItem, bool) { + OnGetSelectedItemId: func() string { item := gui.getSelectedRemoteBranch() - return item, item != nil + if item == nil { + return "" + } + return item.ID() }, } } @@ -163,7 +172,7 @@ func (gui *Gui) branchCommitsListContext() types.IListContext { return presentation.GetCommitListDisplayStrings( gui.State.Commits, gui.State.ScreenMode != SCREEN_NORMAL, - gui.cherryPickedCommitShaMap(), + gui.helpers.cherryPick.CherryPickedCommitShaMap(), gui.State.Modes.Diffing.Ref, parseEmoji, selectedCommitSha, @@ -173,9 +182,12 @@ func (gui *Gui) branchCommitsListContext() types.IListContext { gui.State.BisectInfo, ) }, - SelectedItem: func() (types.ListItem, bool) { + OnGetSelectedItemId: func() string { item := gui.getSelectedLocalCommit() - return item, item != nil + if item == nil { + return "" + } + return item.ID() }, RenderSelection: true, } @@ -205,7 +217,7 @@ func (gui *Gui) subCommitsListContext() types.IListContext { return presentation.GetCommitListDisplayStrings( gui.State.SubCommits, gui.State.ScreenMode != SCREEN_NORMAL, - gui.cherryPickedCommitShaMap(), + gui.helpers.cherryPick.CherryPickedCommitShaMap(), gui.State.Modes.Diffing.Ref, parseEmoji, selectedCommitSha, @@ -215,9 +227,12 @@ func (gui *Gui) subCommitsListContext() types.IListContext { git_commands.NewNullBisectInfo(), ) }, - SelectedItem: func() (types.ListItem, bool) { + OnGetSelectedItemId: func() string { item := gui.getSelectedSubCommit() - return item, item != nil + if item == nil { + return "" + } + return item.ID() }, RenderSelection: true, } @@ -259,14 +274,17 @@ func (gui *Gui) reflogCommitsListContext() types.IListContext { return presentation.GetReflogCommitListDisplayStrings( gui.State.FilteredReflogCommits, gui.State.ScreenMode != SCREEN_NORMAL, - gui.cherryPickedCommitShaMap(), + gui.helpers.cherryPick.CherryPickedCommitShaMap(), gui.State.Modes.Diffing.Ref, parseEmoji, ) }, - SelectedItem: func() (types.ListItem, bool) { + OnGetSelectedItemId: func() string { item := gui.getSelectedReflogCommit() - return item, item != nil + if item == nil { + return "" + } + return item.ID() }, } } @@ -286,9 +304,12 @@ func (gui *Gui) stashListContext() types.IListContext { GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetStashEntryListDisplayStrings(gui.State.StashEntries, gui.State.Modes.Diffing.Ref) }, - SelectedItem: func() (types.ListItem, bool) { + OnGetSelectedItemId: func() string { item := gui.getSelectedStashEntry() - return item, item != nil + if item == nil { + return "" + } + return item.ID() }, } } @@ -332,9 +353,12 @@ func (gui *Gui) submodulesListContext() types.IListContext { GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetSubmoduleListDisplayStrings(gui.State.Submodules) }, - SelectedItem: func() (types.ListItem, bool) { + OnGetSelectedItemId: func() string { item := gui.getSelectedSubmodule() - return item, item != nil + if item == nil { + return "" + } + return item.ID() }, } } diff --git a/pkg/gui/modes.go b/pkg/gui/modes.go index 0f2af6192..2936a560e 100644 --- a/pkg/gui/modes.go +++ b/pkg/gui/modes.go @@ -61,7 +61,7 @@ func (gui *Gui) modeStatuses() []modeStatus { style.FgCyan, ) }, - reset: gui.exitCherryPickingMode, + reset: gui.helpers.cherryPick.Reset, }, { isActive: func() bool { @@ -73,7 +73,7 @@ func (gui *Gui) modeStatuses() []modeStatus { formatWorkingTreeState(workingTreeState), style.FgYellow, ) }, - reset: gui.abortMergeOrRebaseWithConfirm, + reset: gui.helpers.rebase.AbortMergeOrRebaseWithConfirm, }, { isActive: func() bool { diff --git a/pkg/gui/modes/cherrypicking/cherry_picking.go b/pkg/gui/modes/cherrypicking/cherry_picking.go index 705735510..bd5c6437a 100644 --- a/pkg/gui/modes/cherrypicking/cherry_picking.go +++ b/pkg/gui/modes/cherrypicking/cherry_picking.go @@ -11,8 +11,8 @@ type CherryPicking struct { ContextKey string } -func New() CherryPicking { - return CherryPicking{ +func New() *CherryPicking { + return &CherryPicking{ CherryPickedCommits: make([]*models.Commit, 0), ContextKey: "", } diff --git a/pkg/gui/patch_options_panel.go b/pkg/gui/patch_options_panel.go index 1ae0693f1..c0333dad1 100644 --- a/pkg/gui/patch_options_panel.go +++ b/pkg/gui/patch_options_panel.go @@ -102,7 +102,7 @@ func (gui *Gui) handleDeletePatchFromCommit() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.RemovePatchFromCommit) err := gui.git.Patch.DeletePatchesFromCommit(gui.State.Commits, commitIndex) - return gui.checkMergeOrRebase(err) + return gui.helpers.rebase.CheckMergeOrRebase(err) }) } @@ -119,7 +119,7 @@ func (gui *Gui) handleMovePatchToSelectedCommit() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.MovePatchToSelectedCommit) err := gui.git.Patch.MovePatchToSelectedCommit(gui.State.Commits, commitIndex, gui.State.Panels.Commits.SelectedLineIdx) - return gui.checkMergeOrRebase(err) + return gui.helpers.rebase.CheckMergeOrRebase(err) }) } @@ -137,7 +137,7 @@ func (gui *Gui) handleMovePatchIntoWorkingTree() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoIndex) err := gui.git.Patch.MovePatchIntoIndex(gui.State.Commits, commitIndex, stash) - return gui.checkMergeOrRebase(err) + return gui.helpers.rebase.CheckMergeOrRebase(err) }) } @@ -167,7 +167,7 @@ func (gui *Gui) handlePullPatchIntoNewCommit() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoNewCommit) err := gui.git.Patch.PullPatchIntoNewCommit(gui.State.Commits, commitIndex) - return gui.checkMergeOrRebase(err) + return gui.helpers.rebase.CheckMergeOrRebase(err) }) } diff --git a/pkg/gui/rebase_options_panel.go b/pkg/gui/rebase_options_panel.go deleted file mode 100644 index 897c389f8..000000000 --- a/pkg/gui/rebase_options_panel.go +++ /dev/null @@ -1,156 +0,0 @@ -package gui - -import ( - "fmt" - "strings" - - "github.com/jesseduffield/lazygit/pkg/commands/types/enums" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - -type RebaseOption string - -const ( - REBASE_OPTION_CONTINUE = "continue" - REBASE_OPTION_ABORT = "abort" - REBASE_OPTION_SKIP = "skip" -) - -func (gui *Gui) handleCreateRebaseOptionsMenu() error { - options := []string{REBASE_OPTION_CONTINUE, REBASE_OPTION_ABORT} - - if gui.git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING { - options = append(options, REBASE_OPTION_SKIP) - } - - menuItems := make([]*types.MenuItem, len(options)) - for i, option := range options { - // note to self. Never, EVER, close over loop variables in a function - option := option - menuItems[i] = &types.MenuItem{ - DisplayString: option, - OnPress: func() error { - return gui.genericMergeCommand(option) - }, - } - } - - var title string - if gui.git.Status.WorkingTreeState() == enums.REBASE_MODE_MERGING { - title = gui.c.Tr.MergeOptionsTitle - } else { - title = gui.c.Tr.RebaseOptionsTitle - } - - return gui.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems}) -} - -func (gui *Gui) genericMergeCommand(command string) error { - status := gui.git.Status.WorkingTreeState() - - if status != enums.REBASE_MODE_MERGING && status != enums.REBASE_MODE_REBASING { - return gui.c.ErrorMsg(gui.c.Tr.NotMergingOrRebasing) - } - - gui.c.LogAction(fmt.Sprintf("Merge/Rebase: %s", command)) - - commandType := "" - switch status { - case enums.REBASE_MODE_MERGING: - commandType = "merge" - case enums.REBASE_MODE_REBASING: - commandType = "rebase" - default: - // shouldn't be possible to land here - } - - // we should end up with a command like 'git merge --continue' - - // it's impossible for a rebase to require a commit so we'll use a subprocess only if it's a merge - if status == enums.REBASE_MODE_MERGING && command != REBASE_OPTION_ABORT && gui.c.UserConfig.Git.Merging.ManualCommit { - // TODO: see if we should be calling more of the code from gui.Git.Rebase.GenericMergeOrRebaseAction - return gui.runSubprocessWithSuspenseAndRefresh( - gui.git.Rebase.GenericMergeOrRebaseActionCmdObj(commandType, command), - ) - } - result := gui.git.Rebase.GenericMergeOrRebaseAction(commandType, command) - if err := gui.checkMergeOrRebase(result); err != nil { - return err - } - return nil -} - -var conflictStrings = []string{ - "Failed to merge in the changes", - "When you have resolved this problem", - "fix conflicts", - "Resolve all conflicts manually", -} - -func isMergeConflictErr(errStr string) bool { - for _, str := range conflictStrings { - if strings.Contains(errStr, str) { - return true - } - } - - return false -} - -func (gui *Gui) checkMergeOrRebase(result error) error { - if err := gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil { - return err - } - if result == nil { - return nil - } else if strings.Contains(result.Error(), "No changes - did you forget to use") { - return gui.genericMergeCommand(REBASE_OPTION_SKIP) - } else if strings.Contains(result.Error(), "The previous cherry-pick is now empty") { - return gui.genericMergeCommand(REBASE_OPTION_CONTINUE) - } else if strings.Contains(result.Error(), "No rebase in progress?") { - // assume in this case that we're already done - return nil - } else if isMergeConflictErr(result.Error()) { - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.FoundConflictsTitle, - Prompt: gui.c.Tr.FoundConflicts, - HandlersManageFocus: true, - HandleConfirm: func() error { - return gui.c.PushContext(gui.State.Contexts.Files) - }, - HandleClose: func() error { - if err := gui.returnFromContext(); err != nil { - return err - } - - return gui.genericMergeCommand(REBASE_OPTION_ABORT) - }, - }) - } else { - return gui.c.ErrorMsg(result.Error()) - } -} - -func (gui *Gui) abortMergeOrRebaseWithConfirm() error { - // prompt user to confirm that they want to abort, then do it - mode := gui.workingTreeStateNoun() - return gui.c.Ask(types.AskOpts{ - Title: fmt.Sprintf(gui.c.Tr.AbortTitle, mode), - Prompt: fmt.Sprintf(gui.c.Tr.AbortPrompt, mode), - HandleConfirm: func() error { - return gui.genericMergeCommand(REBASE_OPTION_ABORT) - }, - }) -} - -func (gui *Gui) workingTreeStateNoun() string { - workingTreeState := gui.git.Status.WorkingTreeState() - switch workingTreeState { - case enums.REBASE_MODE_NONE: - return "" - case enums.REBASE_MODE_MERGING: - return "merge" - default: - return "rebase" - } -} diff --git a/pkg/gui/reflog_panel.go b/pkg/gui/reflog_panel.go index 39292c7ba..a460cc2bd 100644 --- a/pkg/gui/reflog_panel.go +++ b/pkg/gui/reflog_panel.go @@ -79,3 +79,22 @@ func (gui *Gui) handleViewReflogCommitFiles() error { WindowName: "commits", }) } + +func (gui *Gui) handleCopyReflogCommit() error { + commit := gui.getSelectedReflogCommit() + if commit == nil { + return nil + } + + return gui.helpers.cherryPick.Copy(commit, gui.State.FilteredReflogCommits, gui.State.Contexts.ReflogCommits) +} + +func (gui *Gui) handleCopyReflogCommitRange() error { + // just doing this to ensure something is selected + commit := gui.getSelectedReflogCommit() + if commit == nil { + return nil + } + + return gui.helpers.cherryPick.CopyRange(gui.State.Contexts.ReflogCommits.GetPanelState().GetSelectedLineIdx(), gui.State.FilteredReflogCommits, gui.State.Contexts.ReflogCommits) +} diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go index 2f08c57c5..62959d3e3 100644 --- a/pkg/gui/refresh.go +++ b/pkg/gui/refresh.go @@ -408,7 +408,7 @@ func (gui *Gui) refreshStateFiles() error { } if gui.git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE && conflictFileCount == 0 && prevConflictFileCount > 0 { - gui.OnUIThread(func() error { return gui.promptToContinueRebase() }) + gui.OnUIThread(func() error { return gui.helpers.rebase.PromptToContinueRebase() }) } fileTreeViewModel.RWMutex.Lock() diff --git a/pkg/gui/ref_helper.go b/pkg/gui/refs_helper.go similarity index 76% rename from pkg/gui/ref_helper.go rename to pkg/gui/refs_helper.go index 1d1e408c2..f732ce204 100644 --- a/pkg/gui/ref_helper.go +++ b/pkg/gui/refs_helper.go @@ -6,14 +6,17 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" + "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" ) type RefsHelper struct { - c *types.ControllerCommon - git *commands.GitCommand + c *types.ControllerCommon + git *commands.GitCommand + getContexts func() context.ContextTree getState func() *GuiRepoState } @@ -21,12 +24,14 @@ type RefsHelper struct { func NewRefsHelper( c *types.ControllerCommon, git *commands.GitCommand, + getContexts func() context.ContextTree, getState func() *GuiRepoState, ) *RefsHelper { return &RefsHelper{ - c: c, - git: git, - getState: getState, + c: c, + git: git, + getContexts: getContexts, + getState: getState, } } @@ -134,3 +139,34 @@ func (self *RefsHelper) CreateGitResetMenu(ref string) error { Items: menuItems, }) } + +func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggestedBranchName string) error { + message := utils.ResolvePlaceholderString( + self.c.Tr.NewBranchNameBranchOff, + map[string]string{ + "branchName": fromFormattedName, + }, + ) + + return self.c.Prompt(types.PromptOpts{ + Title: message, + InitialContent: suggestedBranchName, + HandleConfirm: func(response string) error { + self.c.LogAction(self.c.Tr.Actions.CreateBranch) + if err := self.git.Branch.New(sanitizedBranchName(response), from); err != nil { + return err + } + + if self.c.CurrentContext() != self.getContexts().Branches { + if err := self.c.PushContext(self.getContexts().Branches); err != nil { + return err + } + } + + self.getContexts().BranchCommits.GetPanelState().SetSelectedLineIdx(0) + self.getContexts().Branches.GetPanelState().SetSelectedLineIdx(0) + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + }, + }) +} diff --git a/pkg/gui/remote_branches_panel.go b/pkg/gui/remote_branches_panel.go index 4164662ba..a611eb5c4 100644 --- a/pkg/gui/remote_branches_panel.go +++ b/pkg/gui/remote_branches_panel.go @@ -2,6 +2,7 @@ package gui import ( "fmt" + "strings" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -118,3 +119,15 @@ func (gui *Gui) handleEnterRemoteBranch() error { return gui.switchToSubCommitsContext(selectedBranch.RefName()) } + +func (gui *Gui) handleNewBranchOffRemoteBranch() error { + selectedBranch := gui.getSelectedRemoteBranch() + if selectedBranch == nil { + return nil + } + + // will set to the remote's branch name without the remote name + nameSuggestion := strings.SplitAfterN(selectedBranch.RefName(), "/", 2)[1] + + return gui.helpers.refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), nameSuggestion) +} diff --git a/pkg/gui/stash_panel.go b/pkg/gui/stash_panel.go index d1c206587..9b7b03bb5 100644 --- a/pkg/gui/stash_panel.go +++ b/pkg/gui/stash_panel.go @@ -136,3 +136,12 @@ func (gui *Gui) handleViewStashFiles() error { WindowName: "stash", }) } + +func (gui *Gui) handleNewBranchOffStashEntry() error { + stashEntry := gui.getSelectedStashEntry() + if stashEntry == nil { + return nil + } + + return gui.helpers.refs.NewBranch(stashEntry.RefName(), stashEntry.Description(), "") +} diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go index 366d55441..40a7f92b7 100644 --- a/pkg/gui/status_panel.go +++ b/pkg/gui/status_panel.go @@ -48,7 +48,7 @@ func (gui *Gui) handleStatusClick() error { case enums.REBASE_MODE_REBASING, enums.REBASE_MODE_MERGING: workingTreeStatus := fmt.Sprintf("(%s)", formatWorkingTreeState(workingTreeState)) if cursorInSubstring(cx, upstreamStatus+" ", workingTreeStatus) { - return gui.handleCreateRebaseOptionsMenu() + return gui.helpers.rebase.CreateRebaseOptionsMenu() } if cursorInSubstring(cx, upstreamStatus+" "+workingTreeStatus+" ", repoName) { return gui.handleCreateRecentReposMenu() diff --git a/pkg/gui/sub_commits_panel.go b/pkg/gui/sub_commits_panel.go index a6fae60c9..5d81d5a9c 100644 --- a/pkg/gui/sub_commits_panel.go +++ b/pkg/gui/sub_commits_panel.go @@ -102,3 +102,31 @@ func (gui *Gui) switchToSubCommitsContext(refName string) error { return gui.c.PushContext(gui.State.Contexts.SubCommits) } + +func (gui *Gui) handleNewBranchOffSubCommit() error { + commit := gui.getSelectedSubCommit() + if commit == nil { + return nil + } + + return gui.helpers.refs.NewBranch(commit.RefName(), commit.Description(), "") +} + +func (gui *Gui) handleCopySubCommit() error { + commit := gui.getSelectedSubCommit() + if commit == nil { + return nil + } + + return gui.helpers.cherryPick.Copy(commit, gui.State.SubCommits, gui.State.Contexts.SubCommits) +} + +func (gui *Gui) handleCopySubCommitRange() error { + // just doing this to ensure something is selected + commit := gui.getSelectedSubCommit() + if commit == nil { + return nil + } + + return gui.helpers.cherryPick.CopyRange(gui.State.Contexts.SubCommits.GetPanelState().GetSelectedLineIdx(), gui.State.SubCommits, gui.State.Contexts.SubCommits) +} diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 9289c4f2d..4dbb0eca3 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -6,8 +6,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/config" ) -// if Go let me do private struct embedding of structs with public fields (which it should) -// I would just do that. But alas. type ControllerCommon struct { *common.Common IGuiCommon diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index ffdcb49a7..fcbadfd22 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -61,8 +61,8 @@ type IController interface { type IListContext interface { HasKeybindings - GetSelectedItem() (ListItem, bool) + GetSelectedItemId() string HandlePrevLine() error HandleNextLine() error HandleScrollLeft() error From c703cd8f88bfac616cf6bc8a5f8eea41363ddfae Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 30 Jan 2022 20:34:59 +1100 Subject: [PATCH 045/385] fix suggestions panel --- pkg/gui/confirmation_panel.go | 8 ++++---- pkg/gui/keybindings.go | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index d136b7d7f..8ed16ea39 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -230,25 +230,25 @@ func (gui *Gui) setKeyBindings(opts types.CreatePopupPanelOpts) error { }, { ViewName: "suggestions", - Contexts: []string{string(context.CONFIRMATION_CONTEXT_KEY)}, + Contexts: []string{string(context.SUGGESTIONS_CONTEXT_KEY)}, Key: gui.getKey(keybindingConfig.Universal.Confirm), Handler: onSuggestionConfirm, }, { ViewName: "suggestions", - Contexts: []string{string(context.CONFIRMATION_CONTEXT_KEY)}, + Contexts: []string{string(context.SUGGESTIONS_CONTEXT_KEY)}, Key: gui.getKey(keybindingConfig.Universal.ConfirmAlt1), Handler: onSuggestionConfirm, }, { ViewName: "suggestions", - Contexts: []string{string(context.CONFIRMATION_CONTEXT_KEY)}, + Contexts: []string{string(context.SUGGESTIONS_CONTEXT_KEY)}, Key: gui.getKey(keybindingConfig.Universal.Return), Handler: gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleClose), }, { ViewName: "suggestions", - Contexts: []string{string(context.CONFIRMATION_CONTEXT_KEY)}, + Contexts: []string{string(context.SUGGESTIONS_CONTEXT_KEY)}, Key: gui.getKey(keybindingConfig.Universal.TogglePanel), Handler: func() error { return gui.replaceContext(gui.State.Contexts.Confirmation) }, }, diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 123e6f5b5..e6ba31923 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -1496,5 +1496,18 @@ func (gui *Gui) SetKeybinding(binding *types.Binding) error { } func isMouseKey(key interface{}) bool { - return key == gocui.MouseLeft || key == gocui.MouseRight || key == gocui.MouseMiddle || key == gocui.MouseRelease || key == gocui.MouseWheelUp || key == gocui.MouseWheelDown || key == gocui.MouseWheelLeft || key == gocui.MouseWheelRight + switch key { + case + gocui.MouseLeft, + gocui.MouseRight, + gocui.MouseMiddle, + gocui.MouseRelease, + gocui.MouseWheelUp, + gocui.MouseWheelDown, + gocui.MouseWheelLeft, + gocui.MouseWheelRight: + return true + default: + return false + } } From eb056576cfe7d97503ef1baf3e1730c87d63976f Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Mon, 31 Jan 2022 19:48:34 +1100 Subject: [PATCH 046/385] fix integration test --- .../expected/.git_keep/COMMIT_EDITMSG | 8 +-- .../expected/.git_keep/ORIG_HEAD | 2 +- .../expected/.git_keep/index | Bin 1734 -> 1734 bytes .../expected/.git_keep/logs/HEAD | 66 +++++++++--------- .../.git_keep/logs/refs/heads/base_branch | 6 +- .../.git_keep/logs/refs/heads/develop | 10 +-- .../logs/refs/heads/feature/cherry-picking | 18 ++--- .../expected/.git_keep/logs/refs/heads/master | 10 +-- .../.git_keep/logs/refs/heads/other_branch | 4 +- .../06/d48b81c12e9c1a3cc2704c0db337639a8cdf85 | Bin 153 -> 0 bytes .../0f/8c9b8f1cac20c63e92e8df34f6d8b3fa74accd | Bin 0 -> 162 bytes .../16/5a3cfaf6a1d3d757fb7b1c509598a395108079 | 2 - .../1f/b30058516518ac1579a8df132b0e4dade8e51d | Bin 155 -> 0 bytes .../20/8e708af0dc73a41a09e79a7198ce56aef3df05 | Bin 381 -> 0 bytes .../21/730e75ee0eec374cc54eb1140d24e03db834fc | 1 + .../34/850e31f804a946d014b14443cf7387546877b0 | Bin 164 -> 0 bytes .../34/d20faa891d1857610dce8f790a35b702ebd7ee | 3 + .../40/844e90419651d425c0845ec6f7c64ff63ebf03 | Bin 157 -> 0 bytes .../41/6ca3083a0651e1c8be3ad7e0dbe8547a62be8a | Bin 121 -> 0 bytes .../41/893d444283aa0c46aa7b5ee01811522cca473d | 3 + .../45/4b176d9e82bc3e0b5d5fd93fa5ad3a58b7db5f | 2 - .../4a/be915d16bbc10f38b578390ff74c9ae62bf503 | Bin 153 -> 0 bytes .../4b/6f90d670c40e5ac78d9c405a5bc40932a0980b | 3 + .../4c/1db169d59c4345aba213cb79934f4e38222f02 | Bin 201 -> 0 bytes .../5e/66799d4a5a3fed89757f3df445a962c9ce2d4f | Bin 0 -> 381 bytes .../66/340a9343a65aec523bfc57bd5a870eb4e05959 | 2 - .../67/b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 | Bin 0 -> 155 bytes .../6c/590c6a21f4e6d335528b5ecf6c52993b914996 | Bin 0 -> 158 bytes .../72/c9bf1e687e81778850d517953c64f03adbaa1b | 2 + .../72/df4fceb0be99deb091ece3f501ef80b39a876a | Bin 0 -> 74 bytes .../79/6a5a2670ccb2d08db89b9cfcaa07e9be5358e6 | 2 + .../85/aba0ff0b6e7c0a7f6180f9f6e7e8cdcb71ee3b | 3 - .../93/d727583328b5ce8f717380d014b87bd7893222 | 3 - .../95/1a2354eb5856644b0f1db74becc04c908beaa3 | Bin 156 -> 0 bytes .../9a/92a03fdc6eb492ea1ac7acf4fdb04962092f81 | Bin 0 -> 160 bytes .../9c/59217622ae74189d18f2992121f97dd28e966b | Bin 158 -> 0 bytes .../a5/1a44d96e13555215619b32065d0a22d95b8476 | 2 + .../a8/3aac98467d005729bc9d80fe98abba47d41495 | Bin 157 -> 0 bytes .../ab/7ecb7891c5f56480fba1ed3a6e0fa8e989efab | 2 - .../ab/daa06b758aa198cc4afb9c406c87c5690d0ca0 | Bin 0 -> 157 bytes .../b2/afb2548f2d143fdd691058f2283b03933a1749 | 4 ++ .../ba/211bf3464f9c0429483a83963c1c69e1f53d4e | Bin 158 -> 0 bytes .../c6/2b5bc94e327ddb9b545213ff77b207ade48aba | Bin 0 -> 148 bytes .../cd/97d8e8ca03000f761f0e041cea0b6039923e70 | Bin 157 -> 0 bytes .../d4/f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 | 5 ++ .../d7/d52ecd690fe82c7d820ddb437e82d78b0fa7b2 | Bin 0 -> 203 bytes .../d8/8617710499a59992caf98d6df1b5f981c58ab1 | 3 + .../dd/401e3ee3d58b648207cee7f737364a37139bea | Bin 0 -> 157 bytes .../f3/7ec566036d715d6995f55dbc82a4fb3cf56f2f | Bin 0 -> 121 bytes .../f4/7cc13dc21c72755ff2d96d0805837dbb028951 | 2 - .../f9/c5f8e0789c2eb9a6e37ba82a5b34be739989ec | Bin 155 -> 0 bytes .../fa/5c5dac095b577173e47b4a0c139525eced009f | 2 + .../expected/.git_keep/refs/heads/base_branch | 2 +- .../expected/.git_keep/refs/heads/develop | 2 +- .../refs/heads/feature/cherry-picking | 2 +- .../expected/.git_keep/refs/heads/master | 2 +- .../.git_keep/refs/heads/other_branch | 2 +- .../expected/directory/file2 | 2 +- .../mergeConflictsFiltered/expected/file1 | 4 +- .../mergeConflictsFiltered/expected/file3 | 2 +- .../mergeConflictsFiltered/expected/file5 | 2 +- .../mergeConflictsFiltered/recording.json | 2 +- .../mergeConflictsFiltered/test.json | 2 +- 63 files changed, 103 insertions(+), 91 deletions(-) delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/06/d48b81c12e9c1a3cc2704c0db337639a8cdf85 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/0f/8c9b8f1cac20c63e92e8df34f6d8b3fa74accd delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/16/5a3cfaf6a1d3d757fb7b1c509598a395108079 delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/1f/b30058516518ac1579a8df132b0e4dade8e51d delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/20/8e708af0dc73a41a09e79a7198ce56aef3df05 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/21/730e75ee0eec374cc54eb1140d24e03db834fc delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/34/850e31f804a946d014b14443cf7387546877b0 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/34/d20faa891d1857610dce8f790a35b702ebd7ee delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/40/844e90419651d425c0845ec6f7c64ff63ebf03 delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/41/6ca3083a0651e1c8be3ad7e0dbe8547a62be8a create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/41/893d444283aa0c46aa7b5ee01811522cca473d delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/45/4b176d9e82bc3e0b5d5fd93fa5ad3a58b7db5f delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4a/be915d16bbc10f38b578390ff74c9ae62bf503 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4b/6f90d670c40e5ac78d9c405a5bc40932a0980b delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4c/1db169d59c4345aba213cb79934f4e38222f02 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/5e/66799d4a5a3fed89757f3df445a962c9ce2d4f delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/66/340a9343a65aec523bfc57bd5a870eb4e05959 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/67/b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/6c/590c6a21f4e6d335528b5ecf6c52993b914996 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/72/c9bf1e687e81778850d517953c64f03adbaa1b create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/72/df4fceb0be99deb091ece3f501ef80b39a876a create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/79/6a5a2670ccb2d08db89b9cfcaa07e9be5358e6 delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/85/aba0ff0b6e7c0a7f6180f9f6e7e8cdcb71ee3b delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/93/d727583328b5ce8f717380d014b87bd7893222 delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/95/1a2354eb5856644b0f1db74becc04c908beaa3 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/9a/92a03fdc6eb492ea1ac7acf4fdb04962092f81 delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/9c/59217622ae74189d18f2992121f97dd28e966b create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/a5/1a44d96e13555215619b32065d0a22d95b8476 delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/a8/3aac98467d005729bc9d80fe98abba47d41495 delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/ab/7ecb7891c5f56480fba1ed3a6e0fa8e989efab create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/ab/daa06b758aa198cc4afb9c406c87c5690d0ca0 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/b2/afb2548f2d143fdd691058f2283b03933a1749 delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/ba/211bf3464f9c0429483a83963c1c69e1f53d4e create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/c6/2b5bc94e327ddb9b545213ff77b207ade48aba delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/cd/97d8e8ca03000f761f0e041cea0b6039923e70 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/d4/f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/d7/d52ecd690fe82c7d820ddb437e82d78b0fa7b2 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/d8/8617710499a59992caf98d6df1b5f981c58ab1 create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/dd/401e3ee3d58b648207cee7f737364a37139bea create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/f3/7ec566036d715d6995f55dbc82a4fb3cf56f2f delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/f4/7cc13dc21c72755ff2d96d0805837dbb028951 delete mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/f9/c5f8e0789c2eb9a6e37ba82a5b34be739989ec create mode 100644 test/integration/mergeConflictsFiltered/expected/.git_keep/objects/fa/5c5dac095b577173e47b4a0c139525eced009f diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/COMMIT_EDITMSG b/test/integration/mergeConflictsFiltered/expected/.git_keep/COMMIT_EDITMSG index 80977d9d1..f08e0d5c6 100644 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/COMMIT_EDITMSG +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/COMMIT_EDITMSG @@ -23,18 +23,16 @@ Merge branch 'develop' into other_branch # Changes to be committed: # new file: cherrypicking1 # new file: cherrypicking2 -# new file: cherrypicking3 # new file: cherrypicking4 # new file: cherrypicking5 +# new file: cherrypicking6 # new file: cherrypicking7 # new file: cherrypicking8 # new file: cherrypicking9 # modified: directory/file -# modified: directory/file2 -# modified: file1 +# modified: file3 # modified: file4 -# modified: file5 # # Untracked files: -# cherrypicking6 +# cherrypicking3 # diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/ORIG_HEAD b/test/integration/mergeConflictsFiltered/expected/.git_keep/ORIG_HEAD index 84de0034b..c71cd262c 100644 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/ORIG_HEAD +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/ORIG_HEAD @@ -1 +1 @@ -ab7ecb7891c5f56480fba1ed3a6e0fa8e989efab +c62b5bc94e327ddb9b545213ff77b207ade48aba diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/index b/test/integration/mergeConflictsFiltered/expected/.git_keep/index index f455a20fa101c0b36c9902e54b9d2775029fbe06..bf18bbf792e3d66f1dd3646dee53bdb2be63084a 100644 GIT binary patch delta 724 zcmX@cdyH4b#WTp6fq{Vui1`!0FB0Rt#$pDe85tN@nT*+PPgJoK2T9%Bzz3EB(om^8 z6H6dc_b2IqrGPY4>fU4#Mu^;_Ru8ZokcP_LpPa&ISr0PuY0*Nk9FT^}Jz!vHT*AP> z_!a0P5g;~^_>#G&xIRZKViN14yYJ6!)~Y$YoPjSnBekfgvLG`#J2Nlc45*F)Y|e}L zpD-F~-a~Zro_MT_{$?)QF!>ClBG_B6!{xzxfHYLkqsc5x5VyZ`g_sAVp>mHWhk)gj zg{}991NDJvsNC1dOPE0Z61Pm+?+ug#(@?oDXzpOUpUta%rtH}p{! kb9>$!>7g$A97+6788G^zP6o``SA(5b@0H&cDUrm-_(ULQUDN)rC zo2CR*0;Zu#UILXE0>e{HnaznCC Ppd8Ghb+%E-XL%B0!;W}=FvI8ccB)G8^k zl4SkKP^q^QODyYwQml4&CxE1wFZo@8O1)!XXk5a;!1xttvIr2Hyq@sl`bP7GH>Nb4 z+@ycOaOSP@lgAnOk~30^iYf~-le07P(v5-Y7(nK*ZB57k(X6gNRzS^rk8a);AvxWw zg<(n)? 3s4uQz=TW^^OlH >~ z1xQXv> FD#Sj#{;@1S8gXF~O&hbIz{sQH+ zyiCD1gao;|0vR?8hNcRJTnc>!T_5fgFOlMWKC5uXxv+Jg@3X>v&S0cqz%}=U8h3G* u$#PfY`yrp6u&8IPOmf Z$nk}{>L&lqGrSS-agXys{*v3NB>@0V 1643188552 +1100 commit (initial): first commit -416ca3083a0651e1c8be3ad7e0dbe8547a62be8a 416ca3083a0651e1c8be3ad7e0dbe8547a62be8a CI 1643188552 +1100 checkout: moving from master to feature/cherry-picking -416ca3083a0651e1c8be3ad7e0dbe8547a62be8a f47cc13dc21c72755ff2d96d0805837dbb028951 CI 1643188552 +1100 commit: first commit freshman year -f47cc13dc21c72755ff2d96d0805837dbb028951 34850e31f804a946d014b14443cf7387546877b0 CI 1643188552 +1100 commit: second commit subway eat fresh -34850e31f804a946d014b14443cf7387546877b0 66340a9343a65aec523bfc57bd5a870eb4e05959 CI 1643188552 +1100 commit: third commit fresh -66340a9343a65aec523bfc57bd5a870eb4e05959 f9c5f8e0789c2eb9a6e37ba82a5b34be739989ec CI 1643188552 +1100 commit: fourth commit cool -f9c5f8e0789c2eb9a6e37ba82a5b34be739989ec 4abe915d16bbc10f38b578390ff74c9ae62bf503 CI 1643188552 +1100 commit: fifth commit nice -4abe915d16bbc10f38b578390ff74c9ae62bf503 93d727583328b5ce8f717380d014b87bd7893222 CI 1643188552 +1100 commit: sixth commit haha -93d727583328b5ce8f717380d014b87bd7893222 951a2354eb5856644b0f1db74becc04c908beaa3 CI 1643188552 +1100 commit: seventh commit yeah -951a2354eb5856644b0f1db74becc04c908beaa3 1fb30058516518ac1579a8df132b0e4dade8e51d CI 1643188552 +1100 commit: eighth commit woo -1fb30058516518ac1579a8df132b0e4dade8e51d 1fb30058516518ac1579a8df132b0e4dade8e51d CI 1643188552 +1100 checkout: moving from feature/cherry-picking to develop -1fb30058516518ac1579a8df132b0e4dade8e51d 40844e90419651d425c0845ec6f7c64ff63ebf03 CI 1643188552 +1100 commit: first commit on develop -40844e90419651d425c0845ec6f7c64ff63ebf03 416ca3083a0651e1c8be3ad7e0dbe8547a62be8a CI 1643188552 +1100 checkout: moving from develop to master -416ca3083a0651e1c8be3ad7e0dbe8547a62be8a 165a3cfaf6a1d3d757fb7b1c509598a395108079 CI 1643188552 +1100 commit: first commit on master -165a3cfaf6a1d3d757fb7b1c509598a395108079 40844e90419651d425c0845ec6f7c64ff63ebf03 CI 1643188552 +1100 checkout: moving from master to develop -40844e90419651d425c0845ec6f7c64ff63ebf03 9c59217622ae74189d18f2992121f97dd28e966b CI 1643188552 +1100 commit: second commit on develop -9c59217622ae74189d18f2992121f97dd28e966b 165a3cfaf6a1d3d757fb7b1c509598a395108079 CI 1643188552 +1100 checkout: moving from develop to master -165a3cfaf6a1d3d757fb7b1c509598a395108079 454b176d9e82bc3e0b5d5fd93fa5ad3a58b7db5f CI 1643188552 +1100 commit: second commit on master -454b176d9e82bc3e0b5d5fd93fa5ad3a58b7db5f 9c59217622ae74189d18f2992121f97dd28e966b CI 1643188552 +1100 checkout: moving from master to develop -9c59217622ae74189d18f2992121f97dd28e966b ba211bf3464f9c0429483a83963c1c69e1f53d4e CI 1643188552 +1100 commit: third commit on develop -ba211bf3464f9c0429483a83963c1c69e1f53d4e 454b176d9e82bc3e0b5d5fd93fa5ad3a58b7db5f CI 1643188552 +1100 checkout: moving from develop to master -454b176d9e82bc3e0b5d5fd93fa5ad3a58b7db5f a83aac98467d005729bc9d80fe98abba47d41495 CI 1643188552 +1100 commit: third commit on master -a83aac98467d005729bc9d80fe98abba47d41495 ba211bf3464f9c0429483a83963c1c69e1f53d4e CI 1643188552 +1100 checkout: moving from master to develop -ba211bf3464f9c0429483a83963c1c69e1f53d4e 85aba0ff0b6e7c0a7f6180f9f6e7e8cdcb71ee3b CI 1643188552 +1100 commit: fourth commit on develop -85aba0ff0b6e7c0a7f6180f9f6e7e8cdcb71ee3b a83aac98467d005729bc9d80fe98abba47d41495 CI 1643188552 +1100 checkout: moving from develop to master -a83aac98467d005729bc9d80fe98abba47d41495 cd97d8e8ca03000f761f0e041cea0b6039923e70 CI 1643188552 +1100 commit: fourth commit on master -cd97d8e8ca03000f761f0e041cea0b6039923e70 cd97d8e8ca03000f761f0e041cea0b6039923e70 CI 1643188552 +1100 checkout: moving from master to base_branch -cd97d8e8ca03000f761f0e041cea0b6039923e70 ab7ecb7891c5f56480fba1ed3a6e0fa8e989efab CI 1643188552 +1100 commit: file -ab7ecb7891c5f56480fba1ed3a6e0fa8e989efab ab7ecb7891c5f56480fba1ed3a6e0fa8e989efab CI 1643188552 +1100 checkout: moving from base_branch to other_branch -ab7ecb7891c5f56480fba1ed3a6e0fa8e989efab ab7ecb7891c5f56480fba1ed3a6e0fa8e989efab CI 1643188552 +1100 checkout: moving from other_branch to base_branch -ab7ecb7891c5f56480fba1ed3a6e0fa8e989efab 06d48b81c12e9c1a3cc2704c0db337639a8cdf85 CI 1643188552 +1100 commit: file changed -06d48b81c12e9c1a3cc2704c0db337639a8cdf85 ab7ecb7891c5f56480fba1ed3a6e0fa8e989efab CI 1643188552 +1100 checkout: moving from base_branch to other_branch -ab7ecb7891c5f56480fba1ed3a6e0fa8e989efab 4c1db169d59c4345aba213cb79934f4e38222f02 CI 1643188579 +1100 commit (merge): Merge branch 'develop' into other_branch +0000000000000000000000000000000000000000 f37ec566036d715d6995f55dbc82a4fb3cf56f2f CI 1643618835 +1100 commit (initial): first commit +f37ec566036d715d6995f55dbc82a4fb3cf56f2f f37ec566036d715d6995f55dbc82a4fb3cf56f2f CI 1643618835 +1100 checkout: moving from master to feature/cherry-picking +f37ec566036d715d6995f55dbc82a4fb3cf56f2f 21730e75ee0eec374cc54eb1140d24e03db834fc CI 1643618835 +1100 commit: first commit freshman year +21730e75ee0eec374cc54eb1140d24e03db834fc 0f8c9b8f1cac20c63e92e8df34f6d8b3fa74accd CI 1643618835 +1100 commit: second commit subway eat fresh +0f8c9b8f1cac20c63e92e8df34f6d8b3fa74accd 72c9bf1e687e81778850d517953c64f03adbaa1b CI 1643618835 +1100 commit: third commit fresh +72c9bf1e687e81778850d517953c64f03adbaa1b 67b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 CI 1643618835 +1100 commit: fourth commit cool +67b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 4b6f90d670c40e5ac78d9c405a5bc40932a0980b CI 1643618835 +1100 commit: fifth commit nice +4b6f90d670c40e5ac78d9c405a5bc40932a0980b 796a5a2670ccb2d08db89b9cfcaa07e9be5358e6 CI 1643618835 +1100 commit: sixth commit haha +796a5a2670ccb2d08db89b9cfcaa07e9be5358e6 41893d444283aa0c46aa7b5ee01811522cca473d CI 1643618835 +1100 commit: seventh commit yeah +41893d444283aa0c46aa7b5ee01811522cca473d d88617710499a59992caf98d6df1b5f981c58ab1 CI 1643618835 +1100 commit: eighth commit woo +d88617710499a59992caf98d6df1b5f981c58ab1 d88617710499a59992caf98d6df1b5f981c58ab1 CI 1643618835 +1100 checkout: moving from feature/cherry-picking to develop +d88617710499a59992caf98d6df1b5f981c58ab1 fa5c5dac095b577173e47b4a0c139525eced009f CI 1643618835 +1100 commit: first commit on develop +fa5c5dac095b577173e47b4a0c139525eced009f f37ec566036d715d6995f55dbc82a4fb3cf56f2f CI 1643618835 +1100 checkout: moving from develop to master +f37ec566036d715d6995f55dbc82a4fb3cf56f2f abdaa06b758aa198cc4afb9c406c87c5690d0ca0 CI 1643618835 +1100 commit: first commit on master +abdaa06b758aa198cc4afb9c406c87c5690d0ca0 fa5c5dac095b577173e47b4a0c139525eced009f CI 1643618835 +1100 checkout: moving from master to develop +fa5c5dac095b577173e47b4a0c139525eced009f 6c590c6a21f4e6d335528b5ecf6c52993b914996 CI 1643618835 +1100 commit: second commit on develop +6c590c6a21f4e6d335528b5ecf6c52993b914996 abdaa06b758aa198cc4afb9c406c87c5690d0ca0 CI 1643618835 +1100 checkout: moving from develop to master +abdaa06b758aa198cc4afb9c406c87c5690d0ca0 dd401e3ee3d58b648207cee7f737364a37139bea CI 1643618835 +1100 commit: second commit on master +dd401e3ee3d58b648207cee7f737364a37139bea 6c590c6a21f4e6d335528b5ecf6c52993b914996 CI 1643618835 +1100 checkout: moving from master to develop +6c590c6a21f4e6d335528b5ecf6c52993b914996 b2afb2548f2d143fdd691058f2283b03933a1749 CI 1643618835 +1100 commit: third commit on develop +b2afb2548f2d143fdd691058f2283b03933a1749 dd401e3ee3d58b648207cee7f737364a37139bea CI 1643618835 +1100 checkout: moving from develop to master +dd401e3ee3d58b648207cee7f737364a37139bea 34d20faa891d1857610dce8f790a35b702ebd7ee CI 1643618835 +1100 commit: third commit on master +34d20faa891d1857610dce8f790a35b702ebd7ee b2afb2548f2d143fdd691058f2283b03933a1749 CI 1643618835 +1100 checkout: moving from master to develop +b2afb2548f2d143fdd691058f2283b03933a1749 9a92a03fdc6eb492ea1ac7acf4fdb04962092f81 CI 1643618835 +1100 commit: fourth commit on develop +9a92a03fdc6eb492ea1ac7acf4fdb04962092f81 34d20faa891d1857610dce8f790a35b702ebd7ee CI 1643618835 +1100 checkout: moving from develop to master +34d20faa891d1857610dce8f790a35b702ebd7ee d4f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 CI 1643618835 +1100 commit: fourth commit on master +d4f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 d4f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 CI 1643618835 +1100 checkout: moving from master to base_branch +d4f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 c62b5bc94e327ddb9b545213ff77b207ade48aba CI 1643618835 +1100 commit: file +c62b5bc94e327ddb9b545213ff77b207ade48aba c62b5bc94e327ddb9b545213ff77b207ade48aba CI 1643618835 +1100 checkout: moving from base_branch to other_branch +c62b5bc94e327ddb9b545213ff77b207ade48aba c62b5bc94e327ddb9b545213ff77b207ade48aba CI 1643618835 +1100 checkout: moving from other_branch to base_branch +c62b5bc94e327ddb9b545213ff77b207ade48aba a51a44d96e13555215619b32065d0a22d95b8476 CI 1643618835 +1100 commit: file changed +a51a44d96e13555215619b32065d0a22d95b8476 c62b5bc94e327ddb9b545213ff77b207ade48aba CI 1643618835 +1100 checkout: moving from base_branch to other_branch +c62b5bc94e327ddb9b545213ff77b207ade48aba d7d52ecd690fe82c7d820ddb437e82d78b0fa7b2 CI 1643618855 +1100 commit (merge): Merge branch 'develop' into other_branch diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/base_branch b/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/base_branch index 1d7992ef4..9b14238c0 100644 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/base_branch +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/base_branch @@ -1,3 +1,3 @@ -0000000000000000000000000000000000000000 cd97d8e8ca03000f761f0e041cea0b6039923e70 CI 1643188552 +1100 branch: Created from HEAD -cd97d8e8ca03000f761f0e041cea0b6039923e70 ab7ecb7891c5f56480fba1ed3a6e0fa8e989efab CI 1643188552 +1100 commit: file -ab7ecb7891c5f56480fba1ed3a6e0fa8e989efab 06d48b81c12e9c1a3cc2704c0db337639a8cdf85 CI 1643188552 +1100 commit: file changed +0000000000000000000000000000000000000000 d4f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 CI 1643618835 +1100 branch: Created from HEAD +d4f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 c62b5bc94e327ddb9b545213ff77b207ade48aba CI 1643618835 +1100 commit: file +c62b5bc94e327ddb9b545213ff77b207ade48aba a51a44d96e13555215619b32065d0a22d95b8476 CI 1643618835 +1100 commit: file changed diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/develop b/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/develop index 52fde82d1..59e1aede7 100644 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/develop +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/develop @@ -1,5 +1,5 @@ -0000000000000000000000000000000000000000 1fb30058516518ac1579a8df132b0e4dade8e51d CI 1643188552 +1100 branch: Created from HEAD -1fb30058516518ac1579a8df132b0e4dade8e51d 40844e90419651d425c0845ec6f7c64ff63ebf03 CI 1643188552 +1100 commit: first commit on develop -40844e90419651d425c0845ec6f7c64ff63ebf03 9c59217622ae74189d18f2992121f97dd28e966b CI 1643188552 +1100 commit: second commit on develop -9c59217622ae74189d18f2992121f97dd28e966b ba211bf3464f9c0429483a83963c1c69e1f53d4e CI 1643188552 +1100 commit: third commit on develop -ba211bf3464f9c0429483a83963c1c69e1f53d4e 85aba0ff0b6e7c0a7f6180f9f6e7e8cdcb71ee3b CI 1643188552 +1100 commit: fourth commit on develop +0000000000000000000000000000000000000000 d88617710499a59992caf98d6df1b5f981c58ab1 CI 1643618835 +1100 branch: Created from HEAD +d88617710499a59992caf98d6df1b5f981c58ab1 fa5c5dac095b577173e47b4a0c139525eced009f CI 1643618835 +1100 commit: first commit on develop +fa5c5dac095b577173e47b4a0c139525eced009f 6c590c6a21f4e6d335528b5ecf6c52993b914996 CI 1643618835 +1100 commit: second commit on develop +6c590c6a21f4e6d335528b5ecf6c52993b914996 b2afb2548f2d143fdd691058f2283b03933a1749 CI 1643618835 +1100 commit: third commit on develop +b2afb2548f2d143fdd691058f2283b03933a1749 9a92a03fdc6eb492ea1ac7acf4fdb04962092f81 CI 1643618835 +1100 commit: fourth commit on develop diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/feature/cherry-picking b/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/feature/cherry-picking index a77478ee9..752d03eb6 100644 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/feature/cherry-picking +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/feature/cherry-picking @@ -1,9 +1,9 @@ -0000000000000000000000000000000000000000 416ca3083a0651e1c8be3ad7e0dbe8547a62be8a CI 1643188552 +1100 branch: Created from HEAD -416ca3083a0651e1c8be3ad7e0dbe8547a62be8a f47cc13dc21c72755ff2d96d0805837dbb028951 CI 1643188552 +1100 commit: first commit freshman year -f47cc13dc21c72755ff2d96d0805837dbb028951 34850e31f804a946d014b14443cf7387546877b0 CI 1643188552 +1100 commit: second commit subway eat fresh -34850e31f804a946d014b14443cf7387546877b0 66340a9343a65aec523bfc57bd5a870eb4e05959 CI 1643188552 +1100 commit: third commit fresh -66340a9343a65aec523bfc57bd5a870eb4e05959 f9c5f8e0789c2eb9a6e37ba82a5b34be739989ec CI 1643188552 +1100 commit: fourth commit cool -f9c5f8e0789c2eb9a6e37ba82a5b34be739989ec 4abe915d16bbc10f38b578390ff74c9ae62bf503 CI 1643188552 +1100 commit: fifth commit nice -4abe915d16bbc10f38b578390ff74c9ae62bf503 93d727583328b5ce8f717380d014b87bd7893222 CI 1643188552 +1100 commit: sixth commit haha -93d727583328b5ce8f717380d014b87bd7893222 951a2354eb5856644b0f1db74becc04c908beaa3 CI 1643188552 +1100 commit: seventh commit yeah -951a2354eb5856644b0f1db74becc04c908beaa3 1fb30058516518ac1579a8df132b0e4dade8e51d CI 1643188552 +1100 commit: eighth commit woo +0000000000000000000000000000000000000000 f37ec566036d715d6995f55dbc82a4fb3cf56f2f CI 1643618835 +1100 branch: Created from HEAD +f37ec566036d715d6995f55dbc82a4fb3cf56f2f 21730e75ee0eec374cc54eb1140d24e03db834fc CI 1643618835 +1100 commit: first commit freshman year +21730e75ee0eec374cc54eb1140d24e03db834fc 0f8c9b8f1cac20c63e92e8df34f6d8b3fa74accd CI 1643618835 +1100 commit: second commit subway eat fresh +0f8c9b8f1cac20c63e92e8df34f6d8b3fa74accd 72c9bf1e687e81778850d517953c64f03adbaa1b CI 1643618835 +1100 commit: third commit fresh +72c9bf1e687e81778850d517953c64f03adbaa1b 67b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 CI 1643618835 +1100 commit: fourth commit cool +67b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 4b6f90d670c40e5ac78d9c405a5bc40932a0980b CI 1643618835 +1100 commit: fifth commit nice +4b6f90d670c40e5ac78d9c405a5bc40932a0980b 796a5a2670ccb2d08db89b9cfcaa07e9be5358e6 CI 1643618835 +1100 commit: sixth commit haha +796a5a2670ccb2d08db89b9cfcaa07e9be5358e6 41893d444283aa0c46aa7b5ee01811522cca473d CI 1643618835 +1100 commit: seventh commit yeah +41893d444283aa0c46aa7b5ee01811522cca473d d88617710499a59992caf98d6df1b5f981c58ab1 CI 1643618835 +1100 commit: eighth commit woo diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/master b/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/master index 7f0b5ea9c..d27b9c51b 100644 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/master +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/master @@ -1,5 +1,5 @@ -0000000000000000000000000000000000000000 416ca3083a0651e1c8be3ad7e0dbe8547a62be8a CI 1643188552 +1100 commit (initial): first commit -416ca3083a0651e1c8be3ad7e0dbe8547a62be8a 165a3cfaf6a1d3d757fb7b1c509598a395108079 CI 1643188552 +1100 commit: first commit on master -165a3cfaf6a1d3d757fb7b1c509598a395108079 454b176d9e82bc3e0b5d5fd93fa5ad3a58b7db5f CI 1643188552 +1100 commit: second commit on master -454b176d9e82bc3e0b5d5fd93fa5ad3a58b7db5f a83aac98467d005729bc9d80fe98abba47d41495 CI 1643188552 +1100 commit: third commit on master -a83aac98467d005729bc9d80fe98abba47d41495 cd97d8e8ca03000f761f0e041cea0b6039923e70 CI 1643188552 +1100 commit: fourth commit on master +0000000000000000000000000000000000000000 f37ec566036d715d6995f55dbc82a4fb3cf56f2f CI 1643618835 +1100 commit (initial): first commit +f37ec566036d715d6995f55dbc82a4fb3cf56f2f abdaa06b758aa198cc4afb9c406c87c5690d0ca0 CI 1643618835 +1100 commit: first commit on master +abdaa06b758aa198cc4afb9c406c87c5690d0ca0 dd401e3ee3d58b648207cee7f737364a37139bea CI 1643618835 +1100 commit: second commit on master +dd401e3ee3d58b648207cee7f737364a37139bea 34d20faa891d1857610dce8f790a35b702ebd7ee CI 1643618835 +1100 commit: third commit on master +34d20faa891d1857610dce8f790a35b702ebd7ee d4f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 CI 1643618835 +1100 commit: fourth commit on master diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/other_branch b/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/other_branch index 2534238d7..5842c42d8 100644 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/other_branch +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/other_branch @@ -1,2 +1,2 @@ -0000000000000000000000000000000000000000 ab7ecb7891c5f56480fba1ed3a6e0fa8e989efab CI 1643188552 +1100 branch: Created from HEAD -ab7ecb7891c5f56480fba1ed3a6e0fa8e989efab 4c1db169d59c4345aba213cb79934f4e38222f02 CI 1643188579 +1100 commit (merge): Merge branch 'develop' into other_branch +0000000000000000000000000000000000000000 c62b5bc94e327ddb9b545213ff77b207ade48aba CI 1643618835 +1100 branch: Created from HEAD +c62b5bc94e327ddb9b545213ff77b207ade48aba d7d52ecd690fe82c7d820ddb437e82d78b0fa7b2 CI 1643618855 +1100 commit (merge): Merge branch 'develop' into other_branch diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/06/d48b81c12e9c1a3cc2704c0db337639a8cdf85 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/06/d48b81c12e9c1a3cc2704c0db337639a8cdf85 deleted file mode 100644 index 984eeda3bf3a66bbb65f544bcabb658b368e9008..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 153 zcmV;K0A~Mq0gcX03c@fDhGEw^MfQSZ+N6_!h|pD!F`0g`1^YvZ;PLGd+`c@ESGQ%E ztEH4K^#E)k-zgW)kv(%%lF?~Nf(##^jc-_aL}PY2uvROXp_yYM4JC9wx{`%3w$i~B ziAXV_NH+4R({|W?u=jp=;w#Jk#!a{7VX5;i#TY_kuSCw7vz}8Ge{xgiH>^&wzA%~} H{Q*7dWC}}= diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/0f/8c9b8f1cac20c63e92e8df34f6d8b3fa74accd b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/0f/8c9b8f1cac20c63e92e8df34f6d8b3fa74accd new file mode 100644 index 0000000000000000000000000000000000000000..aa6525a94e0f7b834fdfe0093eff304e7cbdac20 GIT binary patch literal 162 zcmV;T0A2rh0gaBq3c@fD1wH30_AbaK*)$1=2%h|mbn}XWwbDk^zgP4Jybd!kI*sGG zk+X5tW`Jyzk~E8m4ka>o$<-(va?L}@JwlZ1#HqQJ8P{*<88HA1sE?u=1iiJw)d|?w zK6x3`lzTf(GaZh!JskIVmhpDMMyGK{wiDmklzgDIwan&2KT{2V>SlpX*Gj*PmV5sw QFG6WF%vet54J?>KpQ4veD*ylh literal 0 HcmV?d00001 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/16/5a3cfaf6a1d3d757fb7b1c509598a395108079 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/16/5a3cfaf6a1d3d757fb7b1c509598a395108079 deleted file mode 100644 index 56bdc0b18..000000000 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/16/5a3cfaf6a1d3d757fb7b1c509598a395108079 +++ /dev/null @@ -1,2 +0,0 @@ -x崕M -0F]$射g"BW=4漙霖褾瘌紑粡莧疱抵臻詖霹D湆-$蠋E噿bB嚈lA雕.蝿台 Yo膁y帰鏘然攘隽娺肀0宲苹|竛O逛缔噯葅gc碫濚SMUY觯怜傰晱/+? \ No newline at end of file diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/1f/b30058516518ac1579a8df132b0e4dade8e51d b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/1f/b30058516518ac1579a8df132b0e4dade8e51d deleted file mode 100644 index 82cc46d1c332e183565fc440e79b42b0c2c43b29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 155 zcmV;M0A&Ao0gaA93c@fD06pgwdlw{|>~0ef5qjz~l5}eYYf6de^DX!Rufq&XsmpS2 z;4B^5rV3r~A~GtalCyIu>QtO%jGag~F?vA^g~_aG(`SRon4D+Q%z;ISvYl|u9c3-W zQi(QXP05?|YIEJ7AK=^%SN)`Aedwvw x4F&m%ivwB J`2yc>J-avrOa1@= diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/20/8e708af0dc73a41a09e79a7198ce56aef3df05 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/20/8e708af0dc73a41a09e79a7198ce56aef3df05 deleted file mode 100644 index 01e88b75d5a2d92a5b6d5d961c9207675fcb3d5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 381 zcmV-@0fPQ`0V^p=O;s>8He)a}FfcPQQAo~6Eh?%k$V|@8%u6?9NMw9z>L%-RBWayi z5r^B0iiV3bc4AX$#LzLD|NhfY>uhU3v*lYKeAxJ_P^TB0N@IrC6JA{3Xuj~ql!lX= z^e-6Byj6bkI5w3g3|oZcbh8$QDOIOBI?LYQ5$VaYRRNnyQ-<}+(?d=gtIe&s5@xVm z!b_oL?!GzLRGKq9@mLrA&0MzO^*fbC+PR+{E2~lkv8l9Rn6SeCntp>ZQ~heYu&TzZ zZ?&=t&tg+)$)L31Z$s_XCmM%tNUZy|$WXRM@I|YM0T3vpWEQ0+m*f{!GR%FU#$DWH zvfS19e#oaMEb3V+lboQYrDf)%GQ=*qslXB*qT3$- 4H^6!-tbg& zzIz?P%Og3Zr2K&Pi5^uX1;z}I*Tv+vu)i> 肉殭蹊s錯蓶s-:IVf驿{\鯪隖;%韖莽铐<~瀋铵山閧j酂撼k:灄&w鷣t銪C \ No newline at end of file diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/34/850e31f804a946d014b14443cf7387546877b0 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/34/850e31f804a946d014b14443cf7387546877b0 deleted file mode 100644 index 5d4a913e6253decff32e3741ab4e1545bc1f6b4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 164 zcmV;V09*ff0gaA93c@fD06pgwdlw|T-E fbhAOhT4^Kd?=AQNufq(CPUCoO zKq#9wn*j>vsEL`iX7Rp{RD^v v<7PXZ#sgr_9mW^}!4}bbx6*a0*`K;wOs9K+Uk1x_ Sc;ydRUhigGF76BT<3b~@I85*W diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/34/d20faa891d1857610dce8f790a35b702ebd7ee b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/34/d20faa891d1857610dce8f790a35b702ebd7ee new file mode 100644 index 000000000..d729e28f3 --- /dev/null +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/34/d20faa891d1857610dce8f790a35b702ebd7ee @@ -0,0 +1,3 @@ +x嵨A +0卆9澎蓆ιD劗z宨3cK屶-x窂7m9邼j1h[OIbd貉8碧蔅:籡=+つ嵦(2柶巧,螒"V奌嘦э簂p窂纨a梚7览P刏8#z飵8U硐苷e- ~ +'d}貆午?+ \ No newline at end of file diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/40/844e90419651d425c0845ec6f7c64ff63ebf03 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/40/844e90419651d425c0845ec6f7c64ff63ebf03 deleted file mode 100644 index cca824fa4253ed75c93175bfb22ebdbd4857924a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmV;O0Al}m0gaA93c@fD06pgwdlzIk$tDp*gr540G}&OGH6=#z`4;?u*I@=G)peaa zXu?BpBA~4+-Ucri#2JGrO_D6K5syTcGn?XUwrYz_9v!Gm29X1kV+t`5`*RGrkkJ#0 z%`r<5rmW(t-)n ~E;c{Jgt ? \ No newline at end of file diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4a/be915d16bbc10f38b578390ff74c9ae62bf503 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4a/be915d16bbc10f38b578390ff74c9ae62bf503 deleted file mode 100644 index 8854dbe4ef85613892f103fec18cf2ed390702fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 153 zcmV;K0A~Mq0gaAJ3c@fL23_YA|6Y*1A0Q%h)ng=oztDndONrp|EqDR9!wd{>tu39j zw3mJWWIQCQfz#}v6TD4Pa!?a$$;C@=Cq3oJV$TQGPBpQs5i-QY8YN{96H1OcyJBoX zFe$|Z7Wv)h?Vw?#`!GK7$!&k(##?)k^46#rozrwxN=k9kbE@M{UDT!anSK?m3qyPX H*OEUM#T`e? diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4b/6f90d670c40e5ac78d9c405a5bc40932a0980b b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4b/6f90d670c40e5ac78d9c405a5bc40932a0980b new file mode 100644 index 000000000..b238d04ca --- /dev/null +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4b/6f90d670c40e5ac78d9c405a5bc40932a0980b @@ -0,0 +1,3 @@ +x崕] +0})鯹慄uMAD鑃彵質kK夃-x_]梕n鋗<犂皑漌嗭帘OV爁蒷9_$┵d谦_$皋篓氃q闐JI鄴>俏然M隢肏穉|#琐腅族N巆`桼梃鞙垫犌T脽憨sm*z +!? \ No newline at end of file diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4c/1db169d59c4345aba213cb79934f4e38222f02 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4c/1db169d59c4345aba213cb79934f4e38222f02 deleted file mode 100644 index 5e63d0027841f9808d6162a8511b0e379e3badc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 201 zcmV;)05<=40gaEbYQ!)QL{s}Kw!0z_R%c6EK?s4XuE;lpl{_0CoGl}ikk5}Hq)$0B zZw98+b-i^uNB__pKxY<27B!wr9CdQa2{CDONeX;W*f<;eVb_MOljew$qa;_n`7jAv zR)=}i05%mQNifZSym-yZW}E|JVT~5t(MfhlNSTi<2aI{p&%V?~mn%JAuCMskb-&}O z)b)j2m_{e!W1>grn1{nXPIUYeAKuVDK)LBw7CO!N!oBV%x^2Bu?F-ubZ#Mh@0YX-j D!%8He)a}FfcPQQAo~6Eh?%k$V|@8%u6?9NMw9z>L%-RBWayi z5r^B0iiV3bc4AX$#LzLD|NhfY>uhU3v*lYKeAxJ_P^TB0N)v`HLUOuU3&WJEQyraU z@9&88WZ9~KO{FQr`sL{%CymwS)?5iQST5nE&@y-59BeAh7$m-A?kTR%(TbSF`snWa zbDOnl4ll>1(wyOm$GYfm=CTd1->EFp&i(9IS(Pe?O{E3HgcbhR^c#$s>Q~!^RW)9H ztCdxF7Mn^-2Bi&u8)~mU(KvKNV%@hzhO#w+FIr6ufIuN7vnVyWB)_PVq3FK ux}jH)ObT*(0EO z;jR9Z%AGe;ZY^fo^m{HWFhB+vGf2;R`t|-d!(FQ+xD3|coMGR5NBtC%2_}RTm@+(G b7n9q<{=%So_VG&PeHAAe9s2VC7!%%Z%iX|5 literal 0 HcmV?d00001 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/66/340a9343a65aec523bfc57bd5a870eb4e05959 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/66/340a9343a65aec523bfc57bd5a870eb4e05959 deleted file mode 100644 index e319e7eda..000000000 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/66/340a9343a65aec523bfc57bd5a870eb4e05959 +++ /dev/null @@ -1,2 +0,0 @@ -x崕K -0@]d扡>~#橪i霖#x|^理=x颊簐0鐽綁@)懊)撋&{#嶤嗦骡 ;x蕝詾<;X抨9"|AMY戝9BF曓}\情.烼鲊\x7袨瑤9g誂彥.戟/k+皤`n騔jc> \ No newline at end of file diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/67/b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/67/b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 new file mode 100644 index 0000000000000000000000000000000000000000..8bd1d7993303f7ab78fc761873be35e29186bf6a GIT binary patch literal 155 zcmV;M0A&Ao0gaAJ3IZ_@L|x|;*$a}+w*w-=tmYV N4dthafOI$JRPuR(@aBXZ}z<_I!)2J~&vdEFdbwuK+@@N$07N|E#mp&OSE&(`K}t JeF3;4KJRU5L}CB{ literal 0 HcmV?d00001 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/6c/590c6a21f4e6d335528b5ecf6c52993b914996 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/6c/590c6a21f4e6d335528b5ecf6c52993b914996 new file mode 100644 index 0000000000000000000000000000000000000000..5400b19fc593885d37c76b4c14a2725f224979b4 GIT binary patch literal 158 zcmV;P0Ac@l0gaA93c@fD06pgwdlzK4n=~ni2tE0XWOs{#ZAy*e^A-Gn*I@=m>O9{X zbVR$hnZcw?VmTU?-jXu=E@3hDT9Rt&MKv>GbZg#hX)xs=L9^fxN{Epnn~%k36yhOt z!Ne4Cm|T9gYu#YHz;V2s?VacKZU?FJ38?qnQ%W3QPlV{c^gGq;Pu)FC>Z0(=pe~^H MvU^?K2a%XTo6+@8CjbBd literal 0 HcmV?d00001 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/72/c9bf1e687e81778850d517953c64f03adbaa1b b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/72/c9bf1e687e81778850d517953c64f03adbaa1b new file mode 100644 index 000000000..8a19f046d --- /dev/null +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/72/c9bf1e687e81778850d517953c64f03adbaa1b @@ -0,0 +1,2 @@ +x崕K +0@]$ "t誧Lf&碻m</圉<谥u閌u8&1Q蠰X-禗+丷"&!塚/煺嶮t4擻 !YM焉`%su綟闻UL塜峄蟍僸傠8蒎冸m L.殰]1Z珒S]U煑起珷6y完@ \ No newline at end of file diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/72/df4fceb0be99deb091ece3f501ef80b39a876a b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/72/df4fceb0be99deb091ece3f501ef80b39a876a new file mode 100644 index 0000000000000000000000000000000000000000..19670ff5ad0dd0dd6e4a8ec0e9f87b3722326911 GIT binary patch literal 74 zcmV-Q0JZ;k0V^p=O;s>6WiT`_Ff%bxNXyJgWsu 梞族枞Ⅶ]g鄪ǖ:珍瞎*踟? -Y2譓}O艫7 \ No newline at end of file diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/93/d727583328b5ce8f717380d014b87bd7893222 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/93/d727583328b5ce8f717380d014b87bd7893222 deleted file mode 100644 index 4eb870a9e..000000000 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/93/d727583328b5ce8f717380d014b87bd7893222 +++ /dev/null @@ -1,3 +0,0 @@ -x崕K -0@]$擄D劗z孖:!偙桉-x窂鬣濂礕]﹐"恞炑;侗}" -h8"Ba采揨y揥荌3啍2阞)鵋v蠫栩L*^[艧^ t棟埴擪^ 08婦8#jzLu鵖W锴+*╘Y}= \ No newline at end of file diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/95/1a2354eb5856644b0f1db74becc04c908beaa3 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/95/1a2354eb5856644b0f1db74becc04c908beaa3 deleted file mode 100644 index 27ac335e974a54a43fbdbe3d2e38a77f1f6a6767..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmV;N0Av4n0gaA93c@fD06pgwdlzJP(=;0p5j^>fO|qqewNj(#?=AQNufq&XnWyQ} zfU)1S#SAL;I7H??QYaci#?BHAS~-grMao)hO5WXdv0H=WYvdTjdzKuE$q*@e!HU#n ziMd8eo|&CK+c+<9I>Y{SKH6KS`_*=3o(@2L=Sd_4hAk1ITj@I0>`&c2?6tm(@ay1X KI=U}W<~}w0N=rci diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/9a/92a03fdc6eb492ea1ac7acf4fdb04962092f81 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/9a/92a03fdc6eb492ea1ac7acf4fdb04962092f81 new file mode 100644 index 0000000000000000000000000000000000000000..03e4507e878d3c236bb977472c21c7579726dd07 GIT binary patch literal 160 zcmV;R0AK%j0gaAL3d0}}M!WVDvo93KF;StELRLA3KO-r`7{rtwzkyz$%kS|Xe6g1D z>YxxWy)grOuWby-l(b w8bwh>2lEMpXjA&Vr3*qJqLx-?*n%z8$qbMPc=ecp-J97>l1 zmlB+g1)WK+cCQ=s16=yyrk^yglb&*&uRwtv#pu0-BN3w6=|0u;Pu)B<*G1r$L0v%f Mty5ji7avVP=I6*s&Hw-a diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/a5/1a44d96e13555215619b32065d0a22d95b8476 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/a5/1a44d96e13555215619b32065d0a22d95b8476 new file mode 100644 index 000000000..9d703767e --- /dev/null +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/a5/1a44d96e13555215619b32065d0a22d95b8476 @@ -0,0 +1,2 @@ +x嵨K +0a9E鰝d驓D劗z屔db鯝夃耥荥|嫙積櫥啘/ |dlXz哪@誴$E|掇"c玽:d須-鲡,諾r >Xp!k惇鳧}z鮹燆藣峰!z!%u謘焅爹-'Z_R=K \ No newline at end of file diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/a8/3aac98467d005729bc9d80fe98abba47d41495 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/a8/3aac98467d005729bc9d80fe98abba47d41495 deleted file mode 100644 index 20ba8aaf2e75e98570d4ca7eb73621bba30596a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmV;O0Al}m0gaA93d0}}0DJZodoL7?uC7o@A*VcJjVlS%8d3{=egpkLufq(?+-hAr z3_70rE&_uI#3i7%(USK_WK3|{$0RO0D(uLL ry LUq`IIC(b|TCx=L~ diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/ab/7ecb7891c5f56480fba1ed3a6e0fa8e989efab b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/ab/7ecb7891c5f56480fba1ed3a6e0fa8e989efab deleted file mode 100644 index 92e71009c..000000000 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/ab/7ecb7891c5f56480fba1ed3a6e0fa8e989efab +++ /dev/null @@ -1,2 +0,0 @@ -x嵨A - @旬=咞B櫻3PJ!c詰&=~s刵?o袼懂s啡x閲猽@ 蔄+帧f'櫓艠9佋斕.嚲-昐%"牓 ,*#xf5亼Om'{Ё~e綍m}X寖G溄"槼濻]洇蛬>"94 \ No newline at end of file diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/ab/daa06b758aa198cc4afb9c406c87c5690d0ca0 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/ab/daa06b758aa198cc4afb9c406c87c5690d0ca0 new file mode 100644 index 0000000000000000000000000000000000000000..e58f89e997c922d435906149ce37205f17eb09e4 GIT binary patch literal 157 zcmV;O0Al}m0gaA93c@fD06pgwdlw|hX45Q)2tD-~X}XIAV@n&s=UeatUWXZ&veY^^ z@Rm<)69H0`K%B-9Gdr(VnQ};+x`4tRW5ANUqFM7MuLg>p6pGPeoH|ESWF{q=#>2`% zM=VNFy_)=Pk7a{?fNMY8<&*3BluKFa4O|QuT}nuBcFtOJ&||8}pSsa`+Z+5USYA-` Le#GVr142KE?E^=p literal 0 HcmV?d00001 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/b2/afb2548f2d143fdd691058f2283b03933a1749 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/b2/afb2548f2d143fdd691058f2283b03933a1749 new file mode 100644 index 000000000..88f896a17 --- /dev/null +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/b2/afb2548f2d143fdd691058f2283b03933a1749 @@ -0,0 +1,4 @@ +x崕M +0F晃)f_(3N(ム蔯鋑DA岺Zz +紷愤{綯謚^辍 +$穪0嚃B2b8趹Q%=篣鹕 &天\覧3H zpb0OvhyZt-Tp&!rQHV3UiJU>4ECw^#*&w44 0V@ Ro8 zDQPd<_mc{*y5s`G2=`%p$|vmSCbyXP2T*SfdEa#!u0)8c(Kc1(PhHhzEeU=V z>% diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/c6/2b5bc94e327ddb9b545213ff77b207ade48aba b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/c6/2b5bc94e327ddb9b545213ff77b207ade48aba new file mode 100644 index 0000000000000000000000000000000000000000..18785a94df9496eaadbeb6a0764773f78ce55391 GIT binary patch literal 148 zcmV;F0Biqv0gcX03c@fDKw;N8MfQRulfM}d5xVLzlFS4PjV&dD$G1mt`}h{GZoMx< zTe6pNh-fevDl(glMkokVAn{xv7s3`}p=2_rr1pHsdua9zrBO>YMFT>>P@pCNES#IG z$yv{6K;_SPZHJy_eV^v1d~@Gdxz(*dw2j_Hi|B&BT5F6t>p3;#Pp;asiuwU{2|2IN C0YuLL literal 0 HcmV?d00001 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/cd/97d8e8ca03000f761f0e041cea0b6039923e70 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/cd/97d8e8ca03000f761f0e041cea0b6039923e70 deleted file mode 100644 index a14b07295610c42f5d340230cb51f4142c7d9579..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmV;O0Al}m0gaAJ3c@fH0A1%4Z!bt*n=gn6UG*3*$qN;XDKQ0)Z@>$<9cEx+E#=W+ zLV4 8s{^^2D0-)iO;Tz*`4D|_GP56Y zAZ3$6<+Y%rZ?(a)!gX2i{GqZx`4Vfn0U9- & zE~oT$y-u*vKg}TmUP6dO71^_EQWHfVo2w1cGX-0yh^^Sv&O^2dCD`n9Arxn0t(me% zZ;fj$#%y)uDwsI)pHEDdwQIEm$w*e%aEV+Rwwg5_51MRCM)CJt`hfEVUeA|zdGNa5 z z1MSS%hr(##tTm$QZ9moIPh1_sb U7Atgre`4;?u*I|aqwUo63 z20Zkp3QEj8%Q;bGUP4B;B&KtgY|%&-Q@xN+PTu`d8;lcN$LX#gDce&|xt1FslV^<4 b2RI@QgWKso>H4ScY;CU&zsh|9ca<-}QqnfS literal 0 HcmV?d00001 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/f4/7cc13dc21c72755ff2d96d0805837dbb028951 b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/f4/7cc13dc21c72755ff2d96d0805837dbb028951 deleted file mode 100644 index 9be5e4363..000000000 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/f4/7cc13dc21c72755ff2d96d0805837dbb028951 +++ /dev/null @@ -1,2 +0,0 @@ -x崕A -1=s$揹caO麑蒷鉐尃縲xk*h]j絭r7錉姍P勦祆媼釺sRD抷H媒S啜鈓騜憷`M^纨f!%簎垜W,嵠墡鉻芠赉啙.鮀冪攩裂栙Z骋鮐菬)做祠4Xx^OrLZmHY$ z>e48>^u{bF1Oq=!e$D_KOjH)OL?4_D$WcQhB`C3@@w-d!ty4(WS$F~$GB(eJLY@dQ zD9(-*B}xKEUuu)XDDT7g }M|=PP diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/fa/5c5dac095b577173e47b4a0c139525eced009f b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/fa/5c5dac095b577173e47b4a0c139525eced009f new file mode 100644 index 000000000..0e4a74d8c --- /dev/null +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/fa/5c5dac095b577173e47b4a0c139525eced009f @@ -0,0 +1,2 @@ +x崕M +0F]$覮兀D瑾荋 殾(邆p黢x綳KY:(O1聾&[r枼c宷鍴R+憈*J$鲂x霅3h-J>h稞C.檾q智篓]楺刉譹后'攠錕hHtNi8#J)z滉.蛞~ 縴[? \ No newline at end of file diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/base_branch b/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/base_branch index 05892d4c0..504dbe400 100644 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/base_branch +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/base_branch @@ -1 +1 @@ -06d48b81c12e9c1a3cc2704c0db337639a8cdf85 +a51a44d96e13555215619b32065d0a22d95b8476 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/develop b/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/develop index a563ebbae..a63801a54 100644 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/develop +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/develop @@ -1 +1 @@ -85aba0ff0b6e7c0a7f6180f9f6e7e8cdcb71ee3b +9a92a03fdc6eb492ea1ac7acf4fdb04962092f81 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/feature/cherry-picking b/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/feature/cherry-picking index 07d05078f..d09c7755e 100644 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/feature/cherry-picking +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/feature/cherry-picking @@ -1 +1 @@ -1fb30058516518ac1579a8df132b0e4dade8e51d +d88617710499a59992caf98d6df1b5f981c58ab1 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/master b/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/master index 70e34863a..7a24b5e07 100644 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/master +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/master @@ -1 +1 @@ -cd97d8e8ca03000f761f0e041cea0b6039923e70 +d4f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/other_branch b/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/other_branch index 8621c3daa..1e24c496e 100644 --- a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/other_branch +++ b/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/other_branch @@ -1 +1 @@ -4c1db169d59c4345aba213cb79934f4e38222f02 +d7d52ecd690fe82c7d820ddb437e82d78b0fa7b2 diff --git a/test/integration/mergeConflictsFiltered/expected/directory/file2 b/test/integration/mergeConflictsFiltered/expected/directory/file2 index 180cf8328..df6b0d2bc 100644 --- a/test/integration/mergeConflictsFiltered/expected/directory/file2 +++ b/test/integration/mergeConflictsFiltered/expected/directory/file2 @@ -1 +1 @@ -test2 +test3 diff --git a/test/integration/mergeConflictsFiltered/expected/file1 b/test/integration/mergeConflictsFiltered/expected/file1 index 4f80ec0c7..dcd348507 100644 --- a/test/integration/mergeConflictsFiltered/expected/file1 +++ b/test/integration/mergeConflictsFiltered/expected/file1 @@ -1,5 +1,5 @@ Here is a story that has been told throuhg the ages -once upon a time there was a dog +once upon a time there was a cat ... ... ... @@ -60,4 +60,4 @@ once upon a time there was a dog ... ... ... -once upon a time there was another dog +once upon a time there was another cat diff --git a/test/integration/mergeConflictsFiltered/expected/file3 b/test/integration/mergeConflictsFiltered/expected/file3 index e3ae5c6d8..1b9ae5f5d 100644 --- a/test/integration/mergeConflictsFiltered/expected/file3 +++ b/test/integration/mergeConflictsFiltered/expected/file3 @@ -1 +1 @@ -once upon a time there was a horse +once upon a time there was a mouse diff --git a/test/integration/mergeConflictsFiltered/expected/file5 b/test/integration/mergeConflictsFiltered/expected/file5 index 1b9ae5f5d..e3ae5c6d8 100644 --- a/test/integration/mergeConflictsFiltered/expected/file5 +++ b/test/integration/mergeConflictsFiltered/expected/file5 @@ -1 +1 @@ -once upon a time there was a mouse +once upon a time there was a horse diff --git a/test/integration/mergeConflictsFiltered/recording.json b/test/integration/mergeConflictsFiltered/recording.json index 2a7ab1ab3..6d620e9e3 100644 --- a/test/integration/mergeConflictsFiltered/recording.json +++ b/test/integration/mergeConflictsFiltered/recording.json @@ -1 +1 @@ -{"KeyEvents":[{"Timestamp":626,"Mod":0,"Key":259,"Ch":0},{"Timestamp":930,"Mod":0,"Key":258,"Ch":0},{"Timestamp":1065,"Mod":0,"Key":258,"Ch":0},{"Timestamp":1202,"Mod":0,"Key":258,"Ch":0},{"Timestamp":1818,"Mod":0,"Key":256,"Ch":77},{"Timestamp":2234,"Mod":0,"Key":13,"Ch":13},{"Timestamp":2929,"Mod":0,"Key":13,"Ch":13},{"Timestamp":3474,"Mod":0,"Key":258,"Ch":0},{"Timestamp":3739,"Mod":0,"Key":258,"Ch":0},{"Timestamp":3890,"Mod":0,"Key":258,"Ch":0},{"Timestamp":4401,"Mod":0,"Key":256,"Ch":32},{"Timestamp":4714,"Mod":0,"Key":256,"Ch":32},{"Timestamp":5681,"Mod":0,"Key":256,"Ch":32},{"Timestamp":6003,"Mod":0,"Key":258,"Ch":0},{"Timestamp":6226,"Mod":0,"Key":256,"Ch":32},{"Timestamp":8394,"Mod":2,"Key":2,"Ch":2},{"Timestamp":9194,"Mod":0,"Key":13,"Ch":13},{"Timestamp":9691,"Mod":0,"Key":258,"Ch":0},{"Timestamp":9842,"Mod":0,"Key":258,"Ch":0},{"Timestamp":10041,"Mod":0,"Key":256,"Ch":32},{"Timestamp":10322,"Mod":0,"Key":258,"Ch":0},{"Timestamp":10610,"Mod":0,"Key":256,"Ch":32},{"Timestamp":11682,"Mod":2,"Key":2,"Ch":2},{"Timestamp":12113,"Mod":0,"Key":258,"Ch":0},{"Timestamp":12458,"Mod":0,"Key":13,"Ch":13},{"Timestamp":12994,"Mod":0,"Key":257,"Ch":0},{"Timestamp":13210,"Mod":0,"Key":256,"Ch":32},{"Timestamp":13842,"Mod":2,"Key":2,"Ch":2},{"Timestamp":15075,"Mod":0,"Key":258,"Ch":0},{"Timestamp":15290,"Mod":0,"Key":258,"Ch":0},{"Timestamp":15890,"Mod":0,"Key":256,"Ch":32},{"Timestamp":16778,"Mod":0,"Key":257,"Ch":0},{"Timestamp":17130,"Mod":0,"Key":256,"Ch":32},{"Timestamp":17546,"Mod":0,"Key":256,"Ch":32},{"Timestamp":18250,"Mod":0,"Key":256,"Ch":32},{"Timestamp":18626,"Mod":0,"Key":257,"Ch":0},{"Timestamp":18882,"Mod":0,"Key":256,"Ch":32},{"Timestamp":19210,"Mod":0,"Key":256,"Ch":32},{"Timestamp":19762,"Mod":0,"Key":257,"Ch":0},{"Timestamp":20002,"Mod":0,"Key":256,"Ch":32},{"Timestamp":20322,"Mod":0,"Key":256,"Ch":32},{"Timestamp":20746,"Mod":0,"Key":256,"Ch":32},{"Timestamp":21138,"Mod":0,"Key":256,"Ch":32},{"Timestamp":22724,"Mod":0,"Key":27,"Ch":0},{"Timestamp":24410,"Mod":0,"Key":256,"Ch":77},{"Timestamp":25725,"Mod":0,"Key":27,"Ch":0},{"Timestamp":26017,"Mod":0,"Key":256,"Ch":109},{"Timestamp":26745,"Mod":0,"Key":13,"Ch":13},{"Timestamp":27826,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":272,"Height":74}]} \ No newline at end of file +{"KeyEvents":[{"Timestamp":682,"Mod":0,"Key":259,"Ch":0},{"Timestamp":929,"Mod":0,"Key":258,"Ch":0},{"Timestamp":1104,"Mod":0,"Key":258,"Ch":0},{"Timestamp":1417,"Mod":0,"Key":258,"Ch":0},{"Timestamp":1953,"Mod":0,"Key":256,"Ch":77},{"Timestamp":2241,"Mod":0,"Key":13,"Ch":13},{"Timestamp":2729,"Mod":0,"Key":13,"Ch":13},{"Timestamp":3233,"Mod":0,"Key":258,"Ch":0},{"Timestamp":3489,"Mod":0,"Key":256,"Ch":32},{"Timestamp":4048,"Mod":0,"Key":256,"Ch":32},{"Timestamp":4353,"Mod":0,"Key":258,"Ch":0},{"Timestamp":4673,"Mod":0,"Key":256,"Ch":32},{"Timestamp":4992,"Mod":0,"Key":258,"Ch":0},{"Timestamp":5208,"Mod":0,"Key":256,"Ch":32},{"Timestamp":6408,"Mod":2,"Key":2,"Ch":2},{"Timestamp":7145,"Mod":0,"Key":13,"Ch":13},{"Timestamp":7625,"Mod":0,"Key":258,"Ch":0},{"Timestamp":7841,"Mod":0,"Key":258,"Ch":0},{"Timestamp":8056,"Mod":0,"Key":258,"Ch":0},{"Timestamp":8520,"Mod":0,"Key":256,"Ch":32},{"Timestamp":8897,"Mod":0,"Key":256,"Ch":32},{"Timestamp":9233,"Mod":0,"Key":256,"Ch":32},{"Timestamp":9633,"Mod":2,"Key":2,"Ch":2},{"Timestamp":10016,"Mod":0,"Key":258,"Ch":0},{"Timestamp":10393,"Mod":0,"Key":13,"Ch":13},{"Timestamp":10881,"Mod":0,"Key":258,"Ch":0},{"Timestamp":11137,"Mod":0,"Key":258,"Ch":0},{"Timestamp":11473,"Mod":0,"Key":258,"Ch":0},{"Timestamp":11809,"Mod":0,"Key":258,"Ch":0},{"Timestamp":12056,"Mod":0,"Key":256,"Ch":32},{"Timestamp":12354,"Mod":0,"Key":256,"Ch":32},{"Timestamp":12921,"Mod":2,"Key":2,"Ch":2},{"Timestamp":13481,"Mod":0,"Key":258,"Ch":0},{"Timestamp":13681,"Mod":0,"Key":258,"Ch":0},{"Timestamp":13945,"Mod":0,"Key":13,"Ch":13},{"Timestamp":14992,"Mod":0,"Key":256,"Ch":32},{"Timestamp":15408,"Mod":0,"Key":256,"Ch":32},{"Timestamp":15929,"Mod":0,"Key":256,"Ch":32},{"Timestamp":16185,"Mod":0,"Key":257,"Ch":0},{"Timestamp":16401,"Mod":0,"Key":256,"Ch":32},{"Timestamp":16753,"Mod":0,"Key":256,"Ch":32},{"Timestamp":17353,"Mod":0,"Key":256,"Ch":32},{"Timestamp":17640,"Mod":0,"Key":258,"Ch":0},{"Timestamp":17825,"Mod":0,"Key":256,"Ch":32},{"Timestamp":18249,"Mod":0,"Key":256,"Ch":32},{"Timestamp":18457,"Mod":0,"Key":257,"Ch":0},{"Timestamp":18673,"Mod":0,"Key":256,"Ch":32},{"Timestamp":19593,"Mod":0,"Key":13,"Ch":13},{"Timestamp":20641,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":272,"Height":74}]} \ No newline at end of file diff --git a/test/integration/mergeConflictsFiltered/test.json b/test/integration/mergeConflictsFiltered/test.json index fc1c9236a..7402aede2 100644 --- a/test/integration/mergeConflictsFiltered/test.json +++ b/test/integration/mergeConflictsFiltered/test.json @@ -1,4 +1,4 @@ { "description": "Verify that when we get merge conflicts we filter out any non-conflicted files", - "speed": 1 + "speed": 5 } From 2a1e3faa0c61cc8c2418310089485dbab268228f Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Mon, 31 Jan 2022 22:11:34 +1100 Subject: [PATCH 047/385] resetting controllers on new repo --- go.mod | 4 +- go.sum | 8 +- main.go | 4 +- pkg/app/app.go | 8 +- pkg/cheatsheet/generate.go | 2 +- pkg/gui/branches_panel.go | 30 +-- pkg/gui/commit_files_panel.go | 10 +- pkg/gui/commits_panel.go | 6 +- pkg/gui/controllers/files_controller.go | 4 +- .../files_helper.go} | 11 +- .../controllers/local_commits_controller.go | 12 +- pkg/gui/{ => controllers}/refs_helper.go | 52 ++-- .../{ => controllers}/suggestions_helper.go | 43 ++-- pkg/gui/controllers/types.go | 30 --- .../{ => controllers}/working_tree_helper.go | 26 +- pkg/gui/diffing.go | 2 +- pkg/gui/dummies.go | 2 +- pkg/gui/filtering_menu_panel.go | 2 +- pkg/gui/gui.go | 226 +++++++++--------- pkg/gui/gui_test.go | 1 + pkg/gui/keybindings.go | 12 +- pkg/gui/layout.go | 6 +- pkg/gui/line_by_line_panel.go | 2 +- pkg/gui/list_context_config.go | 50 ++-- pkg/gui/misc.go | 2 +- pkg/gui/modes.go | 8 +- pkg/gui/patch_options_panel.go | 20 +- pkg/gui/pull_request_menu_panel.go | 2 +- pkg/gui/recent_repos_panel.go | 18 +- pkg/gui/reflog_panel.go | 10 +- pkg/gui/refresh.go | 40 ++-- pkg/gui/remote_branches_panel.go | 8 +- pkg/gui/remotes_panel.go | 4 +- pkg/gui/stash_panel.go | 4 +- pkg/gui/status_panel.go | 6 +- pkg/gui/sub_commits_panel.go | 14 +- pkg/gui/submodules_panel.go | 6 +- pkg/gui/types/common.go | 29 +++ pkg/gui/workspace_reset_options_panel.go | 2 +- vendor/github.com/go-errors/errors/README.md | 1 + .../github.com/go-errors/errors/stackframe.go | 14 +- vendor/github.com/jesseduffield/gocui/gui.go | 8 +- vendor/golang.org/x/sys/unix/zerrors_linux.go | 23 +- .../x/sys/unix/zerrors_linux_386.go | 3 + .../x/sys/unix/zerrors_linux_amd64.go | 3 + .../x/sys/unix/zerrors_linux_arm.go | 3 + .../x/sys/unix/zerrors_linux_arm64.go | 3 + .../x/sys/unix/zerrors_linux_mips.go | 3 + .../x/sys/unix/zerrors_linux_mips64.go | 3 + .../x/sys/unix/zerrors_linux_mips64le.go | 3 + .../x/sys/unix/zerrors_linux_mipsle.go | 3 + .../x/sys/unix/zerrors_linux_ppc.go | 3 + .../x/sys/unix/zerrors_linux_ppc64.go | 3 + .../x/sys/unix/zerrors_linux_ppc64le.go | 3 + .../x/sys/unix/zerrors_linux_riscv64.go | 3 + .../x/sys/unix/zerrors_linux_s390x.go | 3 + .../x/sys/unix/zerrors_linux_sparc64.go | 3 + .../x/sys/unix/zsysnum_linux_386.go | 1 + .../x/sys/unix/zsysnum_linux_amd64.go | 1 + .../x/sys/unix/zsysnum_linux_arm.go | 1 + .../x/sys/unix/zsysnum_linux_arm64.go | 1 + .../x/sys/unix/zsysnum_linux_mips.go | 1 + .../x/sys/unix/zsysnum_linux_mips64.go | 1 + .../x/sys/unix/zsysnum_linux_mips64le.go | 1 + .../x/sys/unix/zsysnum_linux_mipsle.go | 1 + .../x/sys/unix/zsysnum_linux_ppc.go | 1 + .../x/sys/unix/zsysnum_linux_ppc64.go | 1 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 1 + .../x/sys/unix/zsysnum_linux_riscv64.go | 1 + .../x/sys/unix/zsysnum_linux_s390x.go | 1 + .../x/sys/unix/zsysnum_linux_sparc64.go | 1 + vendor/golang.org/x/sys/unix/ztypes_linux.go | 32 ++- .../x/sys/windows/syscall_windows.go | 2 + .../golang.org/x/sys/windows/types_windows.go | 2 + .../x/sys/windows/zsyscall_windows.go | 14 ++ vendor/modules.txt | 6 +- 76 files changed, 514 insertions(+), 370 deletions(-) rename pkg/gui/{file_helper.go => controllers/files_helper.go} (83%) rename pkg/gui/{ => controllers}/refs_helper.go (78%) rename pkg/gui/{ => controllers}/suggestions_helper.go (81%) rename pkg/gui/{ => controllers}/working_tree_helper.go (59%) diff --git a/go.mod b/go.mod index f4f67183d..0cde50810 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/imdario/mergo v0.3.11 github.com/integrii/flaggy v1.4.0 github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 - github.com/jesseduffield/gocui v0.3.1-0.20220108045521-1945d7b9ed8b + github.com/jesseduffield/gocui v0.3.1-0.20220131110921-82fe47ec96ba github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e github.com/jesseduffield/yaml v2.1.0+incompatible github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 @@ -42,7 +42,7 @@ require ( github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // indirect golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect - golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect + golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0 ) diff --git a/go.sum b/go.sum index e0e58cd81..1b3593e93 100644 --- a/go.sum +++ b/go.sum @@ -41,8 +41,8 @@ github.com/gdamore/tcell/v2 v2.4.1-0.20220313203054-2a1a1b586447/go.mod h1:I8YJF github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= -github.com/go-errors/errors v1.4.1 h1:IvVlgbzSsaUNudsw5dcXSzF3EWyXTi5XrAdngnuhRyg= -github.com/go-errors/errors v1.4.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= @@ -73,8 +73,8 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= -github.com/jesseduffield/gocui v0.3.1-0.20220108045521-1945d7b9ed8b h1:AUK5nDiPiaahBtGIsf8rITgZ9SC+uddvnNKs0/mrYA8= -github.com/jesseduffield/gocui v0.3.1-0.20220108045521-1945d7b9ed8b/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU= +github.com/jesseduffield/gocui v0.3.1-0.20220131110921-82fe47ec96ba h1:5czcvu7MjSzrS12qPCLhh6yiE2eRz+tZCybH7Q85TpM= +github.com/jesseduffield/gocui v0.3.1-0.20220131110921-82fe47ec96ba/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU= github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U= github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e/go.mod h1:u60qdFGXRd36jyEXxetz0vQceQIxzI13lIo3EFUDf4I= github.com/jesseduffield/yaml v2.1.0+incompatible h1:HWQJ1gIv2zHKbDYNp0Jwjlj24K8aqpFHnMCynY1EpmE= diff --git a/main.go b/main.go index c6c097146..7d071cda2 100644 --- a/main.go +++ b/main.go @@ -132,10 +132,10 @@ func main() { log.Fatal(err.Error()) } - app, err := app.NewApp(appConfig, filterPath) + app, err := app.NewApp(appConfig) if err == nil { - err = app.Run() + err = app.Run(filterPath) } if err != nil { diff --git a/pkg/app/app.go b/pkg/app/app.go index f38dcb75e..0ee7e4adf 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -94,7 +94,7 @@ func newLogger(config config.AppConfigurer) *logrus.Entry { } // NewApp bootstrap a new application -func NewApp(config config.AppConfigurer, filterPath string) (*App, error) { +func NewApp(config config.AppConfigurer) (*App, error) { userConfig := config.GetUserConfig() app := &App{ @@ -140,7 +140,7 @@ func NewApp(config config.AppConfigurer, filterPath string) (*App, error) { gitConfig := git_config.NewStdCachedGitConfig(app.Log) - app.Gui, err = gui.NewGui(app.Common, config, gitConfig, app.Updater, filterPath, showRecentRepos, dirName) + app.Gui, err = gui.NewGui(app.Common, config, gitConfig, app.Updater, showRecentRepos, dirName) if err != nil { return app, err } @@ -241,7 +241,7 @@ func (app *App) setupRepo() (bool, error) { return false, nil } -func (app *App) Run() error { +func (app *App) Run(filterPath string) error { if app.ClientContext == "INTERACTIVE_REBASE" { return app.Rebase() } @@ -250,7 +250,7 @@ func (app *App) Run() error { os.Exit(0) } - err := app.Gui.RunAndHandleError() + err := app.Gui.RunAndHandleError(filterPath) return err } diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index 3d1b5efcf..15e390356 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -41,7 +41,7 @@ func generateAtDir(cheatsheetDir string) { for lang := range translationSetsByLang { mConfig.GetUserConfig().Gui.Language = lang - mApp, _ := app.NewApp(mConfig, "") + mApp, _ := app.NewApp(mConfig) path := cheatsheetDir + "/Keybindings_" + lang + ".md" file, err := os.Create(path) if err != nil { diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index 9cf0d740a..f295c9470 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -14,7 +14,7 @@ import ( // list panel functions func (gui *Gui) getSelectedBranch() *models.Branch { - if len(gui.State.Branches) == 0 { + if len(gui.State.Model.Branches) == 0 { return nil } @@ -23,7 +23,7 @@ func (gui *Gui) getSelectedBranch() *models.Branch { return nil } - return gui.State.Branches[selectedLine] + return gui.State.Model.Branches[selectedLine] } func (gui *Gui) branchesRenderToMain() error { @@ -56,7 +56,7 @@ func (gui *Gui) handleBranchPress() error { } branch := gui.getSelectedBranch() gui.c.LogAction(gui.c.Tr.Actions.CheckoutBranch) - return gui.helpers.refs.CheckoutRef(branch.Name, types.CheckoutRefOptions{}) + return gui.helpers.Refs.CheckoutRef(branch.Name, types.CheckoutRefOptions{}) } func (gui *Gui) handleCreatePullRequestPress() error { @@ -129,10 +129,10 @@ func (gui *Gui) handleForceCheckout() error { func (gui *Gui) handleCheckoutByName() error { return gui.c.Prompt(types.PromptOpts{ Title: gui.c.Tr.BranchName + ":", - FindSuggestionsFunc: gui.helpers.suggestions.GetRefsSuggestionsFunc(), + FindSuggestionsFunc: gui.helpers.Suggestions.GetRefsSuggestionsFunc(), HandleConfirm: func(response string) error { gui.c.LogAction("Checkout branch") - return gui.helpers.refs.CheckoutRef(response, types.CheckoutRefOptions{ + return gui.helpers.Refs.CheckoutRef(response, types.CheckoutRefOptions{ OnRefNotFound: func(ref string) error { return gui.c.Ask(types.AskOpts{ Title: gui.c.Tr.BranchNotFoundTitle, @@ -148,11 +148,11 @@ func (gui *Gui) handleCheckoutByName() error { } func (gui *Gui) getCheckedOutBranch() *models.Branch { - if len(gui.State.Branches) == 0 { + if len(gui.State.Model.Branches) == 0 { return nil } - return gui.State.Branches[0] + return gui.State.Model.Branches[0] } func (gui *Gui) createNewBranchWithName(newBranchName string) error { @@ -239,7 +239,7 @@ func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error { HandleConfirm: func() error { gui.c.LogAction(gui.c.Tr.Actions.Merge) err := gui.git.Branch.Merge(branchName, git_commands.MergeOpts{}) - return gui.helpers.rebase.CheckMergeOrRebase(err) + return gui.helpers.Rebase.CheckMergeOrRebase(err) }, }) } @@ -273,7 +273,7 @@ func (gui *Gui) handleRebaseOntoBranch(selectedBranchName string) error { HandleConfirm: func() error { gui.c.LogAction(gui.c.Tr.Actions.RebaseBranch) err := gui.git.Rebase.RebaseBranch(selectedBranchName) - return gui.helpers.rebase.CheckMergeOrRebase(err) + return gui.helpers.Rebase.CheckMergeOrRebase(err) }, }) } @@ -339,7 +339,7 @@ func (gui *Gui) handleCreateResetToBranchMenu() error { return nil } - return gui.helpers.refs.CreateGitResetMenu(branch.Name) + return gui.helpers.Refs.CreateGitResetMenu(branch.Name) } func (gui *Gui) handleRenameBranch() error { @@ -362,7 +362,7 @@ func (gui *Gui) handleRenameBranch() error { gui.refreshBranches() // now that we've got our stuff again we need to find that branch and reselect it. - for i, newBranch := range gui.State.Branches { + for i, newBranch := range gui.State.Model.Branches { if newBranch.Name == newBranchName { gui.State.Panels.Branches.SetSelectedLineIdx(i) if err := gui.State.Contexts.Branches.HandleRender(); err != nil { @@ -390,12 +390,6 @@ func (gui *Gui) handleRenameBranch() error { }) } -// sanitizedBranchName will remove all spaces in favor of a dash "-" to meet -// git's branch naming requirement. -func sanitizedBranchName(input string) string { - return strings.Replace(input, " ", "-", -1) -} - func (gui *Gui) handleEnterBranch() error { branch := gui.getSelectedBranch() if branch == nil { @@ -411,5 +405,5 @@ func (gui *Gui) handleNewBranchOffBranch() error { return nil } - return gui.helpers.refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), "") + return gui.helpers.Refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), "") } diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index 8e6410b9e..f55b3d6c3 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -82,8 +82,8 @@ func (gui *Gui) handleDiscardOldFileChange() error { HandleConfirm: func() error { return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { gui.c.LogAction(gui.c.Tr.Actions.DiscardOldFileChange) - if err := gui.git.Rebase.DiscardOldFileChanges(gui.State.Commits, gui.State.Panels.Commits.SelectedLineIdx, fileName); err != nil { - if err := gui.helpers.rebase.CheckMergeOrRebase(err); err != nil { + if err := gui.git.Rebase.DiscardOldFileChanges(gui.State.Model.Commits, gui.State.Panels.Commits.SelectedLineIdx, fileName); err != nil { + if err := gui.helpers.Rebase.CheckMergeOrRebase(err); err != nil { return err } } @@ -109,7 +109,7 @@ func (gui *Gui) refreshCommitFilesView() error { if err != nil { return gui.c.Error(err) } - gui.State.CommitFiles = files + gui.State.Model.CommitFiles = files gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.SetTree() return gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles) @@ -121,7 +121,7 @@ func (gui *Gui) handleOpenOldCommitFile() error { return nil } - return gui.helpers.files.OpenFile(node.GetPath()) + return gui.helpers.Files.OpenFile(node.GetPath()) } func (gui *Gui) handleEditCommitFile() error { @@ -134,7 +134,7 @@ func (gui *Gui) handleEditCommitFile() error { return gui.c.ErrorMsg(gui.c.Tr.ErrCannotEditDirectory) } - return gui.helpers.files.EditFile(node.GetPath()) + return gui.helpers.Files.EditFile(node.GetPath()) } func (gui *Gui) handleToggleFileForPatch() error { diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index b2233f377..4175918ea 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -12,11 +12,11 @@ const COMMIT_THRESHOLD = 200 func (gui *Gui) getSelectedLocalCommit() *models.Commit { selectedLine := gui.State.Panels.Commits.SelectedLineIdx - if selectedLine == -1 || selectedLine > len(gui.State.Commits)-1 { + if selectedLine == -1 || selectedLine > len(gui.State.Model.Commits)-1 { return nil } - return gui.State.Commits[selectedLine] + return gui.State.Model.Commits[selectedLine] } func (gui *Gui) onCommitFocus() error { @@ -56,7 +56,7 @@ func (gui *Gui) branchCommitsRenderToMain() error { func (gui *Gui) refForLog() string { bisectInfo := gui.git.Bisect.GetInfo() - gui.State.BisectInfo = bisectInfo + gui.State.Model.BisectInfo = bisectInfo if !bisectInfo.Started() { return "HEAD" diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index 9209a96b3..57df2e84e 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -40,7 +40,7 @@ type FilesController struct { switchToMergeFn func(path string) error suggestionsHelper ISuggestionsHelper refsHelper IRefsHelper - filesHelper IFileHelper + filesHelper IFilesHelper workingTreeHelper IWorkingTreeHelper } @@ -64,7 +64,7 @@ func NewFilesController( switchToMergeFn func(path string) error, suggestionsHelper ISuggestionsHelper, refsHelper IRefsHelper, - filesHelper IFileHelper, + filesHelper IFilesHelper, workingTreeHelper IWorkingTreeHelper, ) *FilesController { return &FilesController{ diff --git a/pkg/gui/file_helper.go b/pkg/gui/controllers/files_helper.go similarity index 83% rename from pkg/gui/file_helper.go rename to pkg/gui/controllers/files_helper.go index 2e32e168f..c3706cc72 100644 --- a/pkg/gui/file_helper.go +++ b/pkg/gui/controllers/files_helper.go @@ -1,12 +1,17 @@ -package gui +package controllers import ( "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" - "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/types" ) +type IFilesHelper interface { + EditFile(filename string) error + EditFileAtLine(filename string, lineNumber int) error + OpenFile(filename string) error +} + type FilesHelper struct { c *types.ControllerCommon git *commands.GitCommand @@ -25,7 +30,7 @@ func NewFilesHelper( } } -var _ controllers.IFileHelper = &FilesHelper{} +var _ IFilesHelper = &FilesHelper{} func (self *FilesHelper) EditFile(filename string) error { return self.EditFileAtLine(filename, 1) diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index 3e30619be..bc25411bf 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -20,7 +20,6 @@ type ( GetHostingServiceMgrFn func() *hosting_service.HostingServiceMgr PullFilesFn func() error CheckMergeOrRebase func(error) error - OpenSearchFn func(viewName string) error ) type LocalCommitsController struct { @@ -40,7 +39,6 @@ type LocalCommitsController struct { pullFiles PullFilesFn getHostingServiceMgr GetHostingServiceMgrFn switchToCommitFilesContext SwitchToCommitFilesContextFn - openSearch OpenSearchFn getLimitCommits func() bool setLimitCommits func(bool) getShowWholeGitGraph func() bool @@ -65,7 +63,6 @@ func NewLocalCommitsController( pullFiles PullFilesFn, getHostingServiceMgr GetHostingServiceMgrFn, switchToCommitFilesContext SwitchToCommitFilesContextFn, - openSearch OpenSearchFn, getLimitCommits func() bool, setLimitCommits func(bool), getShowWholeGitGraph func() bool, @@ -87,7 +84,6 @@ func NewLocalCommitsController( pullFiles: pullFiles, getHostingServiceMgr: getHostingServiceMgr, switchToCommitFilesContext: switchToCommitFilesContext, - openSearch: openSearch, getLimitCommits: getLimitCommits, setLimitCommits: setLimitCommits, getShowWholeGitGraph: getShowWholeGitGraph, @@ -191,7 +187,7 @@ func (self *LocalCommitsController) Keybindings( // more commits on demand { Key: getKey(config.Universal.StartSearch), - Handler: func() error { return self.handleOpenSearch("commits") }, + Handler: self.openSearch, Description: self.c.Tr.LcStartSearch, Tag: "navigation", }, @@ -653,7 +649,7 @@ func (self *LocalCommitsController) handleCreateCommitResetMenu(commit *models.C return self.refsHelper.CreateGitResetMenu(commit.Sha) } -func (self *LocalCommitsController) handleOpenSearch(string) error { +func (self *LocalCommitsController) openSearch() error { // we usually lazyload these commits but now that we're searching we need to load them now if self.getLimitCommits() { self.setLimitCommits(false) @@ -662,7 +658,9 @@ func (self *LocalCommitsController) handleOpenSearch(string) error { } } - return self.openSearch("commits") + self.c.OpenSearch() + + return nil } func (self *LocalCommitsController) gotoBottom() error { diff --git a/pkg/gui/refs_helper.go b/pkg/gui/controllers/refs_helper.go similarity index 78% rename from pkg/gui/refs_helper.go rename to pkg/gui/controllers/refs_helper.go index f732ce204..2bb1868e0 100644 --- a/pkg/gui/refs_helper.go +++ b/pkg/gui/controllers/refs_helper.go @@ -1,4 +1,4 @@ -package gui +package controllers import ( "fmt" @@ -7,35 +7,40 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/gui/context" - "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) -type RefsHelper struct { - c *types.ControllerCommon - git *commands.GitCommand - getContexts func() context.ContextTree +type IRefsHelper interface { + CheckoutRef(ref string, options types.CheckoutRefOptions) error + CreateGitResetMenu(ref string) error + ResetToRef(ref string, strength string, envVars []string) error + NewBranch(from string, fromDescription string, suggestedBranchname string) error +} - getState func() *GuiRepoState +type RefsHelper struct { + c *types.ControllerCommon + git *commands.GitCommand + getContexts func() context.ContextTree + limitCommits func() } func NewRefsHelper( c *types.ControllerCommon, git *commands.GitCommand, getContexts func() context.ContextTree, - getState func() *GuiRepoState, + limitCommits func(), ) *RefsHelper { return &RefsHelper{ - c: c, - git: git, - getContexts: getContexts, - getState: getState, + c: c, + git: git, + getContexts: getContexts, + limitCommits: limitCommits, } } -var _ controllers.IRefsHelper = &RefsHelper{} +var _ IRefsHelper = &RefsHelper{} func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions) error { waitingStatus := options.WaitingStatus @@ -46,10 +51,11 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions cmdOptions := git_commands.CheckoutOptions{Force: false, EnvVars: options.EnvVars} onSuccess := func() { - self.getState().Panels.Branches.SelectedLineIdx = 0 - self.getState().Panels.Commits.SelectedLineIdx = 0 + self.getContexts().Branches.GetPanelState().SetSelectedLineIdx(0) + self.getContexts().BranchCommits.GetPanelState().SetSelectedLineIdx(0) + self.getContexts().ReflogCommits.GetPanelState().SetSelectedLineIdx(0) // loading a heap of commits is slow so we limit them whenever doing a reset - self.getState().Panels.Commits.LimitCommits = true + self.limitCommits() } return self.c.WithWaitingStatus(waitingStatus, func() error { @@ -101,12 +107,12 @@ func (self *RefsHelper) ResetToRef(ref string, strength string, envVars []string return self.c.Error(err) } - self.getState().Panels.Commits.SelectedLineIdx = 0 - self.getState().Panels.ReflogCommits.SelectedLineIdx = 0 + self.getContexts().BranchCommits.GetPanelState().SetSelectedLineIdx(0) + self.getContexts().ReflogCommits.GetPanelState().SetSelectedLineIdx(0) // loading a heap of commits is slow so we limit them whenever doing a reset - self.getState().Panels.Commits.LimitCommits = true + self.limitCommits() - if err := self.c.PushContext(self.getState().Contexts.BranchCommits); err != nil { + if err := self.c.PushContext(self.getContexts().BranchCommits); err != nil { return err } @@ -170,3 +176,9 @@ func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggest }, }) } + +// sanitizedBranchName will remove all spaces in favor of a dash "-" to meet +// git's branch naming requirement. +func sanitizedBranchName(input string) string { + return strings.Replace(input, " ", "-", -1) +} diff --git a/pkg/gui/suggestions_helper.go b/pkg/gui/controllers/suggestions_helper.go similarity index 81% rename from pkg/gui/suggestions_helper.go rename to pkg/gui/controllers/suggestions_helper.go index 3d6d9cd79..8a58e0e56 100644 --- a/pkg/gui/suggestions_helper.go +++ b/pkg/gui/controllers/suggestions_helper.go @@ -1,10 +1,9 @@ -package gui +package controllers import ( "fmt" "os" - "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -22,30 +21,39 @@ import ( // finding suggestions in this file, so that it's easy to see if a function already // exists for fetching a particular model. +type ISuggestionsHelper interface { + GetRemoteSuggestionsFunc() func(string) []*types.Suggestion + GetBranchNameSuggestionsFunc() func(string) []*types.Suggestion + GetFilePathSuggestionsFunc() func(string) []*types.Suggestion + GetRemoteBranchesSuggestionsFunc(separator string) func(string) []*types.Suggestion + GetRefsSuggestionsFunc() func(string) []*types.Suggestion + GetCustomCommandsHistorySuggestionsFunc() func(string) []*types.Suggestion +} + type SuggestionsHelper struct { c *types.ControllerCommon - getState func() *GuiRepoState + model *types.Model refreshSuggestionsFn func() } -var _ controllers.ISuggestionsHelper = &SuggestionsHelper{} +var _ ISuggestionsHelper = &SuggestionsHelper{} func NewSuggestionsHelper( c *types.ControllerCommon, - getState func() *GuiRepoState, + model *types.Model, refreshSuggestionsFn func(), ) *SuggestionsHelper { return &SuggestionsHelper{ c: c, - getState: getState, + model: model, refreshSuggestionsFn: refreshSuggestionsFn, } } func (self *SuggestionsHelper) getRemoteNames() []string { - result := make([]string, len(self.getState().Remotes)) - for i, remote := range self.getState().Remotes { + result := make([]string, len(self.model.Remotes)) + for i, remote := range self.model.Remotes { result[i] = remote.Name } return result @@ -69,8 +77,8 @@ func (self *SuggestionsHelper) GetRemoteSuggestionsFunc() func(string) []*types. } func (self *SuggestionsHelper) getBranchNames() []string { - result := make([]string, len(self.getState().Branches)) - for i, branch := range self.getState().Branches { + result := make([]string, len(self.model.Branches)) + for i, branch := range self.model.Branches { result[i] = branch.Name } return result @@ -100,8 +108,8 @@ func (self *SuggestionsHelper) GetBranchNameSuggestionsFunc() func(string) []*ty } // here we asynchronously fetch the latest set of paths in the repo and store in -// self.State.FilesTrie. On the main thread we'll be doing a fuzzy search via -// self.State.FilesTrie. So if we've looked for a file previously, we'll start with +// self.model.FilesTrie. On the main thread we'll be doing a fuzzy search via +// self.model.FilesTrie. So if we've looked for a file previously, we'll start with // the old trie and eventually it'll be swapped out for the new one. // Notably, unlike other suggestion functions we're not showing all the options // if nothing has been typed because there'll be too much to display efficiently @@ -122,8 +130,9 @@ func (self *SuggestionsHelper) GetFilePathSuggestionsFunc() func(string) []*type trie.Insert(patricia.Prefix(path), path) return nil }) + // cache the trie for future use - self.getState().FilesTrie = trie + self.model.FilesTrie = trie self.refreshSuggestionsFn() @@ -132,7 +141,7 @@ func (self *SuggestionsHelper) GetFilePathSuggestionsFunc() func(string) []*type return func(input string) []*types.Suggestion { matchingNames := []string{} - _ = self.getState().FilesTrie.VisitFuzzy(patricia.Prefix(input), true, func(prefix patricia.Prefix, item patricia.Item, skipped int) error { + _ = self.model.FilesTrie.VisitFuzzy(patricia.Prefix(input), true, func(prefix patricia.Prefix, item patricia.Item, skipped int) error { matchingNames = append(matchingNames, item.(string)) return nil }) @@ -154,7 +163,7 @@ func (self *SuggestionsHelper) GetFilePathSuggestionsFunc() func(string) []*type func (self *SuggestionsHelper) getRemoteBranchNames(separator string) []string { result := []string{} - for _, remote := range self.getState().Remotes { + for _, remote := range self.model.Remotes { for _, branch := range remote.Branches { result = append(result, fmt.Sprintf("%s%s%s", remote.Name, separator, branch.Name)) } @@ -167,8 +176,8 @@ func (self *SuggestionsHelper) GetRemoteBranchesSuggestionsFunc(separator string } func (self *SuggestionsHelper) getTagNames() []string { - result := make([]string, len(self.getState().Tags)) - for i, tag := range self.getState().Tags { + result := make([]string, len(self.model.Tags)) + for i, tag := range self.model.Tags { result[i] = tag.Name } return result diff --git a/pkg/gui/controllers/types.go b/pkg/gui/controllers/types.go index c3466e536..ecd02536c 100644 --- a/pkg/gui/controllers/types.go +++ b/pkg/gui/controllers/types.go @@ -1,39 +1,9 @@ package controllers import ( - "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/types" ) -type IRefsHelper interface { - CheckoutRef(ref string, options types.CheckoutRefOptions) error - CreateGitResetMenu(ref string) error - ResetToRef(ref string, strength string, envVars []string) error - NewBranch(from string, fromDescription string, suggestedBranchname string) error -} - -type ISuggestionsHelper interface { - GetRemoteSuggestionsFunc() func(string) []*types.Suggestion - GetBranchNameSuggestionsFunc() func(string) []*types.Suggestion - GetFilePathSuggestionsFunc() func(string) []*types.Suggestion - GetRemoteBranchesSuggestionsFunc(separator string) func(string) []*types.Suggestion - GetRefsSuggestionsFunc() func(string) []*types.Suggestion - GetCustomCommandsHistorySuggestionsFunc() func(string) []*types.Suggestion -} - -type IFileHelper interface { - EditFile(filename string) error - EditFileAtLine(filename string, lineNumber int) error - OpenFile(filename string) error -} - -type IWorkingTreeHelper interface { - AnyStagedFiles() bool - AnyTrackedFiles() bool - IsWorkingTreeDirty() bool - FileForSubmodule(submodule *models.SubmoduleConfig) *models.File -} - // all fields mandatory (except `CanRebase` because it's boolean) type SwitchToCommitFilesContextOpts struct { RefName string diff --git a/pkg/gui/working_tree_helper.go b/pkg/gui/controllers/working_tree_helper.go similarity index 59% rename from pkg/gui/working_tree_helper.go rename to pkg/gui/controllers/working_tree_helper.go index 3b0162d75..894d278be 100644 --- a/pkg/gui/working_tree_helper.go +++ b/pkg/gui/controllers/working_tree_helper.go @@ -1,22 +1,29 @@ -package gui +package controllers import ( "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) -type WorkingTreeHelper struct { - getFiles func() []*models.File +type IWorkingTreeHelper interface { + AnyStagedFiles() bool + AnyTrackedFiles() bool + IsWorkingTreeDirty() bool + FileForSubmodule(submodule *models.SubmoduleConfig) *models.File } -func NewWorkingTreeHelper(getFiles func() []*models.File) *WorkingTreeHelper { +type WorkingTreeHelper struct { + model *types.Model +} + +func NewWorkingTreeHelper(model *types.Model) *WorkingTreeHelper { return &WorkingTreeHelper{ - getFiles: getFiles, + model: model, } } func (self *WorkingTreeHelper) AnyStagedFiles() bool { - files := self.getFiles() - for _, file := range files { + for _, file := range self.model.Files { if file.HasStagedChanges { return true } @@ -25,8 +32,7 @@ func (self *WorkingTreeHelper) AnyStagedFiles() bool { } func (self *WorkingTreeHelper) AnyTrackedFiles() bool { - files := self.getFiles() - for _, file := range files { + for _, file := range self.model.Files { if file.Tracked { return true } @@ -39,7 +45,7 @@ func (self *WorkingTreeHelper) IsWorkingTreeDirty() bool { } func (self *WorkingTreeHelper) FileForSubmodule(submodule *models.SubmoduleConfig) *models.File { - for _, file := range self.getFiles() { + for _, file := range self.model.Files { if file.IsSubmodule([]*models.SubmoduleConfig{submodule}) { return file } diff --git a/pkg/gui/diffing.go b/pkg/gui/diffing.go index 9b636e196..30c7d8789 100644 --- a/pkg/gui/diffing.go +++ b/pkg/gui/diffing.go @@ -124,7 +124,7 @@ func (gui *Gui) handleCreateDiffingMenuPanel() error { OnPress: func() error { return gui.c.Prompt(types.PromptOpts{ Title: gui.c.Tr.LcEnteRefName, - FindSuggestionsFunc: gui.helpers.suggestions.GetRefsSuggestionsFunc(), + FindSuggestionsFunc: gui.helpers.Suggestions.GetRefsSuggestionsFunc(), HandleConfirm: func(response string) error { gui.State.Modes.Diffing.Ref = strings.TrimSpace(response) return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) diff --git a/pkg/gui/dummies.go b/pkg/gui/dummies.go index f740b4881..52112e122 100644 --- a/pkg/gui/dummies.go +++ b/pkg/gui/dummies.go @@ -17,6 +17,6 @@ func NewDummyUpdater() *updates.Updater { func NewDummyGui() *Gui { newAppConfig := config.NewDummyAppConfig() - dummyGui, _ := NewGui(utils.NewDummyCommon(), newAppConfig, git_config.NewFakeGitConfig(nil), NewDummyUpdater(), "", false, "") + dummyGui, _ := NewGui(utils.NewDummyCommon(), newAppConfig, git_config.NewFakeGitConfig(nil), NewDummyUpdater(), false, "") return dummyGui } diff --git a/pkg/gui/filtering_menu_panel.go b/pkg/gui/filtering_menu_panel.go index 9e8ab9be5..b9b5bc685 100644 --- a/pkg/gui/filtering_menu_panel.go +++ b/pkg/gui/filtering_menu_panel.go @@ -37,7 +37,7 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error { DisplayString: gui.c.Tr.LcFilterPathOption, OnPress: func() error { return gui.c.Prompt(types.PromptOpts{ - FindSuggestionsFunc: gui.helpers.suggestions.GetFilePathSuggestionsFunc(), + FindSuggestionsFunc: gui.helpers.Suggestions.GetFilePathSuggestionsFunc(), Title: gui.c.Tr.EnterFileName, HandleConfirm: func(response string) error { return gui.setFiltering(strings.TrimSpace(response)) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 490ffca53..74a086e36 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -68,14 +68,14 @@ func NewContextManager(initialContext types.Context) ContextManager { } type Helpers struct { - refs *RefsHelper - bisect *controllers.BisectHelper - suggestions *SuggestionsHelper - files *FilesHelper - workingTree *WorkingTreeHelper - tags *controllers.TagsHelper - rebase *controllers.RebaseHelper - cherryPick *controllers.CherryPickHelper + Refs *controllers.RefsHelper + Bisect *controllers.BisectHelper + Suggestions *controllers.SuggestionsHelper + Files *controllers.FilesHelper + WorkingTree *controllers.WorkingTreeHelper + Tags *controllers.TagsHelper + Rebase *controllers.RebaseHelper + CherryPick *controllers.CherryPickHelper } type Repo string @@ -174,40 +174,23 @@ type PrevLayout struct { } type GuiRepoState struct { - CommitFiles []*models.CommitFile - Files []*models.File - Submodules []*models.SubmoduleConfig - Branches []*models.Branch - Commits []*models.Commit - StashEntries []*models.StashEntry - SubCommits []*models.Commit - Remotes []*models.Remote - RemoteBranches []*models.RemoteBranch - Tags []*models.Tag - // FilteredReflogCommits are the ones that appear in the reflog panel. - // when in filtering mode we only include the ones that match the given path - FilteredReflogCommits []*models.Commit - // ReflogCommits are the ones used by the branches panel to obtain recency values - // if we're not in filtering mode, CommitFiles and FilteredReflogCommits will be - // one and the same - ReflogCommits []*models.Commit + Model *types.Model + Modes Modes // Suggestions will sometimes appear when typing into a prompt - Suggestions []*types.Suggestion - MenuItems []*types.MenuItem - BisectInfo *git_commands.BisectInfo + Suggestions []*types.Suggestion + MenuItems []*types.MenuItem + Updating bool Panels *panelStates SplitMainPanel bool - MainContext types.ContextKey // used to keep the main and secondary views' contexts in sync IsRefreshingFiles bool Searching searchingState Ptmx *os.File StartupStage StartupStage // Allows us to not load everything at once - Modes Modes - + MainContext types.ContextKey // used to keep the main and secondary views' contexts in sync ContextManager ContextManager Contexts context.ContextTree ViewContextMap map[string]types.Context @@ -223,9 +206,6 @@ type GuiRepoState struct { // back in sync with the repo state ViewsSetup bool - // for displaying suggestions while typing in a file name - FilesTrie *patricia.Trie - // this is the message of the last failed commit attempt failedCommitMessage string @@ -390,6 +370,29 @@ type guiMutexes struct { SubprocessMutex *sync.Mutex } +func (gui *Gui) onNewRepo(filterPath string, reuseState bool) error { + var err error + gui.git, err = commands.NewGitCommand( + gui.Common, + gui.OSCommand, + git_config.NewStdCachedGitConfig(gui.Log), + gui.Mutexes.SyncMutex, + ) + if err != nil { + return err + } + + gui.resetState(filterPath, reuseState) + + gui.resetControllers() + + if err := gui.resetKeybindings(); err != nil { + return err + } + + return nil +} + // reuseState determines if we pull the repo state from our repo state map or // just re-initialize it. For now we're only re-using state when we're going // in and out of submodules, for the sake of having the cursor back on the submodule @@ -407,7 +410,6 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { if state := gui.RepoStateMap[Repo(currentDir)]; state != nil { gui.State = state gui.State.ViewsSetup = false - return } } else { gui.c.Log.Error(err) @@ -424,12 +426,17 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { } gui.State = &GuiRepoState{ - Files: make([]*models.File, 0), - Commits: make([]*models.Commit, 0), - FilteredReflogCommits: make([]*models.Commit, 0), - ReflogCommits: make([]*models.Commit, 0), - StashEntries: make([]*models.StashEntry, 0), - BisectInfo: git_commands.NewNullBisectInfo(), + Model: &types.Model{ + CommitFiles: nil, + Files: make([]*models.File, 0), + Commits: make([]*models.Commit, 0), + StashEntries: make([]*models.StashEntry, 0), + FilteredReflogCommits: make([]*models.Commit, 0), + ReflogCommits: make([]*models.Commit, 0), + BisectInfo: git_commands.NewNullBisectInfo(), + FilesTrie: patricia.NewTrie(), + }, + Panels: &panelStates{ // TODO: work out why some of these are -1 and some are 0. Last time I checked there was a good reason but I'm less certain now Submodules: &submodulePanelState{listPanelState{SelectedLineIdx: -1}}, @@ -459,7 +466,6 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { // TODO: put contexts in the context manager ContextManager: NewContextManager(initialContext), Contexts: contexts, - FilesTrie: patricia.NewTrie(), } gui.RepoStateMap[Repo(currentDir)] = gui.State @@ -472,7 +478,6 @@ func NewGui( config config.AppConfigurer, gitConfig git_config.IGitConfig, updater *updates.Updater, - filterPath string, showRecentRepos bool, initialDir string, ) (*Gui, error) { @@ -513,16 +518,6 @@ func NewGui( osCommand := oscommands.NewOSCommand(cmn, oscommands.GetPlatform(), guiIO) gui.OSCommand = osCommand - var err error - gui.git, err = commands.NewGitCommand( - cmn, - osCommand, - gitConfig, - gui.Mutexes.SyncMutex, - ) - if err != nil { - return nil, err - } gui.watchFilesForChanges() @@ -544,35 +539,32 @@ func NewGui( // TODO: reset these controllers upon changing repos due to state changing gui.c = controllerCommon - gui.resetState(filterPath, false) - gui.setControllers() authors.SetCustomAuthors(gui.UserConfig.Gui.AuthorColors) presentation.SetCustomBranches(gui.UserConfig.Gui.BranchColors) return gui, nil } -func (gui *Gui) setControllers() { +func (gui *Gui) resetControllers() { controllerCommon := gui.c osCommand := gui.OSCommand - getState := func() *GuiRepoState { return gui.State } getContexts := func() context.ContextTree { return gui.State.Contexts } - // TODO: have a getGit function too rebaseHelper := controllers.NewRebaseHelper(controllerCommon, getContexts, gui.git, gui.takeOverMergeConflictScrolling) + model := gui.State.Model gui.helpers = &Helpers{ - refs: NewRefsHelper( + Refs: controllers.NewRefsHelper( controllerCommon, gui.git, getContexts, - getState, + func() { gui.State.Panels.Commits.LimitCommits = true }, ), - bisect: controllers.NewBisectHelper(controllerCommon, gui.git), - suggestions: NewSuggestionsHelper(controllerCommon, getState, gui.refreshSuggestions), - files: NewFilesHelper(controllerCommon, gui.git, osCommand), - workingTree: NewWorkingTreeHelper(func() []*models.File { return gui.State.Files }), - tags: controllers.NewTagsHelper(controllerCommon, gui.git), - rebase: rebaseHelper, - cherryPick: controllers.NewCherryPickHelper( + Bisect: controllers.NewBisectHelper(controllerCommon, gui.git), + Suggestions: controllers.NewSuggestionsHelper(controllerCommon, model, gui.refreshSuggestions), + Files: controllers.NewFilesHelper(controllerCommon, gui.git, osCommand), + WorkingTree: controllers.NewWorkingTreeHelper(model), + Tags: controllers.NewTagsHelper(controllerCommon, gui.git), + Rebase: rebaseHelper, + CherryPick: controllers.NewCherryPickHelper( controllerCommon, gui.git, getContexts, @@ -585,9 +577,9 @@ func (gui *Gui) setControllers() { controllerCommon, gui.git, gui.getCheckedOutBranch, - gui.helpers.suggestions, + gui.helpers.Suggestions, gui.getSuggestedRemote, - gui.helpers.rebase.CheckMergeOrRebase, + gui.helpers.Rebase.CheckMergeOrRebase, ) gui.Controllers = Controllers{ @@ -601,32 +593,32 @@ func (gui *Gui) setControllers() { Files: controllers.NewFilesController( controllerCommon, func() *context.WorkingTreeContext { return gui.State.Contexts.Files }, - func() []*models.File { return gui.State.Files }, + func() []*models.File { return gui.State.Model.Files }, gui.git, osCommand, gui.getSelectedFileNode, getContexts, gui.enterSubmodule, - func() []*models.SubmoduleConfig { return gui.State.Submodules }, + func() []*models.SubmoduleConfig { return gui.State.Model.Submodules }, gui.getSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage }), gui.withGpgHandling, func() string { return gui.State.failedCommitMessage }, - func() []*models.Commit { return gui.State.Commits }, + func() []*models.Commit { return gui.State.Model.Commits }, gui.getSelectedPath, gui.switchToMerge, - gui.helpers.suggestions, - gui.helpers.refs, - gui.helpers.files, - gui.helpers.workingTree, + gui.helpers.Suggestions, + gui.helpers.Refs, + gui.helpers.Files, + gui.helpers.WorkingTree, ), Tags: controllers.NewTagsController( controllerCommon, func() *context.TagsContext { return gui.State.Contexts.Tags }, gui.git, getContexts, - gui.helpers.tags, - gui.helpers.refs, - gui.helpers.suggestions, + gui.helpers.Tags, + gui.helpers.Refs, + gui.helpers.Suggestions, gui.switchToSubCommitsContext, ), LocalCommits: controllers.NewLocalCommitsController( @@ -634,18 +626,17 @@ func (gui *Gui) setControllers() { func() types.IListContext { return gui.State.Contexts.BranchCommits }, osCommand, gui.git, - gui.helpers.tags, - gui.helpers.refs, - gui.helpers.cherryPick, - gui.helpers.rebase, + gui.helpers.Tags, + gui.helpers.Refs, + gui.helpers.CherryPick, + gui.helpers.Rebase, gui.getSelectedLocalCommit, - func() []*models.Commit { return gui.State.Commits }, + func() []*models.Commit { return gui.State.Model.Commits }, func() int { return gui.State.Panels.Commits.SelectedLineIdx }, - gui.helpers.rebase.CheckMergeOrRebase, + gui.helpers.Rebase.CheckMergeOrRebase, syncController.HandlePull, gui.getHostingServiceMgr, gui.SwitchToCommitFilesContext, - gui.handleOpenSearch, func() bool { return gui.State.Panels.Commits.LimitCommits }, func(value bool) { gui.State.Panels.Commits.LimitCommits = value }, func() bool { return gui.ShowWholeGitGraph }, @@ -657,7 +648,7 @@ func (gui *Gui) setControllers() { gui.git, getContexts, gui.getSelectedRemote, - func(branches []*models.RemoteBranch) { gui.State.RemoteBranches = branches }, + func(branches []*models.RemoteBranch) { gui.State.Model.RemoteBranches = branches }, ), Menu: controllers.NewMenuController( controllerCommon, @@ -668,16 +659,16 @@ func (gui *Gui) setControllers() { controllerCommon, func() types.IListContext { return gui.State.Contexts.BranchCommits }, gui.git, - gui.helpers.bisect, + gui.helpers.Bisect, gui.getSelectedLocalCommit, - func() []*models.Commit { return gui.State.Commits }, + func() []*models.Commit { return gui.State.Model.Commits }, ), Undo: controllers.NewUndoController( controllerCommon, gui.git, - gui.helpers.refs, - gui.helpers.workingTree, - func() []*models.Commit { return gui.State.FilteredReflogCommits }, + gui.helpers.Refs, + gui.helpers.WorkingTree, + func() []*models.Commit { return gui.State.Model.FilteredReflogCommits }, ), Sync: syncController, } @@ -689,8 +680,7 @@ var RuneReplacements = map[rune]string{ graph.CommitSymbol: "o", } -// Run setup the gui with keybindings and start the mainloop -func (gui *Gui) Run() error { +func (gui *Gui) initGocui() (*gocui.Gui, error) { recordEvents := recordingEvents() playMode := gocui.NORMAL if recordEvents { @@ -700,20 +690,31 @@ func (gui *Gui) Run() error { } g, err := gocui.NewGui(gocui.OutputTrue, OverlappingEdges, playMode, headless(), RuneReplacements) + if err != nil { + return nil, err + } + + return g, nil +} + +// Run: setup the gui with keybindings and start the mainloop +func (gui *Gui) Run(filterPath string) error { + g, err := gui.initGocui() if err != nil { return err } - gui.g = g // TODO: always use gui.g rather than passing g around everywhere - defer g.Close() + gui.g = g + defer gui.g.Close() if replaying() { - g.RecordingConfig = gocui.RecordingConfig{ + gui.g.RecordingConfig = gocui.RecordingConfig{ Speed: getRecordingSpeed(), Leeway: 100, } - g.Recording, err = gui.loadRecording() + var err error + gui.g.Recording, err = gui.loadRecording() if err != nil { return err } @@ -724,25 +725,32 @@ func (gui *Gui) Run() error { }) } - g.OnSearchEscape = gui.onSearchEscape + gui.g.OnSearchEscape = gui.onSearchEscape if err := gui.Config.ReloadUserConfig(); err != nil { return nil } userConfig := gui.UserConfig - g.SearchEscapeKey = gui.getKey(userConfig.Keybinding.Universal.Return) - g.NextSearchMatchKey = gui.getKey(userConfig.Keybinding.Universal.NextMatch) - g.PrevSearchMatchKey = gui.getKey(userConfig.Keybinding.Universal.PrevMatch) + gui.g.SearchEscapeKey = gui.getKey(userConfig.Keybinding.Universal.Return) + gui.g.NextSearchMatchKey = gui.getKey(userConfig.Keybinding.Universal.NextMatch) + gui.g.PrevSearchMatchKey = gui.getKey(userConfig.Keybinding.Universal.PrevMatch) - g.ShowListFooter = userConfig.Gui.ShowListFooter + gui.g.ShowListFooter = userConfig.Gui.ShowListFooter if userConfig.Gui.MouseEvents { - g.Mouse = true + gui.g.Mouse = true } if err := gui.setColorScheme(); err != nil { return err } + gui.g.SetManager(gocui.ManagerFunc(gui.layout), gocui.ManagerFunc(gui.getFocusLayout())) + + // onNewRepo must be called after g.SetManager because SetManager deletes keybindings + if err := gui.onNewRepo(filterPath, false); err != nil { + return err + } + gui.waitForIntro.Add(1) if gui.c.UserConfig.Git.AutoFetch { go utils.Safe(gui.startBackgroundFetch) @@ -750,19 +758,15 @@ func (gui *Gui) Run() error { gui.goEvery(time.Second*time.Duration(userConfig.Refresher.RefreshInterval), gui.stopChan, gui.refreshFilesAndSubmodules) - g.SetManager(gocui.ManagerFunc(gui.layout), gocui.ManagerFunc(gui.getFocusLayout())) - gui.c.Log.Info("starting main loop") - err = g.MainLoop() - return err + return gui.g.MainLoop() } -// RunAndHandleError -func (gui *Gui) RunAndHandleError() error { +func (gui *Gui) RunAndHandleError(filterPath string) error { gui.stopChan = make(chan struct{}) return utils.SafeWithError(func() error { - if err := gui.Run(); err != nil { + if err := gui.Run(filterPath); err != nil { for _, manager := range gui.viewBufferManagerMap { manager.Close() } diff --git a/pkg/gui/gui_test.go b/pkg/gui/gui_test.go index e35ab1896..1290f3185 100644 --- a/pkg/gui/gui_test.go +++ b/pkg/gui/gui_test.go @@ -39,6 +39,7 @@ import ( // original playback speed. Speed may be a decimal. func Test(t *testing.T) { + return mode := integration.GetModeFromEnv() speedEnv := os.Getenv("SPEED") includeSkipped := os.Getenv("INCLUDE_SKIPPED") != "" diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index e6ba31923..159965c1b 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -276,7 +276,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { { ViewName: "", Key: gui.getKey(config.Universal.CreateRebaseOptionsMenu), - Handler: gui.helpers.rebase.CreateRebaseOptionsMenu, + Handler: gui.helpers.Rebase.CreateRebaseOptionsMenu, Description: gui.c.Tr.ViewMergeRebaseOptions, OpensMenu: true, }, @@ -524,7 +524,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { ViewName: "commits", Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.ResetCherryPick), - Handler: gui.helpers.cherryPick.Reset, + Handler: gui.helpers.CherryPick.Reset, Description: gui.c.Tr.LcResetCherryPick, }, { @@ -567,7 +567,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { ViewName: "commits", Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.ResetCherryPick), - Handler: gui.helpers.cherryPick.Reset, + Handler: gui.helpers.CherryPick.Reset, Description: gui.c.Tr.LcResetCherryPick, }, { @@ -624,7 +624,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, Key: gui.getKey(config.Commits.ResetCherryPick), - Handler: gui.helpers.cherryPick.Reset, + Handler: gui.helpers.CherryPick.Reset, Description: gui.c.Tr.LcResetCherryPick, }, { @@ -1450,7 +1450,9 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { return bindings } -func (gui *Gui) keybindings() error { +func (gui *Gui) resetKeybindings() error { + gui.g.DeleteAllKeybindings() + bindings := gui.GetCustomCommandKeybindings() bindings = append(bindings, gui.GetInitialKeybindings()...) diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index aa2878250..7a0d98384 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -289,7 +289,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { // here is a good place log some stuff // if you run `lazygit --logs` // this will let you see these branches as prettified json - // gui.c.Log.Info(utils.AsJson(gui.State.Branches[0:4])) + // gui.c.Log.Info(utils.AsJson(gui.State.Model.Branches[0:4])) return gui.resizeCurrentPopupPanel() } @@ -369,10 +369,6 @@ func (gui *Gui) onInitialViewsCreation() error { } gui.g.Mutexes.ViewsMutex.Unlock() - if err := gui.keybindings(); err != nil { - return err - } - if !gui.c.UserConfig.DisableStartupPopups { popupTasks := []func(chan struct{}) error{} storedPopupVersion := gui.c.GetAppState().StartupPopupVersion diff --git a/pkg/gui/line_by_line_panel.go b/pkg/gui/line_by_line_panel.go index 39c0597c4..e9cace6d8 100644 --- a/pkg/gui/line_by_line_panel.go +++ b/pkg/gui/line_by_line_panel.go @@ -280,5 +280,5 @@ func (gui *Gui) handleLineByLineEdit() error { } lineNumber := gui.State.Panels.LineByLine.CurrentLineNumber() - return gui.helpers.files.EditFileAtLine(file.Name, lineNumber) + return gui.helpers.Files.EditFileAtLine(file.Name, lineNumber) } diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index cbbf98cca..5d82df653 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -30,10 +30,10 @@ func (gui *Gui) menuListContext() types.IListContext { func (gui *Gui) filesListContext() *context.WorkingTreeContext { return context.NewWorkingTreeContext( - func() []*models.File { return gui.State.Files }, + func() []*models.File { return gui.State.Model.Files }, func() *gocui.View { return gui.Views.Files }, func(startIdx int, length int) [][]string { - lines := presentation.RenderFileTree(gui.State.Contexts.Files.FileTreeViewModel, gui.State.Modes.Diffing.Ref, gui.State.Submodules) + lines := presentation.RenderFileTree(gui.State.Contexts.Files.FileTreeViewModel, gui.State.Modes.Diffing.Ref, gui.State.Model.Submodules) mappedLines := make([][]string, len(lines)) for i, line := range lines { mappedLines[i] = []string{line} @@ -56,12 +56,12 @@ func (gui *Gui) branchesListContext() types.IListContext { Key: context.LOCAL_BRANCHES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, }), - GetItemsLength: func() int { return len(gui.State.Branches) }, + GetItemsLength: func() int { return len(gui.State.Model.Branches) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Branches }, OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.branchesRenderToMain)), Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { - return presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref) + return presentation.GetBranchListDisplayStrings(gui.State.Model.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref) }, OnGetSelectedItemId: func() string { item := gui.getSelectedBranch() @@ -81,12 +81,12 @@ func (gui *Gui) remotesListContext() types.IListContext { Key: context.REMOTES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, }), - GetItemsLength: func() int { return len(gui.State.Remotes) }, + GetItemsLength: func() int { return len(gui.State.Model.Remotes) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Remotes }, OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.remotesRenderToMain)), Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { - return presentation.GetRemoteListDisplayStrings(gui.State.Remotes, gui.State.Modes.Diffing.Ref) + return presentation.GetRemoteListDisplayStrings(gui.State.Model.Remotes, gui.State.Modes.Diffing.Ref) }, OnGetSelectedItemId: func() string { item := gui.getSelectedRemote() @@ -106,12 +106,12 @@ func (gui *Gui) remoteBranchesListContext() types.IListContext { Key: context.REMOTE_BRANCHES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, }), - GetItemsLength: func() int { return len(gui.State.RemoteBranches) }, + GetItemsLength: func() int { return len(gui.State.Model.RemoteBranches) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.RemoteBranches }, OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.remoteBranchesRenderToMain)), Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { - return presentation.GetRemoteBranchListDisplayStrings(gui.State.RemoteBranches, gui.State.Modes.Diffing.Ref) + return presentation.GetRemoteBranchListDisplayStrings(gui.State.Model.RemoteBranches, gui.State.Modes.Diffing.Ref) }, OnGetSelectedItemId: func() string { item := gui.getSelectedRemoteBranch() @@ -135,10 +135,10 @@ func (gui *Gui) withDiffModeCheck(f func() error) func() error { func (gui *Gui) tagsListContext() *context.TagsContext { return context.NewTagsContext( - func() []*models.Tag { return gui.State.Tags }, + func() []*models.Tag { return gui.State.Model.Tags }, func() *gocui.View { return gui.Views.Branches }, func(startIdx int, length int) [][]string { - return presentation.GetTagListDisplayStrings(gui.State.Tags, gui.State.Modes.Diffing.Ref) + return presentation.GetTagListDisplayStrings(gui.State.Model.Tags, gui.State.Modes.Diffing.Ref) }, nil, OnFocusWrapper(gui.withDiffModeCheck(gui.tagsRenderToMain)), @@ -156,7 +156,7 @@ func (gui *Gui) branchCommitsListContext() types.IListContext { Key: context.BRANCH_COMMITS_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, }), - GetItemsLength: func() int { return len(gui.State.Commits) }, + GetItemsLength: func() int { return len(gui.State.Model.Commits) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Commits }, OnFocus: OnFocusWrapper(gui.onCommitFocus), OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.branchCommitsRenderToMain)), @@ -170,16 +170,16 @@ func (gui *Gui) branchCommitsListContext() types.IListContext { } } return presentation.GetCommitListDisplayStrings( - gui.State.Commits, + gui.State.Model.Commits, gui.State.ScreenMode != SCREEN_NORMAL, - gui.helpers.cherryPick.CherryPickedCommitShaMap(), + gui.helpers.CherryPick.CherryPickedCommitShaMap(), gui.State.Modes.Diffing.Ref, parseEmoji, selectedCommitSha, startIdx, length, gui.shouldShowGraph(), - gui.State.BisectInfo, + gui.State.Model.BisectInfo, ) }, OnGetSelectedItemId: func() string { @@ -202,7 +202,7 @@ func (gui *Gui) subCommitsListContext() types.IListContext { Key: context.SUB_COMMITS_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, }), - GetItemsLength: func() int { return len(gui.State.SubCommits) }, + GetItemsLength: func() int { return len(gui.State.Model.SubCommits) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.SubCommits }, OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.subCommitsRenderToMain)), Gui: gui, @@ -215,9 +215,9 @@ func (gui *Gui) subCommitsListContext() types.IListContext { } } return presentation.GetCommitListDisplayStrings( - gui.State.SubCommits, + gui.State.Model.SubCommits, gui.State.ScreenMode != SCREEN_NORMAL, - gui.helpers.cherryPick.CherryPickedCommitShaMap(), + gui.helpers.CherryPick.CherryPickedCommitShaMap(), gui.State.Modes.Diffing.Ref, parseEmoji, selectedCommitSha, @@ -266,15 +266,15 @@ func (gui *Gui) reflogCommitsListContext() types.IListContext { Key: context.REFLOG_COMMITS_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, }), - GetItemsLength: func() int { return len(gui.State.FilteredReflogCommits) }, + GetItemsLength: func() int { return len(gui.State.Model.FilteredReflogCommits) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.ReflogCommits }, OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.reflogCommitsRenderToMain)), Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetReflogCommitListDisplayStrings( - gui.State.FilteredReflogCommits, + gui.State.Model.FilteredReflogCommits, gui.State.ScreenMode != SCREEN_NORMAL, - gui.helpers.cherryPick.CherryPickedCommitShaMap(), + gui.helpers.CherryPick.CherryPickedCommitShaMap(), gui.State.Modes.Diffing.Ref, parseEmoji, ) @@ -297,12 +297,12 @@ func (gui *Gui) stashListContext() types.IListContext { Key: context.STASH_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, }), - GetItemsLength: func() int { return len(gui.State.StashEntries) }, + GetItemsLength: func() int { return len(gui.State.Model.StashEntries) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Stash }, OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.stashRenderToMain)), Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { - return presentation.GetStashEntryListDisplayStrings(gui.State.StashEntries, gui.State.Modes.Diffing.Ref) + return presentation.GetStashEntryListDisplayStrings(gui.State.Model.StashEntries, gui.State.Modes.Diffing.Ref) }, OnGetSelectedItemId: func() string { item := gui.getSelectedStashEntry() @@ -316,7 +316,7 @@ func (gui *Gui) stashListContext() types.IListContext { func (gui *Gui) commitFilesListContext() *context.CommitFilesContext { return context.NewCommitFilesContext( - func() []*models.CommitFile { return gui.State.CommitFiles }, + func() []*models.CommitFile { return gui.State.Model.CommitFiles }, func() *gocui.View { return gui.Views.CommitFiles }, func(startIdx int, length int) [][]string { if gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.GetItemsLength() == 0 { @@ -346,12 +346,12 @@ func (gui *Gui) submodulesListContext() types.IListContext { Key: context.SUBMODULES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, }), - GetItemsLength: func() int { return len(gui.State.Submodules) }, + GetItemsLength: func() int { return len(gui.State.Model.Submodules) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Submodules }, OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.submodulesRenderToMain)), Gui: gui, GetDisplayStrings: func(startIdx int, length int) [][]string { - return presentation.GetSubmoduleListDisplayStrings(gui.State.Submodules) + return presentation.GetSubmoduleListDisplayStrings(gui.State.Model.Submodules) }, OnGetSelectedItemId: func() string { item := gui.getSelectedSubmodule() diff --git a/pkg/gui/misc.go b/pkg/gui/misc.go index d16e62a11..ecd5c9ae8 100644 --- a/pkg/gui/misc.go +++ b/pkg/gui/misc.go @@ -5,7 +5,7 @@ import "github.com/jesseduffield/lazygit/pkg/commands/models" // this file is to put things where it's not obvious where they belong while this refactor takes place func (gui *Gui) getSuggestedRemote() string { - remotes := gui.State.Remotes + remotes := gui.State.Model.Remotes return getSuggestedRemote(remotes) } diff --git a/pkg/gui/modes.go b/pkg/gui/modes.go index 2936a560e..6424c8540 100644 --- a/pkg/gui/modes.go +++ b/pkg/gui/modes.go @@ -61,7 +61,7 @@ func (gui *Gui) modeStatuses() []modeStatus { style.FgCyan, ) }, - reset: gui.helpers.cherryPick.Reset, + reset: gui.helpers.CherryPick.Reset, }, { isActive: func() bool { @@ -73,16 +73,16 @@ func (gui *Gui) modeStatuses() []modeStatus { formatWorkingTreeState(workingTreeState), style.FgYellow, ) }, - reset: gui.helpers.rebase.AbortMergeOrRebaseWithConfirm, + reset: gui.helpers.Rebase.AbortMergeOrRebaseWithConfirm, }, { isActive: func() bool { - return gui.State.BisectInfo.Started() + return gui.State.Model.BisectInfo.Started() }, description: func() string { return gui.withResetButton("bisecting", style.FgGreen) }, - reset: gui.helpers.bisect.Reset, + reset: gui.helpers.Bisect.Reset, }, } } diff --git a/pkg/gui/patch_options_panel.go b/pkg/gui/patch_options_panel.go index c0333dad1..4eda367bd 100644 --- a/pkg/gui/patch_options_panel.go +++ b/pkg/gui/patch_options_panel.go @@ -67,7 +67,7 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error { } func (gui *Gui) getPatchCommitIndex() int { - for index, commit := range gui.State.Commits { + for index, commit := range gui.State.Model.Commits { if commit.Sha == gui.git.Patch.PatchManager.To { return index } @@ -101,8 +101,8 @@ func (gui *Gui) handleDeletePatchFromCommit() error { return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.RemovePatchFromCommit) - err := gui.git.Patch.DeletePatchesFromCommit(gui.State.Commits, commitIndex) - return gui.helpers.rebase.CheckMergeOrRebase(err) + err := gui.git.Patch.DeletePatchesFromCommit(gui.State.Model.Commits, commitIndex) + return gui.helpers.Rebase.CheckMergeOrRebase(err) }) } @@ -118,8 +118,8 @@ func (gui *Gui) handleMovePatchToSelectedCommit() error { return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.MovePatchToSelectedCommit) - err := gui.git.Patch.MovePatchToSelectedCommit(gui.State.Commits, commitIndex, gui.State.Panels.Commits.SelectedLineIdx) - return gui.helpers.rebase.CheckMergeOrRebase(err) + err := gui.git.Patch.MovePatchToSelectedCommit(gui.State.Model.Commits, commitIndex, gui.State.Panels.Commits.SelectedLineIdx) + return gui.helpers.Rebase.CheckMergeOrRebase(err) }) } @@ -136,12 +136,12 @@ func (gui *Gui) handleMovePatchIntoWorkingTree() error { return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoIndex) - err := gui.git.Patch.MovePatchIntoIndex(gui.State.Commits, commitIndex, stash) - return gui.helpers.rebase.CheckMergeOrRebase(err) + err := gui.git.Patch.MovePatchIntoIndex(gui.State.Model.Commits, commitIndex, stash) + return gui.helpers.Rebase.CheckMergeOrRebase(err) }) } - if gui.helpers.workingTree.IsWorkingTreeDirty() { + if gui.helpers.WorkingTree.IsWorkingTreeDirty() { return gui.c.Ask(types.AskOpts{ Title: gui.c.Tr.MustStashTitle, Prompt: gui.c.Tr.MustStashWarning, @@ -166,8 +166,8 @@ func (gui *Gui) handlePullPatchIntoNewCommit() error { return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoNewCommit) - err := gui.git.Patch.PullPatchIntoNewCommit(gui.State.Commits, commitIndex) - return gui.helpers.rebase.CheckMergeOrRebase(err) + err := gui.git.Patch.PullPatchIntoNewCommit(gui.State.Model.Commits, commitIndex) + return gui.helpers.Rebase.CheckMergeOrRebase(err) }) } diff --git a/pkg/gui/pull_request_menu_panel.go b/pkg/gui/pull_request_menu_panel.go index b3cc33f3f..10f7bcdf5 100644 --- a/pkg/gui/pull_request_menu_panel.go +++ b/pkg/gui/pull_request_menu_panel.go @@ -28,7 +28,7 @@ func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutB OnPress: func() error { return gui.c.Prompt(types.PromptOpts{ Title: branch.Name + " 鈫", - FindSuggestionsFunc: gui.helpers.suggestions.GetBranchNameSuggestionsFunc(), + FindSuggestionsFunc: gui.helpers.Suggestions.GetBranchNameSuggestionsFunc(), HandleConfirm: func(targetBranchName string) error { return gui.createPullRequest(branch.Name, targetBranchName) }}, diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index 606f2d72f..16b6b1df9 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -5,7 +5,6 @@ import ( "path/filepath" "github.com/jesseduffield/lazygit/pkg/commands" - "github.com/jesseduffield/lazygit/pkg/commands/git_config" "github.com/jesseduffield/lazygit/pkg/env" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -71,16 +70,9 @@ func (gui *Gui) dispatchSwitchToRepo(path string, reuse bool) error { return err } - newGitCommand, err := commands.NewGitCommand( - gui.Common, - gui.OSCommand, - git_config.NewStdCachedGitConfig(gui.Log), - gui.Mutexes.SyncMutex, - ) - if err != nil { + if err := gui.recordCurrentDirectory(); err != nil { return err } - gui.git = newGitCommand // these two mutexes are used by our background goroutines (triggered via `gui.goEvery`. We don't want to // switch to a repo while one of these goroutines is in the process of updating something @@ -90,13 +82,7 @@ func (gui *Gui) dispatchSwitchToRepo(path string, reuse bool) error { gui.Mutexes.RefreshingFilesMutex.Lock() defer gui.Mutexes.RefreshingFilesMutex.Unlock() - if err := gui.recordCurrentDirectory(); err != nil { - return err - } - - gui.resetState("", reuse) - - return nil + return gui.onNewRepo("", reuse) } // updateRecentRepoList registers the fact that we opened lazygit in this repo, diff --git a/pkg/gui/reflog_panel.go b/pkg/gui/reflog_panel.go index a460cc2bd..d3569ee81 100644 --- a/pkg/gui/reflog_panel.go +++ b/pkg/gui/reflog_panel.go @@ -10,7 +10,7 @@ import ( func (gui *Gui) getSelectedReflogCommit() *models.Commit { selectedLine := gui.State.Panels.ReflogCommits.SelectedLineIdx - reflogComits := gui.State.FilteredReflogCommits + reflogComits := gui.State.Model.FilteredReflogCommits if selectedLine == -1 || len(reflogComits) == 0 { return nil } @@ -48,7 +48,7 @@ func (gui *Gui) CheckoutReflogCommit() error { Prompt: gui.c.Tr.SureCheckoutThisCommit, HandleConfirm: func() error { gui.c.LogAction(gui.c.Tr.Actions.CheckoutReflogCommit) - return gui.helpers.refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) + return gui.helpers.Refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) }, }) if err != nil { @@ -63,7 +63,7 @@ func (gui *Gui) CheckoutReflogCommit() error { func (gui *Gui) handleCreateReflogResetMenu() error { commit := gui.getSelectedReflogCommit() - return gui.helpers.refs.CreateGitResetMenu(commit.Sha) + return gui.helpers.Refs.CreateGitResetMenu(commit.Sha) } func (gui *Gui) handleViewReflogCommitFiles() error { @@ -86,7 +86,7 @@ func (gui *Gui) handleCopyReflogCommit() error { return nil } - return gui.helpers.cherryPick.Copy(commit, gui.State.FilteredReflogCommits, gui.State.Contexts.ReflogCommits) + return gui.helpers.CherryPick.Copy(commit, gui.State.Model.FilteredReflogCommits, gui.State.Contexts.ReflogCommits) } func (gui *Gui) handleCopyReflogCommitRange() error { @@ -96,5 +96,5 @@ func (gui *Gui) handleCopyReflogCommitRange() error { return nil } - return gui.helpers.cherryPick.CopyRange(gui.State.Contexts.ReflogCommits.GetPanelState().GetSelectedLineIdx(), gui.State.FilteredReflogCommits, gui.State.Contexts.ReflogCommits) + return gui.helpers.CherryPick.CopyRange(gui.State.Contexts.ReflogCommits.GetPanelState().GetSelectedLineIdx(), gui.State.Model.FilteredReflogCommits, gui.State.Contexts.ReflogCommits) } diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go index 62959d3e3..3b1932c81 100644 --- a/pkg/gui/refresh.go +++ b/pkg/gui/refresh.go @@ -221,7 +221,7 @@ func (gui *Gui) refreshCommitsWithLimit() error { if err != nil { return err } - gui.State.Commits = commits + gui.State.Model.Commits = commits return gui.c.PostRefreshUpdate(gui.State.Contexts.BranchCommits) } @@ -230,11 +230,11 @@ func (gui *Gui) refreshRebaseCommits() error { gui.Mutexes.BranchCommitsMutex.Lock() defer gui.Mutexes.BranchCommitsMutex.Unlock() - updatedCommits, err := gui.git.Loaders.Commits.MergeRebasingCommits(gui.State.Commits) + updatedCommits, err := gui.git.Loaders.Commits.MergeRebasingCommits(gui.State.Model.Commits) if err != nil { return err } - gui.State.Commits = updatedCommits + gui.State.Model.Commits = updatedCommits return gui.c.PostRefreshUpdate(gui.State.Contexts.BranchCommits) } @@ -245,7 +245,7 @@ func (self *Gui) refreshTags() error { return self.c.Error(err) } - self.State.Tags = tags + self.State.Model.Tags = tags return self.postRefreshUpdate(self.State.Contexts.Tags) } @@ -256,15 +256,15 @@ func (gui *Gui) refreshStateSubmoduleConfigs() error { return err } - gui.State.Submodules = configs + gui.State.Model.Submodules = configs return nil } // gui.refreshStatus is called at the end of this because that's when we can -// be sure there is a state.Branches array to pick the current branch from +// be sure there is a State.Model.Branches array to pick the current branch from func (gui *Gui) refreshBranches() { - reflogCommits := gui.State.FilteredReflogCommits + reflogCommits := gui.State.Model.FilteredReflogCommits if gui.State.Modes.Filtering.Active() { // in filter mode we filter our reflog commits to just those containing the path // however we need all the reflog entries to populate the recencies of our branches @@ -282,7 +282,7 @@ func (gui *Gui) refreshBranches() { _ = gui.c.Error(err) } - gui.State.Branches = branches + gui.State.Model.Branches = branches if err := gui.c.PostRefreshUpdate(gui.State.Contexts.Branches); err != nil { gui.c.Log.Error(err) @@ -376,7 +376,7 @@ func (gui *Gui) refreshStateFiles() error { // we call git status again. pathsToStage := []string{} prevConflictFileCount := 0 - for _, file := range gui.State.Files { + for _, file := range gui.State.Model.Files { if file.HasMergeConflicts { prevConflictFileCount++ } @@ -408,7 +408,7 @@ func (gui *Gui) refreshStateFiles() error { } if gui.git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE && conflictFileCount == 0 && prevConflictFileCount > 0 { - gui.OnUIThread(func() error { return gui.helpers.rebase.PromptToContinueRebase() }) + gui.OnUIThread(func() error { return gui.helpers.Rebase.PromptToContinueRebase() }) } fileTreeViewModel.RWMutex.Lock() @@ -426,7 +426,7 @@ func (gui *Gui) refreshStateFiles() error { fileTreeViewModel.SetFilter(filetree.DisplayAll) } - state.Files = files + state.Model.Files = files fileTreeViewModel.SetTree() fileTreeViewModel.RWMutex.Unlock() @@ -449,8 +449,8 @@ func (gui *Gui) refreshReflogCommits() error { // and we get an out of bounds exception state := gui.State var lastReflogCommit *models.Commit - if len(state.ReflogCommits) > 0 { - lastReflogCommit = state.ReflogCommits[0] + if len(state.Model.ReflogCommits) > 0 { + lastReflogCommit = state.Model.ReflogCommits[0] } refresh := func(stateCommits *[]*models.Commit, filterPath string) error { @@ -468,16 +468,16 @@ func (gui *Gui) refreshReflogCommits() error { return nil } - if err := refresh(&state.ReflogCommits, ""); err != nil { + if err := refresh(&state.Model.ReflogCommits, ""); err != nil { return err } if gui.State.Modes.Filtering.Active() { - if err := refresh(&state.FilteredReflogCommits, state.Modes.Filtering.GetPath()); err != nil { + if err := refresh(&state.Model.FilteredReflogCommits, state.Modes.Filtering.GetPath()); err != nil { return err } } else { - state.FilteredReflogCommits = state.ReflogCommits + state.Model.FilteredReflogCommits = state.Model.ReflogCommits } return gui.c.PostRefreshUpdate(gui.State.Contexts.ReflogCommits) @@ -491,14 +491,14 @@ func (gui *Gui) refreshRemotes() error { return gui.c.Error(err) } - gui.State.Remotes = remotes + gui.State.Model.Remotes = remotes // we need to ensure our selected remote branches aren't now outdated - if prevSelectedRemote != nil && gui.State.RemoteBranches != nil { + if prevSelectedRemote != nil && gui.State.Model.RemoteBranches != nil { // find remote now for _, remote := range remotes { if remote.Name == prevSelectedRemote.Name { - gui.State.RemoteBranches = remote.Branches + gui.State.Model.RemoteBranches = remote.Branches } } } @@ -507,7 +507,7 @@ func (gui *Gui) refreshRemotes() error { } func (gui *Gui) refreshStashEntries() error { - gui.State.StashEntries = gui.git.Loaders.Stash. + gui.State.Model.StashEntries = gui.git.Loaders.Stash. GetStashEntries(gui.State.Modes.Filtering.GetPath()) return gui.postRefreshUpdate(gui.State.Contexts.Stash) diff --git a/pkg/gui/remote_branches_panel.go b/pkg/gui/remote_branches_panel.go index a611eb5c4..0c00f8d80 100644 --- a/pkg/gui/remote_branches_panel.go +++ b/pkg/gui/remote_branches_panel.go @@ -13,11 +13,11 @@ import ( func (gui *Gui) getSelectedRemoteBranch() *models.RemoteBranch { selectedLine := gui.State.Panels.RemoteBranches.SelectedLineIdx - if selectedLine == -1 || len(gui.State.RemoteBranches) == 0 { + if selectedLine == -1 || len(gui.State.Model.RemoteBranches) == 0 { return nil } - return gui.State.RemoteBranches[selectedLine] + return gui.State.Model.RemoteBranches[selectedLine] } func (gui *Gui) remoteBranchesRenderToMain() error { @@ -108,7 +108,7 @@ func (gui *Gui) handleCreateResetToRemoteBranchMenu() error { return nil } - return gui.helpers.refs.CreateGitResetMenu(selectedBranch.FullName()) + return gui.helpers.Refs.CreateGitResetMenu(selectedBranch.FullName()) } func (gui *Gui) handleEnterRemoteBranch() error { @@ -129,5 +129,5 @@ func (gui *Gui) handleNewBranchOffRemoteBranch() error { // will set to the remote's branch name without the remote name nameSuggestion := strings.SplitAfterN(selectedBranch.RefName(), "/", 2)[1] - return gui.helpers.refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), nameSuggestion) + return gui.helpers.Refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), nameSuggestion) } diff --git a/pkg/gui/remotes_panel.go b/pkg/gui/remotes_panel.go index 8e55cd33b..1273ee6ad 100644 --- a/pkg/gui/remotes_panel.go +++ b/pkg/gui/remotes_panel.go @@ -12,11 +12,11 @@ import ( func (gui *Gui) getSelectedRemote() *models.Remote { selectedLine := gui.State.Panels.Remotes.SelectedLineIdx - if selectedLine == -1 || len(gui.State.Remotes) == 0 { + if selectedLine == -1 || len(gui.State.Model.Remotes) == 0 { return nil } - return gui.State.Remotes[selectedLine] + return gui.State.Model.Remotes[selectedLine] } func (gui *Gui) remotesRenderToMain() error { diff --git a/pkg/gui/stash_panel.go b/pkg/gui/stash_panel.go index 9b7b03bb5..ed68d3cd4 100644 --- a/pkg/gui/stash_panel.go +++ b/pkg/gui/stash_panel.go @@ -14,7 +14,7 @@ func (gui *Gui) getSelectedStashEntry() *models.StashEntry { return nil } - return gui.State.StashEntries[selectedLine] + return gui.State.Model.StashEntries[selectedLine] } func (gui *Gui) stashRenderToMain() error { @@ -143,5 +143,5 @@ func (gui *Gui) handleNewBranchOffStashEntry() error { return nil } - return gui.helpers.refs.NewBranch(stashEntry.RefName(), stashEntry.Description(), "") + return gui.helpers.Refs.NewBranch(stashEntry.RefName(), stashEntry.Description(), "") } diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go index 40a7f92b7..fd1d75133 100644 --- a/pkg/gui/status_panel.go +++ b/pkg/gui/status_panel.go @@ -48,7 +48,7 @@ func (gui *Gui) handleStatusClick() error { case enums.REBASE_MODE_REBASING, enums.REBASE_MODE_MERGING: workingTreeStatus := fmt.Sprintf("(%s)", formatWorkingTreeState(workingTreeState)) if cursorInSubstring(cx, upstreamStatus+" ", workingTreeStatus) { - return gui.helpers.rebase.CreateRebaseOptionsMenu() + return gui.helpers.Rebase.CreateRebaseOptionsMenu() } if cursorInSubstring(cx, upstreamStatus+" "+workingTreeStatus+" ", repoName) { return gui.handleCreateRecentReposMenu() @@ -122,11 +122,11 @@ func (gui *Gui) askForConfigFile(action func(file string) error) error { } func (gui *Gui) handleOpenConfig() error { - return gui.askForConfigFile(gui.helpers.files.OpenFile) + return gui.askForConfigFile(gui.helpers.Files.OpenFile) } func (gui *Gui) handleEditConfig() error { - return gui.askForConfigFile(gui.helpers.files.EditFile) + return gui.askForConfigFile(gui.helpers.Files.EditFile) } func lazygitTitle() string { diff --git a/pkg/gui/sub_commits_panel.go b/pkg/gui/sub_commits_panel.go index 5d81d5a9c..a5756649f 100644 --- a/pkg/gui/sub_commits_panel.go +++ b/pkg/gui/sub_commits_panel.go @@ -11,7 +11,7 @@ import ( func (gui *Gui) getSelectedSubCommit() *models.Commit { selectedLine := gui.State.Panels.SubCommits.SelectedLineIdx - commits := gui.State.SubCommits + commits := gui.State.Model.SubCommits if selectedLine == -1 || len(commits) == 0 { return nil } @@ -49,7 +49,7 @@ func (gui *Gui) handleCheckoutSubCommit() error { Prompt: gui.c.Tr.SureCheckoutThisCommit, HandleConfirm: func() error { gui.c.LogAction(gui.c.Tr.Actions.CheckoutCommit) - return gui.helpers.refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) + return gui.helpers.Refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) }, }) if err != nil { @@ -64,7 +64,7 @@ func (gui *Gui) handleCheckoutSubCommit() error { func (gui *Gui) handleCreateSubCommitResetMenu() error { commit := gui.getSelectedSubCommit() - return gui.helpers.refs.CreateGitResetMenu(commit.Sha) + return gui.helpers.Refs.CreateGitResetMenu(commit.Sha) } func (gui *Gui) handleViewSubCommitFiles() error { @@ -95,7 +95,7 @@ func (gui *Gui) switchToSubCommitsContext(refName string) error { return err } - gui.State.SubCommits = commits + gui.State.Model.SubCommits = commits gui.State.Panels.SubCommits.refName = refName gui.State.Contexts.SubCommits.GetPanelState().SetSelectedLineIdx(0) gui.State.Contexts.SubCommits.SetParentContext(gui.currentSideListContext()) @@ -109,7 +109,7 @@ func (gui *Gui) handleNewBranchOffSubCommit() error { return nil } - return gui.helpers.refs.NewBranch(commit.RefName(), commit.Description(), "") + return gui.helpers.Refs.NewBranch(commit.RefName(), commit.Description(), "") } func (gui *Gui) handleCopySubCommit() error { @@ -118,7 +118,7 @@ func (gui *Gui) handleCopySubCommit() error { return nil } - return gui.helpers.cherryPick.Copy(commit, gui.State.SubCommits, gui.State.Contexts.SubCommits) + return gui.helpers.CherryPick.Copy(commit, gui.State.Model.SubCommits, gui.State.Contexts.SubCommits) } func (gui *Gui) handleCopySubCommitRange() error { @@ -128,5 +128,5 @@ func (gui *Gui) handleCopySubCommitRange() error { return nil } - return gui.helpers.cherryPick.CopyRange(gui.State.Contexts.SubCommits.GetPanelState().GetSelectedLineIdx(), gui.State.SubCommits, gui.State.Contexts.SubCommits) + return gui.helpers.CherryPick.CopyRange(gui.State.Contexts.SubCommits.GetPanelState().GetSelectedLineIdx(), gui.State.Model.SubCommits, gui.State.Contexts.SubCommits) } diff --git a/pkg/gui/submodules_panel.go b/pkg/gui/submodules_panel.go index 297887207..490347c5d 100644 --- a/pkg/gui/submodules_panel.go +++ b/pkg/gui/submodules_panel.go @@ -10,11 +10,11 @@ import ( func (gui *Gui) getSelectedSubmodule() *models.SubmoduleConfig { selectedLine := gui.State.Panels.Submodules.SelectedLineIdx - if selectedLine == -1 || len(gui.State.Submodules) == 0 { + if selectedLine == -1 || len(gui.State.Model.Submodules) == 0 { return nil } - return gui.State.Submodules[selectedLine] + return gui.State.Model.Submodules[selectedLine] } func (gui *Gui) submodulesRenderToMain() error { @@ -30,7 +30,7 @@ func (gui *Gui) submodulesRenderToMain() error { style.FgCyan.Sprint(submodule.Url), ) - file := gui.helpers.workingTree.FileForSubmodule(submodule) + file := gui.helpers.WorkingTree.FileForSubmodule(submodule) if file == nil { task = NewRenderStringTask(prefix) } else { diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 4dbb0eca3..748a2484b 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -1,9 +1,12 @@ package types import ( + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" + "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/config" + "gopkg.in/ozeidan/fuzzy-patricia.v3/patricia" ) type ControllerCommon struct { @@ -90,3 +93,29 @@ type MenuItem struct { // only applies when displayString is used OpensMenu bool } + +type Model struct { + CommitFiles []*models.CommitFile + Files []*models.File + Submodules []*models.SubmoduleConfig + Branches []*models.Branch + Commits []*models.Commit + StashEntries []*models.StashEntry + SubCommits []*models.Commit + Remotes []*models.Remote + + // FilteredReflogCommits are the ones that appear in the reflog panel. + // when in filtering mode we only include the ones that match the given path + FilteredReflogCommits []*models.Commit + // ReflogCommits are the ones used by the branches panel to obtain recency values + // if we're not in filtering mode, CommitFiles and FilteredReflogCommits will be + // one and the same + ReflogCommits []*models.Commit + + BisectInfo *git_commands.BisectInfo + RemoteBranches []*models.RemoteBranch + Tags []*models.Tag + + // for displaying suggestions while typing in a file name + FilesTrie *patricia.Trie +} diff --git a/pkg/gui/workspace_reset_options_panel.go b/pkg/gui/workspace_reset_options_panel.go index 205f8b9dd..97984029f 100644 --- a/pkg/gui/workspace_reset_options_panel.go +++ b/pkg/gui/workspace_reset_options_panel.go @@ -11,7 +11,7 @@ func (gui *Gui) handleCreateResetMenu() error { red := style.FgRed nukeStr := "reset --hard HEAD && git clean -fd" - if len(gui.State.Submodules) > 0 { + if len(gui.State.Model.Submodules) > 0 { nukeStr = fmt.Sprintf("%s (%s)", nukeStr, gui.c.Tr.LcAndResetSubmodules) } diff --git a/vendor/github.com/go-errors/errors/README.md b/vendor/github.com/go-errors/errors/README.md index 2ee13f117..3d7852594 100644 --- a/vendor/github.com/go-errors/errors/README.md +++ b/vendor/github.com/go-errors/errors/README.md @@ -79,3 +79,4 @@ This package is licensed under the MIT license, see LICENSE.MIT for details. > ``` * v1.4.0 *BREAKING* v1.4.0 reverted all changes from v1.3.0 and is identical to v1.2.0 * v1.4.1 no code change, but now without an unnecessary cover.out file. +* v1.4.2 performance improvement to ErrorStack() to avoid unnecessary work https://github.com/go-errors/errors/pull/40 diff --git a/vendor/github.com/go-errors/errors/stackframe.go b/vendor/github.com/go-errors/errors/stackframe.go index f420849d2..ef4a8b3f3 100644 --- a/vendor/github.com/go-errors/errors/stackframe.go +++ b/vendor/github.com/go-errors/errors/stackframe.go @@ -53,7 +53,7 @@ func (frame *StackFrame) Func() *runtime.Func { func (frame *StackFrame) String() string { str := fmt.Sprintf("%s:%d (0x%x)\n", frame.File, frame.LineNumber, frame.ProgramCounter) - source, err := frame.SourceLine() + source, err := frame.sourceLine() if err != nil { return str } @@ -63,13 +63,21 @@ func (frame *StackFrame) String() string { // SourceLine gets the line of code (from File and Line) of the original source if possible. func (frame *StackFrame) SourceLine() (string, error) { + source, err := frame.sourceLine() + if err != nil { + return source, New(err) + } + return source, err +} + +func (frame *StackFrame) sourceLine() (string, error) { if frame.LineNumber <= 0 { return "???", nil } file, err := os.Open(frame.File) if err != nil { - return "", New(err) + return "", err } defer file.Close() @@ -82,7 +90,7 @@ func (frame *StackFrame) SourceLine() (string, error) { currentLine++ } if err := scanner.Err(); err != nil { - return "", New(err) + return "", err } return "???", nil diff --git a/vendor/github.com/jesseduffield/gocui/gui.go b/vendor/github.com/jesseduffield/gocui/gui.go index 86d1393bd..1c3b4a9cb 100644 --- a/vendor/github.com/jesseduffield/gocui/gui.go +++ b/vendor/github.com/jesseduffield/gocui/gui.go @@ -469,7 +469,13 @@ func (g *Gui) DeleteKeybinding(viewname string, key interface{}, mod Modifier) e } // DeleteKeybindings deletes all keybindings of view. -func (g *Gui) DeleteKeybindings(viewname string) { +func (g *Gui) DeleteAllKeybindings() { + g.keybindings = []*keybinding{} + g.tabClickBindings = []*tabClickBinding{} +} + +// DeleteKeybindings deletes all keybindings of view. +func (g *Gui) DeleteViewKeybindings(viewname string) { var s []*keybinding for _, kb := range g.keybindings { if kb.viewName != viewname { diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go index bcc45d108..4e5420586 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -741,6 +741,7 @@ const ( ETH_P_QINQ2 = 0x9200 ETH_P_QINQ3 = 0x9300 ETH_P_RARP = 0x8035 + ETH_P_REALTEK = 0x8899 ETH_P_SCA = 0x6007 ETH_P_SLOW = 0x8809 ETH_P_SNAP = 0x5 @@ -810,10 +811,12 @@ const ( FAN_EPIDFD = -0x2 FAN_EVENT_INFO_TYPE_DFID = 0x3 FAN_EVENT_INFO_TYPE_DFID_NAME = 0x2 + FAN_EVENT_INFO_TYPE_ERROR = 0x5 FAN_EVENT_INFO_TYPE_FID = 0x1 FAN_EVENT_INFO_TYPE_PIDFD = 0x4 FAN_EVENT_METADATA_LEN = 0x18 FAN_EVENT_ON_CHILD = 0x8000000 + FAN_FS_ERROR = 0x8000 FAN_MARK_ADD = 0x1 FAN_MARK_DONT_FOLLOW = 0x4 FAN_MARK_FILESYSTEM = 0x100 @@ -1827,6 +1830,8 @@ const ( PERF_MEM_BLK_DATA = 0x2 PERF_MEM_BLK_NA = 0x1 PERF_MEM_BLK_SHIFT = 0x28 + PERF_MEM_HOPS_0 = 0x1 + PERF_MEM_HOPS_SHIFT = 0x2b PERF_MEM_LOCK_LOCKED = 0x2 PERF_MEM_LOCK_NA = 0x1 PERF_MEM_LOCK_SHIFT = 0x18 @@ -1986,6 +1991,9 @@ const ( PR_SCHED_CORE_CREATE = 0x1 PR_SCHED_CORE_GET = 0x0 PR_SCHED_CORE_MAX = 0x4 + PR_SCHED_CORE_SCOPE_PROCESS_GROUP = 0x2 + PR_SCHED_CORE_SCOPE_THREAD = 0x0 + PR_SCHED_CORE_SCOPE_THREAD_GROUP = 0x1 PR_SCHED_CORE_SHARE_FROM = 0x3 PR_SCHED_CORE_SHARE_TO = 0x2 PR_SET_CHILD_SUBREAPER = 0x24 @@ -2167,12 +2175,23 @@ const ( RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 RTC_AF = 0x20 + RTC_BSM_DIRECT = 0x1 + RTC_BSM_DISABLED = 0x0 + RTC_BSM_LEVEL = 0x2 + RTC_BSM_STANDBY = 0x3 RTC_FEATURE_ALARM = 0x0 + RTC_FEATURE_ALARM_RES_2S = 0x3 RTC_FEATURE_ALARM_RES_MINUTE = 0x1 - RTC_FEATURE_CNT = 0x3 + RTC_FEATURE_BACKUP_SWITCH_MODE = 0x6 + RTC_FEATURE_CNT = 0x7 + RTC_FEATURE_CORRECTION = 0x5 RTC_FEATURE_NEED_WEEK_DAY = 0x2 + RTC_FEATURE_UPDATE_INTERRUPT = 0x4 RTC_IRQF = 0x80 RTC_MAX_FREQ = 0x2000 + RTC_PARAM_BACKUP_SWITCH_MODE = 0x2 + RTC_PARAM_CORRECTION = 0x1 + RTC_PARAM_FEATURES = 0x0 RTC_PF = 0x40 RTC_UF = 0x10 RTF_ADDRCLASSMASK = 0xf8000000 @@ -2532,6 +2551,8 @@ const ( SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 SO_VM_SOCKETS_BUFFER_SIZE = 0x0 SO_VM_SOCKETS_CONNECT_TIMEOUT = 0x6 + SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW = 0x8 + SO_VM_SOCKETS_CONNECT_TIMEOUT_OLD = 0x6 SO_VM_SOCKETS_NONBLOCK_TXRX = 0x7 SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 SO_VM_SOCKETS_TRUSTED = 0x5 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index 3ca40ca7f..234fd4a5d 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -250,6 +250,8 @@ const ( RTC_EPOCH_SET = 0x4004700e RTC_IRQP_READ = 0x8004700b RTC_IRQP_SET = 0x4004700c + RTC_PARAM_GET = 0x40187013 + RTC_PARAM_SET = 0x40187014 RTC_PIE_OFF = 0x7006 RTC_PIE_ON = 0x7005 RTC_PLL_GET = 0x801c7011 @@ -327,6 +329,7 @@ const ( SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index ead332091..58619b758 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -251,6 +251,8 @@ const ( RTC_EPOCH_SET = 0x4008700e RTC_IRQP_READ = 0x8008700b RTC_IRQP_SET = 0x4008700c + RTC_PARAM_GET = 0x40187013 + RTC_PARAM_SET = 0x40187014 RTC_PIE_OFF = 0x7006 RTC_PIE_ON = 0x7005 RTC_PLL_GET = 0x80207011 @@ -328,6 +330,7 @@ const ( SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index 39bdc9455..3a64ff59d 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -257,6 +257,8 @@ const ( RTC_EPOCH_SET = 0x4004700e RTC_IRQP_READ = 0x8004700b RTC_IRQP_SET = 0x4004700c + RTC_PARAM_GET = 0x40187013 + RTC_PARAM_SET = 0x40187014 RTC_PIE_OFF = 0x7006 RTC_PIE_ON = 0x7005 RTC_PLL_GET = 0x801c7011 @@ -334,6 +336,7 @@ const ( SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index 9aec987db..abe0b9257 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -247,6 +247,8 @@ const ( RTC_EPOCH_SET = 0x4008700e RTC_IRQP_READ = 0x8008700b RTC_IRQP_SET = 0x4008700c + RTC_PARAM_GET = 0x40187013 + RTC_PARAM_SET = 0x40187014 RTC_PIE_OFF = 0x7006 RTC_PIE_ON = 0x7005 RTC_PLL_GET = 0x80207011 @@ -324,6 +326,7 @@ const ( SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index a8bba9491..14d7a8439 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -250,6 +250,8 @@ const ( RTC_EPOCH_SET = 0x8004700e RTC_IRQP_READ = 0x4004700b RTC_IRQP_SET = 0x8004700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x401c7011 @@ -327,6 +329,7 @@ const ( SO_RCVTIMEO = 0x1006 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x1006 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x4 SO_REUSEPORT = 0x200 SO_RXQ_OVFL = 0x28 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index ee9e7e202..99e7c4ac0 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -250,6 +250,8 @@ const ( RTC_EPOCH_SET = 0x8008700e RTC_IRQP_READ = 0x4008700b RTC_IRQP_SET = 0x8008700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x40207011 @@ -327,6 +329,7 @@ const ( SO_RCVTIMEO = 0x1006 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x1006 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x4 SO_REUSEPORT = 0x200 SO_RXQ_OVFL = 0x28 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index ba4b288a3..496364c33 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -250,6 +250,8 @@ const ( RTC_EPOCH_SET = 0x8008700e RTC_IRQP_READ = 0x4008700b RTC_IRQP_SET = 0x8008700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x40207011 @@ -327,6 +329,7 @@ const ( SO_RCVTIMEO = 0x1006 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x1006 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x4 SO_REUSEPORT = 0x200 SO_RXQ_OVFL = 0x28 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index bc93afc36..3e4083085 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -250,6 +250,8 @@ const ( RTC_EPOCH_SET = 0x8004700e RTC_IRQP_READ = 0x4004700b RTC_IRQP_SET = 0x8004700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x401c7011 @@ -327,6 +329,7 @@ const ( SO_RCVTIMEO = 0x1006 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x1006 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x4 SO_REUSEPORT = 0x200 SO_RXQ_OVFL = 0x28 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go index 9295e6947..1151a7dfa 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go @@ -305,6 +305,8 @@ const ( RTC_EPOCH_SET = 0x8004700e RTC_IRQP_READ = 0x4004700b RTC_IRQP_SET = 0x8004700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x401c7011 @@ -382,6 +384,7 @@ const ( SO_RCVTIMEO = 0x12 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x12 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index 1fa081c9a..ed17f249e 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -309,6 +309,8 @@ const ( RTC_EPOCH_SET = 0x8008700e RTC_IRQP_READ = 0x4008700b RTC_IRQP_SET = 0x8008700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x40207011 @@ -386,6 +388,7 @@ const ( SO_RCVTIMEO = 0x12 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x12 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index 74b321149..d84a37c1a 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -309,6 +309,8 @@ const ( RTC_EPOCH_SET = 0x8008700e RTC_IRQP_READ = 0x4008700b RTC_IRQP_SET = 0x8008700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x40207011 @@ -386,6 +388,7 @@ const ( SO_RCVTIMEO = 0x12 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x12 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go index c91c8ac5b..5cafba83f 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -238,6 +238,8 @@ const ( RTC_EPOCH_SET = 0x4008700e RTC_IRQP_READ = 0x8008700b RTC_IRQP_SET = 0x4008700c + RTC_PARAM_GET = 0x40187013 + RTC_PARAM_SET = 0x40187014 RTC_PIE_OFF = 0x7006 RTC_PIE_ON = 0x7005 RTC_PLL_GET = 0x80207011 @@ -315,6 +317,7 @@ const ( SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index b66bf2228..6d122da41 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -313,6 +313,8 @@ const ( RTC_EPOCH_SET = 0x4008700e RTC_IRQP_READ = 0x8008700b RTC_IRQP_SET = 0x4008700c + RTC_PARAM_GET = 0x40187013 + RTC_PARAM_SET = 0x40187014 RTC_PIE_OFF = 0x7006 RTC_PIE_ON = 0x7005 RTC_PLL_GET = 0x80207011 @@ -390,6 +392,7 @@ const ( SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index f7fb149b0..6bd19e51d 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -304,6 +304,8 @@ const ( RTC_EPOCH_SET = 0x8008700e RTC_IRQP_READ = 0x4008700b RTC_IRQP_SET = 0x8008700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x40207011 @@ -381,6 +383,7 @@ const ( SO_RCVTIMEO = 0x2000 SO_RCVTIMEO_NEW = 0x44 SO_RCVTIMEO_OLD = 0x2000 + SO_RESERVE_MEM = 0x52 SO_REUSEADDR = 0x4 SO_REUSEPORT = 0x200 SO_RXQ_OVFL = 0x24 diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go index 31847d230..cac1f758b 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go @@ -445,4 +445,5 @@ const ( SYS_LANDLOCK_RESTRICT_SELF = 446 SYS_MEMFD_SECRET = 447 SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go index 3503cbbde..f327e4a0b 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go @@ -367,4 +367,5 @@ const ( SYS_LANDLOCK_RESTRICT_SELF = 446 SYS_MEMFD_SECRET = 447 SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go index 5ecd24bf6..fb06a08d4 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go @@ -409,4 +409,5 @@ const ( SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go index 7e5c94cc7..58285646e 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go @@ -312,4 +312,5 @@ const ( SYS_LANDLOCK_RESTRICT_SELF = 446 SYS_MEMFD_SECRET = 447 SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go index e1e2a2bf5..3b0418e68 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go @@ -429,4 +429,5 @@ const ( SYS_LANDLOCK_ADD_RULE = 4445 SYS_LANDLOCK_RESTRICT_SELF = 4446 SYS_PROCESS_MRELEASE = 4448 + SYS_FUTEX_WAITV = 4449 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go index 7651915a3..314ebf166 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go @@ -359,4 +359,5 @@ const ( SYS_LANDLOCK_ADD_RULE = 5445 SYS_LANDLOCK_RESTRICT_SELF = 5446 SYS_PROCESS_MRELEASE = 5448 + SYS_FUTEX_WAITV = 5449 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go index a26a2c050..b8fbb937a 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go @@ -359,4 +359,5 @@ const ( SYS_LANDLOCK_ADD_RULE = 5445 SYS_LANDLOCK_RESTRICT_SELF = 5446 SYS_PROCESS_MRELEASE = 5448 + SYS_FUTEX_WAITV = 5449 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go index fda9a6a99..ee309b2ba 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go @@ -429,4 +429,5 @@ const ( SYS_LANDLOCK_ADD_RULE = 4445 SYS_LANDLOCK_RESTRICT_SELF = 4446 SYS_PROCESS_MRELEASE = 4448 + SYS_FUTEX_WAITV = 4449 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go index e8496150d..ac3748104 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go @@ -436,4 +436,5 @@ const ( SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go index 5ee0678a3..5aa472111 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go @@ -408,4 +408,5 @@ const ( SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go index 29c0f9a39..0793ac1a6 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go @@ -408,4 +408,5 @@ const ( SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go index 5c9a9a3b6..a520962e3 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go @@ -310,4 +310,5 @@ const ( SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go index 913f50f98..d1738586b 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go @@ -373,4 +373,5 @@ const ( SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go index 0de03a722..dfd5660f9 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go @@ -387,4 +387,5 @@ const ( SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go index f6f0d79c4..66788f156 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -1144,7 +1144,8 @@ const ( PERF_RECORD_BPF_EVENT = 0x12 PERF_RECORD_CGROUP = 0x13 PERF_RECORD_TEXT_POKE = 0x14 - PERF_RECORD_MAX = 0x15 + PERF_RECORD_AUX_OUTPUT_HW_ID = 0x15 + PERF_RECORD_MAX = 0x16 PERF_RECORD_KSYMBOL_TYPE_UNKNOWN = 0x0 PERF_RECORD_KSYMBOL_TYPE_BPF = 0x1 PERF_RECORD_KSYMBOL_TYPE_OOL = 0x2 @@ -1784,7 +1785,8 @@ const ( const ( NF_NETDEV_INGRESS = 0x0 - NF_NETDEV_NUMHOOKS = 0x1 + NF_NETDEV_EGRESS = 0x1 + NF_NETDEV_NUMHOOKS = 0x2 ) const ( @@ -3166,7 +3168,13 @@ const ( DEVLINK_ATTR_RELOAD_ACTION_INFO = 0xa2 DEVLINK_ATTR_RELOAD_ACTION_STATS = 0xa3 DEVLINK_ATTR_PORT_PCI_SF_NUMBER = 0xa4 - DEVLINK_ATTR_MAX = 0xa9 + DEVLINK_ATTR_RATE_TYPE = 0xa5 + DEVLINK_ATTR_RATE_TX_SHARE = 0xa6 + DEVLINK_ATTR_RATE_TX_MAX = 0xa7 + DEVLINK_ATTR_RATE_NODE_NAME = 0xa8 + DEVLINK_ATTR_RATE_PARENT_NODE_NAME = 0xa9 + DEVLINK_ATTR_REGION_MAX_SNAPSHOTS = 0xaa + DEVLINK_ATTR_MAX = 0xaa DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE = 0x0 DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX = 0x1 DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT = 0x0 @@ -3463,7 +3471,14 @@ const ( ETHTOOL_MSG_CABLE_TEST_ACT = 0x1a ETHTOOL_MSG_CABLE_TEST_TDR_ACT = 0x1b ETHTOOL_MSG_TUNNEL_INFO_GET = 0x1c - ETHTOOL_MSG_USER_MAX = 0x21 + ETHTOOL_MSG_FEC_GET = 0x1d + ETHTOOL_MSG_FEC_SET = 0x1e + ETHTOOL_MSG_MODULE_EEPROM_GET = 0x1f + ETHTOOL_MSG_STATS_GET = 0x20 + ETHTOOL_MSG_PHC_VCLOCKS_GET = 0x21 + ETHTOOL_MSG_MODULE_GET = 0x22 + ETHTOOL_MSG_MODULE_SET = 0x23 + ETHTOOL_MSG_USER_MAX = 0x23 ETHTOOL_MSG_KERNEL_NONE = 0x0 ETHTOOL_MSG_STRSET_GET_REPLY = 0x1 ETHTOOL_MSG_LINKINFO_GET_REPLY = 0x2 @@ -3494,7 +3509,14 @@ const ( ETHTOOL_MSG_CABLE_TEST_NTF = 0x1b ETHTOOL_MSG_CABLE_TEST_TDR_NTF = 0x1c ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY = 0x1d - ETHTOOL_MSG_KERNEL_MAX = 0x22 + ETHTOOL_MSG_FEC_GET_REPLY = 0x1e + ETHTOOL_MSG_FEC_NTF = 0x1f + ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY = 0x20 + ETHTOOL_MSG_STATS_GET_REPLY = 0x21 + ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY = 0x22 + ETHTOOL_MSG_MODULE_GET_REPLY = 0x23 + ETHTOOL_MSG_MODULE_NTF = 0x24 + ETHTOOL_MSG_KERNEL_MAX = 0x24 ETHTOOL_A_HEADER_UNSPEC = 0x0 ETHTOOL_A_HEADER_DEV_INDEX = 0x1 ETHTOOL_A_HEADER_DEV_NAME = 0x2 diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index 200b62a00..cf44e6933 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -363,6 +363,8 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys SetProcessWorkingSetSizeEx(hProcess Handle, dwMinimumWorkingSetSize uintptr, dwMaximumWorkingSetSize uintptr, flags uint32) (err error) //sys GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) //sys SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) +//sys GetActiveProcessorCount(groupNumber uint16) (ret uint32) +//sys GetMaximumProcessorCount(groupNumber uint16) (ret uint32) // Volume Management Functions //sys DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) = DefineDosDeviceW diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go index bb31abda4..e19471c6a 100644 --- a/vendor/golang.org/x/sys/windows/types_windows.go +++ b/vendor/golang.org/x/sys/windows/types_windows.go @@ -3172,3 +3172,5 @@ type ModuleInfo struct { SizeOfImage uint32 EntryPoint uintptr } + +const ALL_PROCESSOR_GROUPS = 0xFFFF diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index 1055d47ed..9ea1a44f0 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -226,6 +226,7 @@ var ( procFreeLibrary = modkernel32.NewProc("FreeLibrary") procGenerateConsoleCtrlEvent = modkernel32.NewProc("GenerateConsoleCtrlEvent") procGetACP = modkernel32.NewProc("GetACP") + procGetActiveProcessorCount = modkernel32.NewProc("GetActiveProcessorCount") procGetCommTimeouts = modkernel32.NewProc("GetCommTimeouts") procGetCommandLineW = modkernel32.NewProc("GetCommandLineW") procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") @@ -251,6 +252,7 @@ var ( procGetLogicalDriveStringsW = modkernel32.NewProc("GetLogicalDriveStringsW") procGetLogicalDrives = modkernel32.NewProc("GetLogicalDrives") procGetLongPathNameW = modkernel32.NewProc("GetLongPathNameW") + procGetMaximumProcessorCount = modkernel32.NewProc("GetMaximumProcessorCount") procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW") procGetModuleHandleExW = modkernel32.NewProc("GetModuleHandleExW") procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW") @@ -1967,6 +1969,12 @@ func GetACP() (acp uint32) { return } +func GetActiveProcessorCount(groupNumber uint16) (ret uint32) { + r0, _, _ := syscall.Syscall(procGetActiveProcessorCount.Addr(), 1, uintptr(groupNumber), 0, 0) + ret = uint32(r0) + return +} + func GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { r1, _, e1 := syscall.Syscall(procGetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) if r1 == 0 { @@ -2169,6 +2177,12 @@ func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err er return } +func GetMaximumProcessorCount(groupNumber uint16) (ret uint32) { + r0, _, _ := syscall.Syscall(procGetMaximumProcessorCount.Addr(), 1, uintptr(groupNumber), 0, 0) + ret = uint32(r0) + return +} + func GetModuleFileName(module Handle, filename *uint16, size uint32) (n uint32, err error) { r0, _, e1 := syscall.Syscall(procGetModuleFileNameW.Addr(), 3, uintptr(module), uintptr(unsafe.Pointer(filename)), uintptr(size)) n = uint32(r0) diff --git a/vendor/modules.txt b/vendor/modules.txt index 61e66d73c..417adb1dc 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -74,7 +74,7 @@ github.com/gdamore/tcell/v2/terminfo/x/xfce github.com/gdamore/tcell/v2/terminfo/x/xterm github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty github.com/gdamore/tcell/v2/terminfo/x/xterm_termite -# github.com/go-errors/errors v1.4.1 +# github.com/go-errors/errors v1.4.2 ## explicit github.com/go-errors/errors # github.com/go-git/gcfg v1.5.0 @@ -159,7 +159,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem github.com/jesseduffield/go-git/v5/utils/merkletrie/index github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame github.com/jesseduffield/go-git/v5/utils/merkletrie/noder -# github.com/jesseduffield/gocui v0.3.1-0.20220108045521-1945d7b9ed8b +# github.com/jesseduffield/gocui v0.3.1-0.20220131110921-82fe47ec96ba ## explicit github.com/jesseduffield/gocui # github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e @@ -255,7 +255,7 @@ golang.org/x/crypto/ssh/knownhosts golang.org/x/net/context golang.org/x/net/internal/socks golang.org/x/net/proxy -# golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e +# golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 ## explicit golang.org/x/sys/cpu golang.org/x/sys/internal/unsafeheader From 2db463681564e8db945cd6811fc633545ee9fd83 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Mon, 31 Jan 2022 22:20:28 +1100 Subject: [PATCH 048/385] no more indirection --- pkg/gui/context_config.go | 4 +- pkg/gui/controllers/bisect_controller.go | 12 ++-- pkg/gui/controllers/cherry_pick_helper.go | 14 ++-- pkg/gui/controllers/files_controller.go | 65 +++++++++---------- .../controllers/local_commits_controller.go | 60 ++++++++--------- pkg/gui/controllers/menu_controller.go | 14 ++-- pkg/gui/controllers/rebase_helper.go | 8 +-- pkg/gui/controllers/refs_helper.go | 26 ++++---- pkg/gui/controllers/remotes_controller.go | 26 ++++---- pkg/gui/controllers/tags_controller.go | 28 ++++---- pkg/gui/gui.go | 32 +++++---- 11 files changed, 142 insertions(+), 147 deletions(-) diff --git a/pkg/gui/context_config.go b/pkg/gui/context_config.go index c5c2bf544..eec6cdd69 100644 --- a/pkg/gui/context_config.go +++ b/pkg/gui/context_config.go @@ -32,8 +32,8 @@ func (gui *Gui) allContexts() []types.Context { } } -func (gui *Gui) contextTree() context.ContextTree { - return context.ContextTree{ +func (gui *Gui) contextTree() *context.ContextTree { + return &context.ContextTree{ Status: NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.SIDE_CONTEXT, diff --git a/pkg/gui/controllers/bisect_controller.go b/pkg/gui/controllers/bisect_controller.go index 6befce84c..bb7ba642d 100644 --- a/pkg/gui/controllers/bisect_controller.go +++ b/pkg/gui/controllers/bisect_controller.go @@ -13,7 +13,7 @@ import ( type BisectController struct { c *types.ControllerCommon - getContext func() types.IListContext + context types.IListContext git *commands.GitCommand bisectHelper *BisectHelper @@ -25,7 +25,7 @@ var _ types.IController = &BisectController{} func NewBisectController( c *types.ControllerCommon, - getContext func() types.IListContext, + context types.IListContext, git *commands.GitCommand, bisectHelper *BisectHelper, @@ -34,7 +34,7 @@ func NewBisectController( ) *BisectController { return &BisectController{ c: c, - getContext: getContext, + context: context, git: git, bisectHelper: bisectHelper, @@ -232,8 +232,8 @@ func (self *BisectController) selectCurrentBisectCommit() { // find index of commit with that sha, move cursor to that. for i, commit := range self.getCommits() { if commit.Sha == info.GetCurrentSha() { - self.getContext().GetPanelState().SetSelectedLineIdx(i) - _ = self.getContext().HandleFocus() + self.context.GetPanelState().SetSelectedLineIdx(i) + _ = self.context.HandleFocus() break } } @@ -252,5 +252,5 @@ func (self *BisectController) checkSelected(callback func(*models.Commit) error) } func (self *BisectController) Context() types.Context { - return self.getContext() + return self.context } diff --git a/pkg/gui/controllers/cherry_pick_helper.go b/pkg/gui/controllers/cherry_pick_helper.go index 3bce03132..1f6665224 100644 --- a/pkg/gui/controllers/cherry_pick_helper.go +++ b/pkg/gui/controllers/cherry_pick_helper.go @@ -13,8 +13,8 @@ type CherryPickHelper struct { git *commands.GitCommand - getContexts func() context.ContextTree - getData func() *cherrypicking.CherryPicking + contexts *context.ContextTree + getData func() *cherrypicking.CherryPicking rebaseHelper *RebaseHelper } @@ -25,14 +25,14 @@ type CherryPickHelper struct { func NewCherryPickHelper( c *types.ControllerCommon, git *commands.GitCommand, - getContexts func() context.ContextTree, + contexts *context.ContextTree, getData func() *cherrypicking.CherryPicking, rebaseHelper *RebaseHelper, ) *CherryPickHelper { return &CherryPickHelper{ c: c, git: git, - getContexts: getContexts, + contexts: contexts, getData: getData, rebaseHelper: rebaseHelper, } @@ -143,9 +143,9 @@ func (self *CherryPickHelper) resetIfNecessary(context types.Context) error { func (self *CherryPickHelper) rerender() error { for _, context := range []types.Context{ - self.getContexts().BranchCommits, - self.getContexts().ReflogCommits, - self.getContexts().SubCommits, + self.contexts.BranchCommits, + self.contexts.ReflogCommits, + self.contexts.SubCommits, } { if err := self.c.PostRefreshUpdate(context); err != nil { return err diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index 57df2e84e..a7c4ff374 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -21,21 +21,20 @@ type FilesController struct { // case I would actually prefer a _zero_ letter variable name in the form of // struct embedding, but Go does not allow hiding public fields in an embedded struct // to the client - c *types.ControllerCommon - getContext func() *context.WorkingTreeContext - getFiles func() []*models.File - git *commands.GitCommand - os *oscommands.OSCommand + c *types.ControllerCommon + context *context.WorkingTreeContext + model *types.Model + git *commands.GitCommand + os *oscommands.OSCommand getSelectedFileNode func() *filetree.FileNode - getContexts func() context.ContextTree + contexts *context.ContextTree enterSubmodule func(submodule *models.SubmoduleConfig) error getSubmodules func() []*models.SubmoduleConfig setCommitMessage func(message string) getCheckedOutBranch func() *models.Branch withGpgHandling func(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error getFailedCommitMessage func() string - getCommits func() []*models.Commit getSelectedPath func() string switchToMergeFn func(path string) error suggestionsHelper ISuggestionsHelper @@ -48,18 +47,17 @@ var _ types.IController = &FilesController{} func NewFilesController( c *types.ControllerCommon, - getContext func() *context.WorkingTreeContext, - getFiles func() []*models.File, + context *context.WorkingTreeContext, + model *types.Model, git *commands.GitCommand, os *oscommands.OSCommand, getSelectedFileNode func() *filetree.FileNode, - allContexts func() context.ContextTree, + allContexts *context.ContextTree, enterSubmodule func(submodule *models.SubmoduleConfig) error, getSubmodules func() []*models.SubmoduleConfig, setCommitMessage func(message string), withGpgHandling func(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error, getFailedCommitMessage func() string, - getCommits func() []*models.Commit, getSelectedPath func() string, switchToMergeFn func(path string) error, suggestionsHelper ISuggestionsHelper, @@ -69,18 +67,17 @@ func NewFilesController( ) *FilesController { return &FilesController{ c: c, - getContext: getContext, - getFiles: getFiles, + context: context, + model: model, git: git, os: os, getSelectedFileNode: getSelectedFileNode, - getContexts: allContexts, + contexts: allContexts, enterSubmodule: enterSubmodule, getSubmodules: getSubmodules, setCommitMessage: setCommitMessage, withGpgHandling: withGpgHandling, getFailedCommitMessage: getFailedCommitMessage, - getCommits: getCommits, getSelectedPath: getSelectedPath, switchToMergeFn: switchToMergeFn, suggestionsHelper: suggestionsHelper, @@ -99,7 +96,7 @@ func (self *FilesController) Keybindings(getKey func(key string) interface{}, co }, { Key: gocui.MouseLeft, - Handler: func() error { return self.getContext().HandleClick(self.checkSelectedFileNode(self.press)) }, + Handler: func() error { return self.context.HandleClick(self.checkSelectedFileNode(self.press)) }, }, { Key: getKey(" "), // TODO: softcode @@ -198,7 +195,7 @@ func (self *FilesController) Keybindings(getKey func(key string) interface{}, co }, } - return append(bindings, self.getContext().Keybindings(getKey, config, guards)...) + return append(bindings, self.context.Keybindings(getKey, config, guards)...) } func (self *FilesController) press(node *filetree.FileNode) error { @@ -206,7 +203,7 @@ func (self *FilesController) press(node *filetree.FileNode) error { file := node.File if file.HasInlineMergeConflicts { - return self.c.PushContext(self.getContexts().Merging) + return self.c.PushContext(self.contexts.Merging) } if file.HasUnstagedChanges { @@ -245,7 +242,7 @@ func (self *FilesController) press(node *filetree.FileNode) error { return err } - return self.getContext().HandleFocus() + return self.context.HandleFocus() } func (self *FilesController) checkSelectedFileNode(callback func(*filetree.FileNode) error) func() error { @@ -260,7 +257,7 @@ func (self *FilesController) checkSelectedFileNode(callback func(*filetree.FileN } func (self *FilesController) Context() types.Context { - return self.getContext() + return self.context } func (self *FilesController) getSelectedFile() *models.File { @@ -300,11 +297,11 @@ func (self *FilesController) EnterFile(opts types.OnFocusOpts) error { return self.c.ErrorMsg(self.c.Tr.FileStagingRequirements) } - return self.c.PushContext(self.getContexts().Staging, opts) + return self.c.PushContext(self.contexts.Staging, opts) } func (self *FilesController) allFilesStaged() bool { - for _, file := range self.getFiles() { + for _, file := range self.model.Files { if file.HasUnstagedChanges { return false } @@ -329,7 +326,7 @@ func (self *FilesController) stageAll() error { return err } - return self.getContexts().Files.HandleFocus() + return self.contexts.Files.HandleFocus() } func (self *FilesController) ignore(node *filetree.FileNode) error { @@ -434,7 +431,7 @@ func (self *FilesController) HandleCommitPress() error { return self.c.Error(err) } - if len(self.getFiles()) == 0 { + if len(self.model.Files) == 0 { return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle) } @@ -459,7 +456,7 @@ func (self *FilesController) HandleCommitPress() error { } } - if err := self.c.PushContext(self.getContexts().CommitMessage); err != nil { + if err := self.c.PushContext(self.contexts.CommitMessage); err != nil { return err } @@ -485,7 +482,7 @@ func (self *FilesController) promptToStageAllAndRetry(retry func() error) error } func (self *FilesController) handleAmendCommitPress() error { - if len(self.getFiles()) == 0 { + if len(self.model.Files) == 0 { return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle) } @@ -493,7 +490,7 @@ func (self *FilesController) handleAmendCommitPress() error { return self.promptToStageAllAndRetry(self.handleAmendCommitPress) } - if len(self.getCommits()) == 0 { + if len(self.model.Commits) == 0 { return self.c.ErrorMsg(self.c.Tr.NoCommitToAmend) } @@ -511,7 +508,7 @@ func (self *FilesController) handleAmendCommitPress() error { // HandleCommitEditorPress - handle when the user wants to commit changes via // their editor rather than via the popup panel func (self *FilesController) HandleCommitEditorPress() error { - if len(self.getFiles()) == 0 { + if len(self.model.Files) == 0 { return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle) } @@ -552,8 +549,8 @@ func (self *FilesController) handleStatusFilterPressed() error { } func (self *FilesController) setStatusFiltering(filter filetree.FileTreeDisplayFilter) error { - self.getContext().FileTreeViewModel.SetFilter(filter) - return self.c.PostRefreshUpdate(self.getContext()) + self.context.FileTreeViewModel.SetFilter(filter) + return self.c.PostRefreshUpdate(self.context) } func (self *FilesController) edit(node *filetree.FileNode) error { @@ -643,9 +640,9 @@ func (self *FilesController) handleToggleDirCollapsed() error { return nil } - self.getContext().FileTreeViewModel.ToggleCollapsed(node.GetPath()) + self.context.FileTreeViewModel.ToggleCollapsed(node.GetPath()) - if err := self.c.PostRefreshUpdate(self.getContexts().Files); err != nil { + if err := self.c.PostRefreshUpdate(self.contexts.Files); err != nil { self.c.Log.Error(err) } @@ -653,9 +650,9 @@ func (self *FilesController) handleToggleDirCollapsed() error { } func (self *FilesController) toggleTreeView() error { - self.getContext().FileTreeViewModel.ToggleShowTree() + self.context.FileTreeViewModel.ToggleShowTree() - return self.c.PostRefreshUpdate(self.getContext()) + return self.c.PostRefreshUpdate(self.context) } func (self *FilesController) OpenMergeTool() error { diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index bc25411bf..749199c1e 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -24,7 +24,7 @@ type ( type LocalCommitsController struct { c *types.ControllerCommon - getContext func() types.IListContext + context types.IListContext os *oscommands.OSCommand git *commands.GitCommand tagsHelper *TagsHelper @@ -33,7 +33,7 @@ type LocalCommitsController struct { rebaseHelper *RebaseHelper getSelectedLocalCommit func() *models.Commit - getCommits func() []*models.Commit + model *types.Model getSelectedLocalCommitIdx func() int CheckMergeOrRebase CheckMergeOrRebase pullFiles PullFilesFn @@ -49,7 +49,7 @@ var _ types.IController = &LocalCommitsController{} func NewLocalCommitsController( c *types.ControllerCommon, - getContext func() types.IListContext, + context types.IListContext, os *oscommands.OSCommand, git *commands.GitCommand, tagsHelper *TagsHelper, @@ -57,7 +57,7 @@ func NewLocalCommitsController( cherryPickHelper *CherryPickHelper, rebaseHelper *RebaseHelper, getSelectedLocalCommit func() *models.Commit, - getCommits func() []*models.Commit, + model *types.Model, getSelectedLocalCommitIdx func() int, CheckMergeOrRebase CheckMergeOrRebase, pullFiles PullFilesFn, @@ -70,7 +70,7 @@ func NewLocalCommitsController( ) *LocalCommitsController { return &LocalCommitsController{ c: c, - getContext: getContext, + context: context, os: os, git: git, tagsHelper: tagsHelper, @@ -78,7 +78,7 @@ func NewLocalCommitsController( cherryPickHelper: cherryPickHelper, rebaseHelper: rebaseHelper, getSelectedLocalCommit: getSelectedLocalCommit, - getCommits: getCommits, + model: model, getSelectedLocalCommitIdx: getSelectedLocalCommitIdx, CheckMergeOrRebase: CheckMergeOrRebase, pullFiles: pullFiles, @@ -199,7 +199,7 @@ func (self *LocalCommitsController) Keybindings( }, { Key: gocui.MouseLeft, - Handler: func() error { return self.getContext().HandleClick(self.checkSelected(self.enter)) }, + Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, }, } @@ -246,11 +246,11 @@ func (self *LocalCommitsController) Keybindings( }, }...) - return append(bindings, self.getContext().Keybindings(getKey, config, guards)...) + return append(bindings, self.context.Keybindings(getKey, config, guards)...) } func (self *LocalCommitsController) squashDown() error { - if len(self.getCommits()) <= 1 { + if len(self.model.Commits) <= 1 { return self.c.ErrorMsg(self.c.Tr.YouNoCommitsToSquash) } @@ -275,7 +275,7 @@ func (self *LocalCommitsController) squashDown() error { } func (self *LocalCommitsController) fixup() error { - if len(self.getCommits()) <= 1 { + if len(self.model.Commits) <= 1 { return self.c.ErrorMsg(self.c.Tr.YouNoCommitsToSquash) } @@ -319,7 +319,7 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error { InitialContent: message, HandleConfirm: func(response string) error { self.c.LogAction(self.c.Tr.Actions.RewordCommit) - if err := self.git.Rebase.RewordCommit(self.getCommits(), self.getSelectedLocalCommitIdx(), response); err != nil { + if err := self.git.Rebase.RewordCommit(self.model.Commits, self.getSelectedLocalCommitIdx(), response); err != nil { return self.c.Error(err) } @@ -339,7 +339,7 @@ func (self *LocalCommitsController) rewordEditor() error { self.c.LogAction(self.c.Tr.Actions.RewordCommit) subProcess, err := self.git.Rebase.RewordCommitInEditor( - self.getCommits(), self.getSelectedLocalCommitIdx(), + self.model.Commits, self.getSelectedLocalCommitIdx(), ) if err != nil { return self.c.Error(err) @@ -402,7 +402,7 @@ func (self *LocalCommitsController) pick() error { } func (self *LocalCommitsController) interactiveRebase(action string) error { - err := self.git.Rebase.InteractiveRebase(self.getCommits(), self.getSelectedLocalCommitIdx(), action) + err := self.git.Rebase.InteractiveRebase(self.model.Commits, self.getSelectedLocalCommitIdx(), action) return self.CheckMergeOrRebase(err) } @@ -441,9 +441,9 @@ func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool, } func (self *LocalCommitsController) handleCommitMoveDown() error { - index := self.getContext().GetPanelState().GetSelectedLineIdx() - commits := self.getCommits() - selectedCommit := self.getCommits()[index] + index := self.context.GetPanelState().GetSelectedLineIdx() + commits := self.model.Commits + selectedCommit := self.model.Commits[index] if selectedCommit.Status == "rebasing" { if commits[index+1].Status != "rebasing" { return nil @@ -458,7 +458,7 @@ func (self *LocalCommitsController) handleCommitMoveDown() error { return self.c.Error(err) } // TODO: use MoveSelectedLine - _ = self.getContext().HandleNextLine() + _ = self.context.HandleNextLine() return self.c.Refresh(types.RefreshOptions{ Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS}, }) @@ -466,22 +466,22 @@ func (self *LocalCommitsController) handleCommitMoveDown() error { return self.c.WithWaitingStatus(self.c.Tr.MovingStatus, func() error { self.c.LogAction(self.c.Tr.Actions.MoveCommitDown) - err := self.git.Rebase.MoveCommitDown(self.getCommits(), index) + err := self.git.Rebase.MoveCommitDown(self.model.Commits, index) if err == nil { // TODO: use MoveSelectedLine - _ = self.getContext().HandleNextLine() + _ = self.context.HandleNextLine() } return self.CheckMergeOrRebase(err) }) } func (self *LocalCommitsController) handleCommitMoveUp() error { - index := self.getContext().GetPanelState().GetSelectedLineIdx() + index := self.context.GetPanelState().GetSelectedLineIdx() if index == 0 { return nil } - selectedCommit := self.getCommits()[index] + selectedCommit := self.model.Commits[index] if selectedCommit.Status == "rebasing" { // logging directly here because MoveTodoDown doesn't have enough information // to provide a useful log @@ -494,7 +494,7 @@ func (self *LocalCommitsController) handleCommitMoveUp() error { if err := self.git.Rebase.MoveTodoDown(index - 1); err != nil { return self.c.Error(err) } - _ = self.getContext().HandlePrevLine() + _ = self.context.HandlePrevLine() return self.c.Refresh(types.RefreshOptions{ Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS}, }) @@ -502,9 +502,9 @@ func (self *LocalCommitsController) handleCommitMoveUp() error { return self.c.WithWaitingStatus(self.c.Tr.MovingStatus, func() error { self.c.LogAction(self.c.Tr.Actions.MoveCommitUp) - err := self.git.Rebase.MoveCommitDown(self.getCommits(), index-1) + err := self.git.Rebase.MoveCommitDown(self.model.Commits, index-1) if err == nil { - _ = self.getContext().HandlePrevLine() + _ = self.context.HandlePrevLine() } return self.CheckMergeOrRebase(err) }) @@ -572,7 +572,7 @@ func (self *LocalCommitsController) createRevertMergeCommitMenu(commit *models.C } func (self *LocalCommitsController) afterRevertCommit() error { - _ = self.getContext().HandleNextLine() + _ = self.context.HandleNextLine() return self.c.Refresh(types.RefreshOptions{ Mode: types.BLOCK_UI, Scope: []types.RefreshableView{types.COMMITS, types.BRANCHES}, }) @@ -582,7 +582,7 @@ func (self *LocalCommitsController) enter(commit *models.Commit) error { return self.switchToCommitFilesContext(SwitchToCommitFilesContextOpts{ RefName: commit.Sha, CanRebase: true, - Context: self.getContext(), + Context: self.context, WindowName: "commits", }) } @@ -672,7 +672,7 @@ func (self *LocalCommitsController) gotoBottom() error { } } - _ = self.getContext().HandleGotoBottom() + _ = self.context.HandleGotoBottom() return nil } @@ -804,7 +804,7 @@ func (self *LocalCommitsController) checkSelected(callback func(*models.Commit) } func (self *LocalCommitsController) Context() types.Context { - return self.getContext() + return self.context } func (self *LocalCommitsController) newBranch(commit *models.Commit) error { @@ -812,11 +812,11 @@ func (self *LocalCommitsController) newBranch(commit *models.Commit) error { } func (self *LocalCommitsController) copy(commit *models.Commit) error { - return self.cherryPickHelper.Copy(commit, self.getCommits(), self.getContext()) + return self.cherryPickHelper.Copy(commit, self.model.Commits, self.context) } func (self *LocalCommitsController) copyRange(*models.Commit) error { - return self.cherryPickHelper.CopyRange(self.getContext().GetPanelState().GetSelectedLineIdx(), self.getCommits(), self.getContext()) + return self.cherryPickHelper.CopyRange(self.context.GetPanelState().GetSelectedLineIdx(), self.model.Commits, self.context) } func (self *LocalCommitsController) paste() error { diff --git a/pkg/gui/controllers/menu_controller.go b/pkg/gui/controllers/menu_controller.go index e03666ad5..7773a0148 100644 --- a/pkg/gui/controllers/menu_controller.go +++ b/pkg/gui/controllers/menu_controller.go @@ -7,8 +7,8 @@ import ( ) type MenuController struct { - c *types.ControllerCommon - getContext func() types.IListContext + c *types.ControllerCommon + context types.IListContext getSelectedMenuItem func() *types.MenuItem } @@ -17,12 +17,12 @@ var _ types.IController = &MenuController{} func NewMenuController( c *types.ControllerCommon, - getContext func() types.IListContext, + context types.IListContext, getSelectedMenuItem func() *types.MenuItem, ) *MenuController { return &MenuController{ c: c, - getContext: getContext, + context: context, getSelectedMenuItem: getSelectedMenuItem, } } @@ -43,11 +43,11 @@ func (self *MenuController) Keybindings(getKey func(key string) interface{}, con }, { Key: gocui.MouseLeft, - Handler: func() error { return self.getContext().HandleClick(self.press) }, + Handler: func() error { return self.context.HandleClick(self.press) }, }, } - return append(bindings, self.getContext().Keybindings(getKey, config, guards)...) + return append(bindings, self.context.Keybindings(getKey, config, guards)...) } func (self *MenuController) press() error { @@ -65,5 +65,5 @@ func (self *MenuController) press() error { } func (self *MenuController) Context() types.Context { - return self.getContext() + return self.context } diff --git a/pkg/gui/controllers/rebase_helper.go b/pkg/gui/controllers/rebase_helper.go index 6515895c1..036af31e0 100644 --- a/pkg/gui/controllers/rebase_helper.go +++ b/pkg/gui/controllers/rebase_helper.go @@ -12,20 +12,20 @@ import ( type RebaseHelper struct { c *types.ControllerCommon - getContexts func() context.ContextTree + contexts *context.ContextTree git *commands.GitCommand takeOverMergeConflictScrolling func() } func NewRebaseHelper( c *types.ControllerCommon, - getContexts func() context.ContextTree, + contexts *context.ContextTree, git *commands.GitCommand, takeOverMergeConflictScrolling func(), ) *RebaseHelper { return &RebaseHelper{ c: c, - getContexts: getContexts, + contexts: contexts, git: git, takeOverMergeConflictScrolling: takeOverMergeConflictScrolling, } @@ -139,7 +139,7 @@ func (self *RebaseHelper) CheckMergeOrRebase(result error) error { Prompt: self.c.Tr.FoundConflicts, HandlersManageFocus: true, HandleConfirm: func() error { - return self.c.PushContext(self.getContexts().Files) + return self.c.PushContext(self.contexts.Files) }, HandleClose: func() error { if err := self.c.PopContext(); err != nil { diff --git a/pkg/gui/controllers/refs_helper.go b/pkg/gui/controllers/refs_helper.go index 2bb1868e0..8d56ec0d7 100644 --- a/pkg/gui/controllers/refs_helper.go +++ b/pkg/gui/controllers/refs_helper.go @@ -22,20 +22,20 @@ type IRefsHelper interface { type RefsHelper struct { c *types.ControllerCommon git *commands.GitCommand - getContexts func() context.ContextTree + contexts *context.ContextTree limitCommits func() } func NewRefsHelper( c *types.ControllerCommon, git *commands.GitCommand, - getContexts func() context.ContextTree, + contexts *context.ContextTree, limitCommits func(), ) *RefsHelper { return &RefsHelper{ c: c, git: git, - getContexts: getContexts, + contexts: contexts, limitCommits: limitCommits, } } @@ -51,9 +51,9 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions cmdOptions := git_commands.CheckoutOptions{Force: false, EnvVars: options.EnvVars} onSuccess := func() { - self.getContexts().Branches.GetPanelState().SetSelectedLineIdx(0) - self.getContexts().BranchCommits.GetPanelState().SetSelectedLineIdx(0) - self.getContexts().ReflogCommits.GetPanelState().SetSelectedLineIdx(0) + self.contexts.Branches.GetPanelState().SetSelectedLineIdx(0) + self.contexts.BranchCommits.GetPanelState().SetSelectedLineIdx(0) + self.contexts.ReflogCommits.GetPanelState().SetSelectedLineIdx(0) // loading a heap of commits is slow so we limit them whenever doing a reset self.limitCommits() } @@ -107,12 +107,12 @@ func (self *RefsHelper) ResetToRef(ref string, strength string, envVars []string return self.c.Error(err) } - self.getContexts().BranchCommits.GetPanelState().SetSelectedLineIdx(0) - self.getContexts().ReflogCommits.GetPanelState().SetSelectedLineIdx(0) + self.contexts.BranchCommits.GetPanelState().SetSelectedLineIdx(0) + self.contexts.ReflogCommits.GetPanelState().SetSelectedLineIdx(0) // loading a heap of commits is slow so we limit them whenever doing a reset self.limitCommits() - if err := self.c.PushContext(self.getContexts().BranchCommits); err != nil { + if err := self.c.PushContext(self.contexts.BranchCommits); err != nil { return err } @@ -163,14 +163,14 @@ func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggest return err } - if self.c.CurrentContext() != self.getContexts().Branches { - if err := self.c.PushContext(self.getContexts().Branches); err != nil { + if self.c.CurrentContext() != self.contexts.Branches { + if err := self.c.PushContext(self.contexts.Branches); err != nil { return err } } - self.getContexts().BranchCommits.GetPanelState().SetSelectedLineIdx(0) - self.getContexts().Branches.GetPanelState().SetSelectedLineIdx(0) + self.contexts.BranchCommits.GetPanelState().SetSelectedLineIdx(0) + self.contexts.Branches.GetPanelState().SetSelectedLineIdx(0) return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) }, diff --git a/pkg/gui/controllers/remotes_controller.go b/pkg/gui/controllers/remotes_controller.go index bc91f40e7..d9812d213 100644 --- a/pkg/gui/controllers/remotes_controller.go +++ b/pkg/gui/controllers/remotes_controller.go @@ -11,30 +11,30 @@ import ( ) type RemotesController struct { - c *types.ControllerCommon - getContext func() types.IListContext - git *commands.GitCommand + c *types.ControllerCommon + context types.IListContext + git *commands.GitCommand getSelectedRemote func() *models.Remote setRemoteBranches func([]*models.RemoteBranch) - getContexts func() context.ContextTree + contexts *context.ContextTree } var _ types.IController = &RemotesController{} func NewRemotesController( c *types.ControllerCommon, - getContext func() types.IListContext, + context types.IListContext, git *commands.GitCommand, - getContexts func() context.ContextTree, + contexts *context.ContextTree, getSelectedRemote func() *models.Remote, setRemoteBranches func([]*models.RemoteBranch), ) *RemotesController { return &RemotesController{ c: c, git: git, - getContexts: getContexts, - getContext: getContext, + contexts: contexts, + context: context, getSelectedRemote: getSelectedRemote, setRemoteBranches: setRemoteBranches, } @@ -48,7 +48,7 @@ func (self *RemotesController) Keybindings(getKey func(key string) interface{}, }, { Key: gocui.MouseLeft, - Handler: func() error { return self.getContext().HandleClick(self.checkSelected(self.enter)) }, + Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, }, { Key: getKey(config.Branches.FetchRemote), @@ -72,7 +72,7 @@ func (self *RemotesController) Keybindings(getKey func(key string) interface{}, }, } - return append(bindings, self.getContext().Keybindings(getKey, config, guards)...) + return append(bindings, self.context.Keybindings(getKey, config, guards)...) } func (self *RemotesController) enter(remote *models.Remote) error { @@ -83,9 +83,9 @@ func (self *RemotesController) enter(remote *models.Remote) error { if len(remote.Branches) == 0 { newSelectedLine = -1 } - self.getContexts().RemoteBranches.GetPanelState().SetSelectedLineIdx(newSelectedLine) + self.contexts.RemoteBranches.GetPanelState().SetSelectedLineIdx(newSelectedLine) - return self.c.PushContext(self.getContexts().RemoteBranches) + return self.c.PushContext(self.contexts.RemoteBranches) } func (self *RemotesController) add() error { @@ -191,5 +191,5 @@ func (self *RemotesController) checkSelected(callback func(*models.Remote) error } func (self *RemotesController) Context() types.Context { - return self.getContext() + return self.context } diff --git a/pkg/gui/controllers/tags_controller.go b/pkg/gui/controllers/tags_controller.go index 0ba73857e..424f5a4b0 100644 --- a/pkg/gui/controllers/tags_controller.go +++ b/pkg/gui/controllers/tags_controller.go @@ -10,11 +10,11 @@ import ( ) type TagsController struct { - c *types.ControllerCommon - getContext func() *context.TagsContext - git *commands.GitCommand - getContexts func() context.ContextTree - tagsHelper *TagsHelper + c *types.ControllerCommon + context *context.TagsContext + git *commands.GitCommand + contexts *context.ContextTree + tagsHelper *TagsHelper refsHelper IRefsHelper suggestionsHelper ISuggestionsHelper @@ -26,9 +26,9 @@ var _ types.IController = &TagsController{} func NewTagsController( c *types.ControllerCommon, - getContext func() *context.TagsContext, + context *context.TagsContext, git *commands.GitCommand, - getContexts func() context.ContextTree, + contexts *context.ContextTree, tagsHelper *TagsHelper, refsHelper IRefsHelper, suggestionsHelper ISuggestionsHelper, @@ -37,9 +37,9 @@ func NewTagsController( ) *TagsController { return &TagsController{ c: c, - getContext: getContext, + context: context, git: git, - getContexts: getContexts, + contexts: contexts, tagsHelper: tagsHelper, refsHelper: refsHelper, suggestionsHelper: suggestionsHelper, @@ -83,7 +83,7 @@ func (self *TagsController) Keybindings(getKey func(key string) interface{}, con }, } - return append(bindings, self.getContext().Keybindings(getKey, config, guards)...) + return append(bindings, self.context.Keybindings(getKey, config, guards)...) } func (self *TagsController) checkout(tag *models.Tag) error { @@ -91,7 +91,7 @@ func (self *TagsController) checkout(tag *models.Tag) error { if err := self.refsHelper.CheckoutRef(tag.Name, types.CheckoutRefOptions{}); err != nil { return err } - return self.c.PushContext(self.getContexts().Branches) + return self.c.PushContext(self.contexts.Branches) } func (self *TagsController) enter(tag *models.Tag) error { @@ -151,12 +151,12 @@ func (self *TagsController) createResetMenu(tag *models.Tag) error { func (self *TagsController) create() error { // leaving commit SHA blank so that we're just creating the tag for the current commit - return self.tagsHelper.CreateTagMenu("", func() { self.getContext().GetPanelState().SetSelectedLineIdx(0) }) + return self.tagsHelper.CreateTagMenu("", func() { self.context.GetPanelState().SetSelectedLineIdx(0) }) } func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func() error { return func() error { - tag := self.getContext().GetSelectedTag() + tag := self.context.GetSelectedTag() if tag == nil { return nil } @@ -166,5 +166,5 @@ func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func( } func (self *TagsController) Context() types.Context { - return self.getContext() + return self.context } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 74a086e36..1b1bf6f39 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -192,7 +192,7 @@ type GuiRepoState struct { MainContext types.ContextKey // used to keep the main and secondary views' contexts in sync ContextManager ContextManager - Contexts context.ContextTree + Contexts *context.ContextTree ViewContextMap map[string]types.Context ViewTabContextMap map[string][]context.TabContext @@ -548,14 +548,13 @@ func NewGui( func (gui *Gui) resetControllers() { controllerCommon := gui.c osCommand := gui.OSCommand - getContexts := func() context.ContextTree { return gui.State.Contexts } - rebaseHelper := controllers.NewRebaseHelper(controllerCommon, getContexts, gui.git, gui.takeOverMergeConflictScrolling) + rebaseHelper := controllers.NewRebaseHelper(controllerCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling) model := gui.State.Model gui.helpers = &Helpers{ Refs: controllers.NewRefsHelper( controllerCommon, gui.git, - getContexts, + gui.State.Contexts, func() { gui.State.Panels.Commits.LimitCommits = true }, ), Bisect: controllers.NewBisectHelper(controllerCommon, gui.git), @@ -567,7 +566,7 @@ func (gui *Gui) resetControllers() { CherryPick: controllers.NewCherryPickHelper( controllerCommon, gui.git, - getContexts, + gui.State.Contexts, func() *cherrypicking.CherryPicking { return gui.State.Modes.CherryPicking }, rebaseHelper, ), @@ -592,18 +591,17 @@ func (gui *Gui) resetControllers() { ), Files: controllers.NewFilesController( controllerCommon, - func() *context.WorkingTreeContext { return gui.State.Contexts.Files }, - func() []*models.File { return gui.State.Model.Files }, + gui.State.Contexts.Files, + model, gui.git, osCommand, gui.getSelectedFileNode, - getContexts, + gui.State.Contexts, gui.enterSubmodule, func() []*models.SubmoduleConfig { return gui.State.Model.Submodules }, gui.getSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage }), gui.withGpgHandling, func() string { return gui.State.failedCommitMessage }, - func() []*models.Commit { return gui.State.Model.Commits }, gui.getSelectedPath, gui.switchToMerge, gui.helpers.Suggestions, @@ -613,9 +611,9 @@ func (gui *Gui) resetControllers() { ), Tags: controllers.NewTagsController( controllerCommon, - func() *context.TagsContext { return gui.State.Contexts.Tags }, + gui.State.Contexts.Tags, gui.git, - getContexts, + gui.State.Contexts, gui.helpers.Tags, gui.helpers.Refs, gui.helpers.Suggestions, @@ -623,7 +621,7 @@ func (gui *Gui) resetControllers() { ), LocalCommits: controllers.NewLocalCommitsController( controllerCommon, - func() types.IListContext { return gui.State.Contexts.BranchCommits }, + gui.State.Contexts.BranchCommits, osCommand, gui.git, gui.helpers.Tags, @@ -631,7 +629,7 @@ func (gui *Gui) resetControllers() { gui.helpers.CherryPick, gui.helpers.Rebase, gui.getSelectedLocalCommit, - func() []*models.Commit { return gui.State.Model.Commits }, + model, func() int { return gui.State.Panels.Commits.SelectedLineIdx }, gui.helpers.Rebase.CheckMergeOrRebase, syncController.HandlePull, @@ -644,20 +642,20 @@ func (gui *Gui) resetControllers() { ), Remotes: controllers.NewRemotesController( controllerCommon, - func() types.IListContext { return gui.State.Contexts.Remotes }, + gui.State.Contexts.Remotes, gui.git, - getContexts, + gui.State.Contexts, gui.getSelectedRemote, func(branches []*models.RemoteBranch) { gui.State.Model.RemoteBranches = branches }, ), Menu: controllers.NewMenuController( controllerCommon, - func() types.IListContext { return gui.State.Contexts.Menu }, + gui.State.Contexts.Menu, gui.getSelectedMenuItem, ), Bisect: controllers.NewBisectController( controllerCommon, - func() types.IListContext { return gui.State.Contexts.BranchCommits }, + gui.State.Contexts.BranchCommits, gui.git, gui.helpers.Bisect, gui.getSelectedLocalCommit, From 226985bf7602763f7578ef236bdc4cec3a1494e9 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 5 Feb 2022 10:31:07 +1100 Subject: [PATCH 049/385] refactor keybindings --- pkg/gui/context/base_context.go | 24 ++++++- pkg/gui/context/commit_files_context.go | 2 + pkg/gui/context/list_context_trait.go | 29 ++++----- pkg/gui/context/tags_context.go | 2 + pkg/gui/context/working_tree_context.go | 2 + pkg/gui/controllers/bisect_controller.go | 7 +- pkg/gui/controllers/files_controller.go | 44 ++++++------- .../controllers/local_commits_controller.go | 65 +++++++++---------- pkg/gui/controllers/menu_controller.go | 11 ++-- pkg/gui/controllers/remotes_controller.go | 15 ++--- pkg/gui/controllers/submodules_controller.go | 21 +++--- pkg/gui/controllers/sync_controller.go | 11 ++-- pkg/gui/controllers/tags_controller.go | 17 +++-- pkg/gui/controllers/undo_controller.go | 11 +--- pkg/gui/gui.go | 27 ++++++-- pkg/gui/keybindings.go | 36 ++++------ pkg/gui/list_context.go | 35 +++++----- pkg/gui/list_context_config.go | 40 ++++++------ pkg/gui/types/context.go | 17 +++-- 19 files changed, 215 insertions(+), 201 deletions(-) diff --git a/pkg/gui/context/base_context.go b/pkg/gui/context/base_context.go index f6007fe5f..c61f57cf4 100644 --- a/pkg/gui/context/base_context.go +++ b/pkg/gui/context/base_context.go @@ -1,6 +1,8 @@ package context -import "github.com/jesseduffield/lazygit/pkg/gui/types" +import ( + "github.com/jesseduffield/lazygit/pkg/gui/types" +) type BaseContext struct { kind types.ContextKind @@ -9,9 +11,14 @@ type BaseContext struct { windowName string onGetOptionsMap func() map[string]string + keybindingsFns []types.KeybindingsFn + keybindings []*types.Binding + *ParentContextMgr } +var _ types.IBaseContext = &BaseContext{} + type NewBaseContextOpts struct { Kind types.ContextKind Key types.ContextKey @@ -58,3 +65,18 @@ func (self *BaseContext) GetKind() types.ContextKind { func (self *BaseContext) GetKey() types.ContextKey { return self.key } + +func (self *BaseContext) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + bindings := []*types.Binding{} + for i := range self.keybindingsFns { + // the first binding in the bindings array takes precedence but we want the + // last keybindingsFn to take precedence to we add them in reverse + bindings = append(bindings, self.keybindingsFns[len(self.keybindingsFns)-1-i](opts)...) + } + + return bindings +} + +func (self *BaseContext) AddKeybindingsFn(fn types.KeybindingsFn) { + self.keybindingsFns = append(self.keybindingsFns, fn) +} diff --git a/pkg/gui/context/commit_files_context.go b/pkg/gui/context/commit_files_context.go index dd557f6b2..49a9f34da 100644 --- a/pkg/gui/context/commit_files_context.go +++ b/pkg/gui/context/commit_files_context.go @@ -55,6 +55,8 @@ func NewCommitFilesContext( c: c, } + baseContext.AddKeybindingsFn(listContextTrait.keybindings) + self.BaseContext = baseContext self.ListContextTrait = listContextTrait self.CommitFileTreeViewModel = viewModel diff --git a/pkg/gui/context/list_context_trait.go b/pkg/gui/context/list_context_trait.go index c1d45eb4e..50a91b827 100644 --- a/pkg/gui/context/list_context_trait.go +++ b/pkg/gui/context/list_context_trait.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -182,32 +181,28 @@ func (self *ListContextTrait) HandleRenderToMain() error { return nil } -func (self *ListContextTrait) Keybindings( - getKey func(key string) interface{}, - config config.KeybindingConfig, - guards types.KeybindingGuards, -) []*types.Binding { +func (self *ListContextTrait) keybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ - {Tag: "navigation", Key: getKey(config.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: getKey(config.Universal.PrevItem), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, {Tag: "navigation", Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: getKey(config.Universal.NextItemAlt), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: getKey(config.Universal.NextItem), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: getKey(config.Universal.PrevPage), Modifier: gocui.ModNone, Handler: self.HandlePrevPage, Description: self.c.Tr.LcPrevPage}, - {Tag: "navigation", Key: getKey(config.Universal.NextPage), Modifier: gocui.ModNone, Handler: self.HandleNextPage, Description: self.c.Tr.LcNextPage}, - {Tag: "navigation", Key: getKey(config.Universal.GotoTop), Modifier: gocui.ModNone, Handler: self.HandleGotoTop, Description: self.c.Tr.LcGotoTop}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItem), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevPage), Modifier: gocui.ModNone, Handler: self.HandlePrevPage, Description: self.c.Tr.LcPrevPage}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextPage), Modifier: gocui.ModNone, Handler: self.HandleNextPage, Description: self.c.Tr.LcNextPage}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Modifier: gocui.ModNone, Handler: self.HandleGotoTop, Description: self.c.Tr.LcGotoTop}, {Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: func() error { return self.HandleClick(nil) }}, {Tag: "navigation", Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: getKey(config.Universal.ScrollLeft), Modifier: gocui.ModNone, Handler: self.HandleScrollLeft}, - {Tag: "navigation", Key: getKey(config.Universal.ScrollRight), Modifier: gocui.ModNone, Handler: self.HandleScrollRight}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Modifier: gocui.ModNone, Handler: self.HandleScrollLeft}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollRight), Modifier: gocui.ModNone, Handler: self.HandleScrollRight}, { - Key: getKey(config.Universal.StartSearch), + Key: opts.GetKey(opts.Config.Universal.StartSearch), Handler: func() error { self.c.OpenSearch(); return nil }, Description: self.c.Tr.LcStartSearch, Tag: "navigation", }, { - Key: getKey(config.Universal.GotoBottom), + Key: opts.GetKey(opts.Config.Universal.GotoBottom), Description: self.c.Tr.LcGotoBottom, Handler: self.HandleGotoBottom, Tag: "navigation", diff --git a/pkg/gui/context/tags_context.go b/pkg/gui/context/tags_context.go index fc6e1bde1..8644b15dc 100644 --- a/pkg/gui/context/tags_context.go +++ b/pkg/gui/context/tags_context.go @@ -55,6 +55,8 @@ func NewTagsContext( c: c, } + baseContext.AddKeybindingsFn(listContextTrait.keybindings) + self.BaseContext = baseContext self.ListContextTrait = listContextTrait self.TagsViewModel = list diff --git a/pkg/gui/context/working_tree_context.go b/pkg/gui/context/working_tree_context.go index fafddf9e8..8ab4a1403 100644 --- a/pkg/gui/context/working_tree_context.go +++ b/pkg/gui/context/working_tree_context.go @@ -55,6 +55,8 @@ func NewWorkingTreeContext( c: c, } + baseContext.AddKeybindingsFn(listContextTrait.keybindings) + self.BaseContext = baseContext self.ListContextTrait = listContextTrait self.FileTreeViewModel = viewModel diff --git a/pkg/gui/controllers/bisect_controller.go b/pkg/gui/controllers/bisect_controller.go index bb7ba642d..9841b5e59 100644 --- a/pkg/gui/controllers/bisect_controller.go +++ b/pkg/gui/controllers/bisect_controller.go @@ -7,7 +7,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -43,11 +42,11 @@ func NewBisectController( } } -func (self *BisectController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { +func (self *BisectController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: getKey(config.Commits.ViewBisectOptions), - Handler: guards.OutsideFilterMode(self.checkSelected(self.openMenu)), + Key: opts.GetKey(opts.Config.Commits.ViewBisectOptions), + Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.openMenu)), Description: self.c.Tr.LcViewBisectOptions, OpensMenu: true, }, diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index a7c4ff374..1f9521867 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -87,10 +87,10 @@ func NewFilesController( } } -func (self *FilesController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { - bindings := []*types.Binding{ +func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + return []*types.Binding{ { - Key: getKey(config.Universal.Select), + Key: opts.GetKey(opts.Config.Universal.Select), Handler: self.checkSelectedFileNode(self.press), Description: self.c.Tr.LcToggleStaged, }, @@ -99,103 +99,101 @@ func (self *FilesController) Keybindings(getKey func(key string) interface{}, co Handler: func() error { return self.context.HandleClick(self.checkSelectedFileNode(self.press)) }, }, { - Key: getKey(" "), // TODO: softcode + Key: opts.GetKey(" "), // TODO: softcode Handler: self.handleStatusFilterPressed, Description: self.c.Tr.LcFileFilter, }, { - Key: getKey(config.Files.CommitChanges), + Key: opts.GetKey(opts.Config.Files.CommitChanges), Handler: self.HandleCommitPress, Description: self.c.Tr.CommitChanges, }, { - Key: getKey(config.Files.CommitChangesWithoutHook), + Key: opts.GetKey(opts.Config.Files.CommitChangesWithoutHook), Handler: self.HandleWIPCommitPress, Description: self.c.Tr.LcCommitChangesWithoutHook, }, { - Key: getKey(config.Files.AmendLastCommit), + Key: opts.GetKey(opts.Config.Files.AmendLastCommit), Handler: self.handleAmendCommitPress, Description: self.c.Tr.AmendLastCommit, }, { - Key: getKey(config.Files.CommitChangesWithEditor), + Key: opts.GetKey(opts.Config.Files.CommitChangesWithEditor), Handler: self.HandleCommitEditorPress, Description: self.c.Tr.CommitChangesWithEditor, }, { - Key: getKey(config.Universal.Edit), + Key: opts.GetKey(opts.Config.Universal.Edit), Handler: self.checkSelectedFileNode(self.edit), Description: self.c.Tr.LcEditFile, }, { - Key: getKey(config.Universal.OpenFile), + Key: opts.GetKey(opts.Config.Universal.OpenFile), Handler: self.Open, Description: self.c.Tr.LcOpenFile, }, { - Key: getKey(config.Files.IgnoreFile), + Key: opts.GetKey(opts.Config.Files.IgnoreFile), Handler: self.checkSelectedFileNode(self.ignore), Description: self.c.Tr.LcIgnoreFile, }, { - Key: getKey(config.Universal.Remove), + Key: opts.GetKey(opts.Config.Universal.Remove), Handler: self.checkSelectedFileNode(self.remove), Description: self.c.Tr.LcViewDiscardOptions, OpensMenu: true, }, { - Key: getKey(config.Files.RefreshFiles), + Key: opts.GetKey(opts.Config.Files.RefreshFiles), Handler: self.refresh, Description: self.c.Tr.LcRefreshFiles, }, { - Key: getKey(config.Files.StashAllChanges), + Key: opts.GetKey(opts.Config.Files.StashAllChanges), Handler: self.stash, Description: self.c.Tr.LcStashAllChanges, }, { - Key: getKey(config.Files.ViewStashOptions), + Key: opts.GetKey(opts.Config.Files.ViewStashOptions), Handler: self.createStashMenu, Description: self.c.Tr.LcViewStashOptions, OpensMenu: true, }, { - Key: getKey(config.Files.ToggleStagedAll), + Key: opts.GetKey(opts.Config.Files.ToggleStagedAll), Handler: self.stageAll, Description: self.c.Tr.LcToggleStagedAll, }, { - Key: getKey(config.Universal.GoInto), + Key: opts.GetKey(opts.Config.Universal.GoInto), Handler: self.enter, Description: self.c.Tr.FileEnter, }, { ViewName: "", - Key: getKey(config.Universal.ExecuteCustomCommand), + Key: opts.GetKey(opts.Config.Universal.ExecuteCustomCommand), Handler: self.handleCustomCommand, Description: self.c.Tr.LcExecuteCustomCommand, }, { - Key: getKey(config.Commits.ViewResetOptions), + Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), Handler: self.createResetMenu, Description: self.c.Tr.LcViewResetToUpstreamOptions, OpensMenu: true, }, // here { - Key: getKey(config.Files.ToggleTreeView), + Key: opts.GetKey(opts.Config.Files.ToggleTreeView), Handler: self.toggleTreeView, Description: self.c.Tr.LcToggleTreeView, }, { - Key: getKey(config.Files.OpenMergeTool), + Key: opts.GetKey(opts.Config.Files.OpenMergeTool), Handler: self.OpenMergeTool, Description: self.c.Tr.LcOpenMergeTool, }, } - - return append(bindings, self.context.Keybindings(getKey, config, guards)...) } func (self *FilesController) press(node *filetree.FileNode) error { diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index 749199c1e..5458697e3 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -8,7 +8,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/hosting_service" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" - "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -91,108 +90,104 @@ func NewLocalCommitsController( } } -func (self *LocalCommitsController) Keybindings( - getKey func(key string) interface{}, - config config.KeybindingConfig, - guards types.KeybindingGuards, -) []*types.Binding { +func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { outsideFilterModeBindings := []*types.Binding{ { - Key: getKey(config.Commits.SquashDown), + Key: opts.GetKey(opts.Config.Commits.SquashDown), Handler: self.squashDown, Description: self.c.Tr.LcSquashDown, }, { - Key: getKey(config.Commits.MarkCommitAsFixup), + Key: opts.GetKey(opts.Config.Commits.MarkCommitAsFixup), Handler: self.fixup, Description: self.c.Tr.LcFixupCommit, }, { - Key: getKey(config.Commits.RenameCommit), + Key: opts.GetKey(opts.Config.Commits.RenameCommit), Handler: self.checkSelected(self.reword), Description: self.c.Tr.LcRewordCommit, }, { - Key: getKey(config.Commits.RenameCommitWithEditor), + Key: opts.GetKey(opts.Config.Commits.RenameCommitWithEditor), Handler: self.rewordEditor, Description: self.c.Tr.LcRenameCommitEditor, }, { - Key: getKey(config.Universal.Remove), + Key: opts.GetKey(opts.Config.Universal.Remove), Handler: self.drop, Description: self.c.Tr.LcDeleteCommit, }, { - Key: getKey(config.Universal.Edit), + Key: opts.GetKey(opts.Config.Universal.Edit), Handler: self.edit, Description: self.c.Tr.LcEditCommit, }, { - Key: getKey(config.Commits.PickCommit), + Key: opts.GetKey(opts.Config.Commits.PickCommit), Handler: self.pick, Description: self.c.Tr.LcPickCommit, }, { - Key: getKey(config.Commits.CreateFixupCommit), + Key: opts.GetKey(opts.Config.Commits.CreateFixupCommit), Handler: self.checkSelected(self.handleCreateFixupCommit), Description: self.c.Tr.LcCreateFixupCommit, }, { - Key: getKey(config.Commits.SquashAboveCommits), + Key: opts.GetKey(opts.Config.Commits.SquashAboveCommits), Handler: self.checkSelected(self.handleSquashAllAboveFixupCommits), Description: self.c.Tr.LcSquashAboveCommits, }, { - Key: getKey(config.Commits.MoveDownCommit), + Key: opts.GetKey(opts.Config.Commits.MoveDownCommit), Handler: self.handleCommitMoveDown, Description: self.c.Tr.LcMoveDownCommit, }, { - Key: getKey(config.Commits.MoveUpCommit), + Key: opts.GetKey(opts.Config.Commits.MoveUpCommit), Handler: self.handleCommitMoveUp, Description: self.c.Tr.LcMoveUpCommit, }, { - Key: getKey(config.Commits.AmendToCommit), + Key: opts.GetKey(opts.Config.Commits.AmendToCommit), Handler: self.handleCommitAmendTo, Description: self.c.Tr.LcAmendToCommit, }, { - Key: getKey(config.Commits.RevertCommit), + Key: opts.GetKey(opts.Config.Commits.RevertCommit), Handler: self.checkSelected(self.handleCommitRevert), Description: self.c.Tr.LcRevertCommit, }, { - Key: getKey(config.Universal.New), + Key: opts.GetKey(opts.Config.Universal.New), Modifier: gocui.ModNone, Handler: self.checkSelected(self.newBranch), Description: self.c.Tr.LcCreateNewBranchFromCommit, }, { - Key: getKey(config.Commits.CherryPickCopy), + Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), Handler: self.checkSelected(self.copy), Description: self.c.Tr.LcCherryPickCopy, }, { - Key: getKey(config.Commits.CherryPickCopyRange), + Key: opts.GetKey(opts.Config.Commits.CherryPickCopyRange), Handler: self.checkSelected(self.copyRange), Description: self.c.Tr.LcCherryPickCopyRange, }, { - Key: getKey(config.Commits.PasteCommits), - Handler: guards.OutsideFilterMode(self.paste), + Key: opts.GetKey(opts.Config.Commits.PasteCommits), + Handler: opts.Guards.OutsideFilterMode(self.paste), Description: self.c.Tr.LcPasteCommits, }, // overriding these navigation keybindings because we might need to load // more commits on demand { - Key: getKey(config.Universal.StartSearch), + Key: opts.GetKey(opts.Config.Universal.StartSearch), Handler: self.openSearch, Description: self.c.Tr.LcStartSearch, Tag: "navigation", }, { - Key: getKey(config.Universal.GotoBottom), + Key: opts.GetKey(opts.Config.Universal.GotoBottom), Handler: self.gotoBottom, Description: self.c.Tr.LcGotoBottom, Tag: "navigation", @@ -204,49 +199,49 @@ func (self *LocalCommitsController) Keybindings( } for _, binding := range outsideFilterModeBindings { - binding.Handler = guards.OutsideFilterMode(binding.Handler) + binding.Handler = opts.Guards.OutsideFilterMode(binding.Handler) } bindings := append(outsideFilterModeBindings, []*types.Binding{ { - Key: getKey(config.Commits.OpenLogMenu), + Key: opts.GetKey(opts.Config.Commits.OpenLogMenu), Handler: self.handleOpenLogMenu, Description: self.c.Tr.LcOpenLogMenu, OpensMenu: true, }, { - Key: getKey(config.Commits.ViewResetOptions), + Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), Handler: self.checkSelected(self.handleCreateCommitResetMenu), Description: self.c.Tr.LcResetToThisCommit, }, { - Key: getKey(config.Universal.GoInto), + Key: opts.GetKey(opts.Config.Universal.GoInto), Handler: self.checkSelected(self.enter), Description: self.c.Tr.LcViewCommitFiles, }, { - Key: getKey(config.Commits.CheckoutCommit), + Key: opts.GetKey(opts.Config.Commits.CheckoutCommit), Handler: self.checkSelected(self.handleCheckoutCommit), Description: self.c.Tr.LcCheckoutCommit, }, { - Key: getKey(config.Commits.TagCommit), + Key: opts.GetKey(opts.Config.Commits.TagCommit), Handler: self.checkSelected(self.handleTagCommit), Description: self.c.Tr.LcTagCommit, }, { - Key: getKey(config.Commits.CopyCommitMessageToClipboard), + Key: opts.GetKey(opts.Config.Commits.CopyCommitMessageToClipboard), Handler: self.checkSelected(self.handleCopySelectedCommitMessageToClipboard), Description: self.c.Tr.LcCopyCommitMessageToClipboard, }, { - Key: getKey(config.Commits.OpenInBrowser), + Key: opts.GetKey(opts.Config.Commits.OpenInBrowser), Handler: self.checkSelected(self.handleOpenCommitInBrowser), Description: self.c.Tr.LcOpenCommitInBrowser, }, }...) - return append(bindings, self.context.Keybindings(getKey, config, guards)...) + return bindings } func (self *LocalCommitsController) squashDown() error { diff --git a/pkg/gui/controllers/menu_controller.go b/pkg/gui/controllers/menu_controller.go index 7773a0148..7c93ef6f7 100644 --- a/pkg/gui/controllers/menu_controller.go +++ b/pkg/gui/controllers/menu_controller.go @@ -2,7 +2,6 @@ package controllers import ( "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -27,18 +26,18 @@ func NewMenuController( } } -func (self *MenuController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { +func (self *MenuController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: getKey(config.Universal.Select), + Key: opts.GetKey(opts.Config.Universal.Select), Handler: self.press, }, { - Key: getKey(config.Universal.Confirm), + Key: opts.GetKey(opts.Config.Universal.Confirm), Handler: self.press, }, { - Key: getKey(config.Universal.ConfirmAlt1), + Key: opts.GetKey(opts.Config.Universal.ConfirmAlt1), Handler: self.press, }, { @@ -47,7 +46,7 @@ func (self *MenuController) Keybindings(getKey func(key string) interface{}, con }, } - return append(bindings, self.context.Keybindings(getKey, config, guards)...) + return bindings } func (self *MenuController) press() error { diff --git a/pkg/gui/controllers/remotes_controller.go b/pkg/gui/controllers/remotes_controller.go index d9812d213..9f7acb9d0 100644 --- a/pkg/gui/controllers/remotes_controller.go +++ b/pkg/gui/controllers/remotes_controller.go @@ -4,7 +4,6 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -40,10 +39,10 @@ func NewRemotesController( } } -func (self *RemotesController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { +func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: getKey(config.Universal.GoInto), + Key: opts.GetKey(opts.Config.Universal.GoInto), Handler: self.checkSelected(self.enter), }, { @@ -51,28 +50,28 @@ func (self *RemotesController) Keybindings(getKey func(key string) interface{}, Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, }, { - Key: getKey(config.Branches.FetchRemote), + Key: opts.GetKey(opts.Config.Branches.FetchRemote), Handler: self.checkSelected(self.fetch), Description: self.c.Tr.LcFetchRemote, }, { - Key: getKey(config.Universal.New), + Key: opts.GetKey(opts.Config.Universal.New), Handler: self.add, Description: self.c.Tr.LcAddNewRemote, }, { - Key: getKey(config.Universal.Remove), + Key: opts.GetKey(opts.Config.Universal.Remove), Handler: self.checkSelected(self.remove), Description: self.c.Tr.LcRemoveRemote, }, { - Key: getKey(config.Universal.Edit), + Key: opts.GetKey(opts.Config.Universal.Edit), Handler: self.checkSelected(self.edit), Description: self.c.Tr.LcEditRemote, }, } - return append(bindings, self.context.Keybindings(getKey, config, guards)...) + return bindings } func (self *RemotesController) enter(remote *models.Remote) error { diff --git a/pkg/gui/controllers/submodules_controller.go b/pkg/gui/controllers/submodules_controller.go index 851d11983..f1ac7acf3 100644 --- a/pkg/gui/controllers/submodules_controller.go +++ b/pkg/gui/controllers/submodules_controller.go @@ -8,7 +8,6 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -40,40 +39,40 @@ func NewSubmodulesController( } } -func (self *SubmodulesController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { - bindings := []*types.Binding{ +func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + return []*types.Binding{ { - Key: getKey(config.Universal.GoInto), + Key: opts.GetKey(opts.Config.Universal.GoInto), Handler: self.checkSelected(self.enter), Description: self.c.Tr.LcEnterSubmodule, }, { - Key: getKey(config.Universal.Remove), + Key: opts.GetKey(opts.Config.Universal.Remove), Handler: self.checkSelected(self.remove), Description: self.c.Tr.LcRemoveSubmodule, }, { - Key: getKey(config.Submodules.Update), + Key: opts.GetKey(opts.Config.Submodules.Update), Handler: self.checkSelected(self.update), Description: self.c.Tr.LcSubmoduleUpdate, }, { - Key: getKey(config.Universal.New), + Key: opts.GetKey(opts.Config.Universal.New), Handler: self.add, Description: self.c.Tr.LcAddSubmodule, }, { - Key: getKey(config.Universal.Edit), + Key: opts.GetKey(opts.Config.Universal.Edit), Handler: self.checkSelected(self.editURL), Description: self.c.Tr.LcEditSubmoduleUrl, }, { - Key: getKey(config.Submodules.Init), + Key: opts.GetKey(opts.Config.Submodules.Init), Handler: self.checkSelected(self.init), Description: self.c.Tr.LcInitSubmodule, }, { - Key: getKey(config.Submodules.BulkMenu), + Key: opts.GetKey(opts.Config.Submodules.BulkMenu), Handler: self.openBulkActionsMenu, Description: self.c.Tr.LcViewBulkSubmoduleOptions, OpensMenu: true, @@ -83,8 +82,6 @@ func (self *SubmodulesController) Keybindings(getKey func(key string) interface{ Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, }, } - - return append(bindings, self.context.Keybindings(getKey, config, guards)...) } func (self *SubmodulesController) enter(submodule *models.SubmoduleConfig) error { diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go index 582d8a9de..106b4c516 100644 --- a/pkg/gui/controllers/sync_controller.go +++ b/pkg/gui/controllers/sync_controller.go @@ -7,7 +7,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -46,16 +45,16 @@ func NewSyncController( } } -func (self *SyncController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { +func (self *SyncController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: getKey(config.Universal.PushFiles), - Handler: guards.NoPopupPanel(self.HandlePush), + Key: opts.GetKey(opts.Config.Universal.PushFiles), + Handler: opts.Guards.NoPopupPanel(self.HandlePush), Description: self.c.Tr.LcPush, }, { - Key: getKey(config.Universal.PullFiles), - Handler: guards.NoPopupPanel(self.HandlePull), + Key: opts.GetKey(opts.Config.Universal.PullFiles), + Handler: opts.Guards.NoPopupPanel(self.HandlePull), Description: self.c.Tr.LcPull, }, } diff --git a/pkg/gui/controllers/tags_controller.go b/pkg/gui/controllers/tags_controller.go index 424f5a4b0..231f12736 100644 --- a/pkg/gui/controllers/tags_controller.go +++ b/pkg/gui/controllers/tags_controller.go @@ -3,7 +3,6 @@ package controllers import ( "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -48,42 +47,42 @@ func NewTagsController( } } -func (self *TagsController) Keybindings(getKey func(key string) interface{}, config config.KeybindingConfig, guards types.KeybindingGuards) []*types.Binding { +func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: getKey(config.Universal.Select), + Key: opts.GetKey(opts.Config.Universal.Select), Handler: self.withSelectedTag(self.checkout), Description: self.c.Tr.LcCheckout, }, { - Key: getKey(config.Universal.Remove), + Key: opts.GetKey(opts.Config.Universal.Remove), Handler: self.withSelectedTag(self.delete), Description: self.c.Tr.LcDeleteTag, }, { - Key: getKey(config.Branches.PushTag), + Key: opts.GetKey(opts.Config.Branches.PushTag), Handler: self.withSelectedTag(self.push), Description: self.c.Tr.LcPushTag, }, { - Key: getKey(config.Universal.New), + Key: opts.GetKey(opts.Config.Universal.New), Handler: self.create, Description: self.c.Tr.LcCreateTag, }, { - Key: getKey(config.Commits.ViewResetOptions), + Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), Handler: self.withSelectedTag(self.createResetMenu), Description: self.c.Tr.LcViewResetOptions, OpensMenu: true, }, { - Key: getKey(config.Universal.GoInto), + Key: opts.GetKey(opts.Config.Universal.GoInto), Handler: self.withSelectedTag(self.enter), Description: self.c.Tr.LcViewCommits, }, } - return append(bindings, self.context.Keybindings(getKey, config, guards)...) + return bindings } func (self *TagsController) checkout(tag *models.Tag) error { diff --git a/pkg/gui/controllers/undo_controller.go b/pkg/gui/controllers/undo_controller.go index 89bc6ea9e..0f288957c 100644 --- a/pkg/gui/controllers/undo_controller.go +++ b/pkg/gui/controllers/undo_controller.go @@ -4,7 +4,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" - "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -64,19 +63,15 @@ type reflogAction struct { to string } -func (self *UndoController) Keybindings( - getKey func(key string) interface{}, - config config.KeybindingConfig, - guards types.KeybindingGuards, -) []*types.Binding { +func (self *UndoController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { - Key: getKey(config.Universal.Undo), + Key: opts.GetKey(opts.Config.Universal.Undo), Handler: self.reflogUndo, Description: self.c.Tr.LcUndoReflog, }, { - Key: getKey(config.Universal.Redo), + Key: opts.GetKey(opts.Config.Universal.Redo), Handler: self.reflogRedo, Description: self.c.Tr.LcRedoReflog, }, diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 1b1bf6f39..116fcee2d 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -581,14 +581,16 @@ func (gui *Gui) resetControllers() { gui.helpers.Rebase.CheckMergeOrRebase, ) + submodulesController := controllers.NewSubmodulesController( + controllerCommon, + gui.State.Contexts.Submodules, + gui.git, + gui.enterSubmodule, + gui.getSelectedSubmodule, + ) + gui.Controllers = Controllers{ - Submodules: controllers.NewSubmodulesController( - controllerCommon, - gui.State.Contexts.Submodules, - gui.git, - gui.enterSubmodule, - gui.getSelectedSubmodule, - ), + Submodules: submodulesController, Files: controllers.NewFilesController( controllerCommon, gui.State.Contexts.Files, @@ -670,6 +672,17 @@ func (gui *Gui) resetControllers() { ), Sync: syncController, } + + gui.State.Contexts.Submodules.AddKeybindingsFn(gui.Controllers.Submodules.GetKeybindings) + gui.State.Contexts.Files.AddKeybindingsFn(gui.Controllers.Files.GetKeybindings) + gui.State.Contexts.Tags.AddKeybindingsFn(gui.Controllers.Tags.GetKeybindings) + // TODO: commit to one name here: local commits or branch commits + gui.State.Contexts.BranchCommits.AddKeybindingsFn(gui.Controllers.LocalCommits.GetKeybindings) + gui.State.Contexts.BranchCommits.AddKeybindingsFn(gui.Controllers.Bisect.GetKeybindings) + gui.State.Contexts.Remotes.AddKeybindingsFn(gui.Controllers.Remotes.GetKeybindings) + gui.State.Contexts.Menu.AddKeybindingsFn(gui.Controllers.Menu.GetKeybindings) + gui.State.Contexts.Menu.AddKeybindingsFn(gui.Controllers.Menu.GetKeybindings) + // TODO: handle global contexts } var RuneReplacements = map[rune]string{ diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 159965c1b..68b878a13 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -1355,16 +1355,16 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { }, } + keybindingsOpts := types.KeybindingsOpts{ + GetKey: gui.getKey, + Config: config, + Guards: guards, + } + + // global bindings for _, controller := range []types.IController{ - gui.Controllers.LocalCommits, - gui.Controllers.Submodules, - gui.Controllers.Files, - gui.Controllers.Remotes, - gui.Controllers.Menu, - gui.Controllers.Bisect, - gui.Controllers.Undo, gui.Controllers.Sync, - gui.Controllers.Tags, + gui.Controllers.Undo, } { context := controller.Context() viewName := "" @@ -1375,27 +1375,17 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { contextKeys = []string{string(context.GetKey())} } - for _, binding := range controller.Keybindings(gui.getKey, config, guards) { + for _, binding := range controller.GetKeybindings(keybindingsOpts) { binding.Contexts = contextKeys binding.ViewName = viewName bindings = append(bindings, binding) } } - // while migrating we'll continue providing keybindings from the list contexts themselves. - // for each controller we add above we need to remove the corresponding list context from here. - for _, listContext := range []types.IListContext{ - gui.State.Contexts.Branches, - gui.State.Contexts.RemoteBranches, - gui.State.Contexts.ReflogCommits, - gui.State.Contexts.SubCommits, - gui.State.Contexts.Stash, - gui.State.Contexts.CommitFiles, - gui.State.Contexts.Suggestions, - } { - viewName := listContext.GetViewName() - contextKey := listContext.GetKey() - for _, binding := range listContext.Keybindings(gui.getKey, config, guards) { + for _, context := range gui.allContexts() { + viewName := context.GetViewName() + contextKey := context.GetKey() + for _, binding := range context.GetKeybindings(keybindingsOpts) { binding.Contexts = []string{string(contextKey)} binding.ViewName = viewName bindings = append(bindings, binding) diff --git a/pkg/gui/list_context.go b/pkg/gui/list_context.go index f2da7aaac..7644df6e6 100644 --- a/pkg/gui/list_context.go +++ b/pkg/gui/list_context.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -232,32 +231,34 @@ func (self *ListContext) HandleRenderToMain() error { return nil } -func (self *ListContext) Keybindings( - getKey func(key string) interface{}, - config config.KeybindingConfig, - guards types.KeybindingGuards, -) []*types.Binding { +func (self *ListContext) attachKeybindings() *ListContext { + self.BaseContext.AddKeybindingsFn(self.keybindings) + + return self +} + +func (self *ListContext) keybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ - {Tag: "navigation", Key: getKey(config.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: getKey(config.Universal.PrevItem), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, {Tag: "navigation", Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: getKey(config.Universal.NextItemAlt), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: getKey(config.Universal.NextItem), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: getKey(config.Universal.PrevPage), Modifier: gocui.ModNone, Handler: self.HandlePrevPage, Description: self.Gui.c.Tr.LcPrevPage}, - {Tag: "navigation", Key: getKey(config.Universal.NextPage), Modifier: gocui.ModNone, Handler: self.HandleNextPage, Description: self.Gui.c.Tr.LcNextPage}, - {Tag: "navigation", Key: getKey(config.Universal.GotoTop), Modifier: gocui.ModNone, Handler: self.HandleGotoTop, Description: self.Gui.c.Tr.LcGotoTop}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItem), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevPage), Modifier: gocui.ModNone, Handler: self.HandlePrevPage, Description: self.Gui.c.Tr.LcPrevPage}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextPage), Modifier: gocui.ModNone, Handler: self.HandleNextPage, Description: self.Gui.c.Tr.LcNextPage}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Modifier: gocui.ModNone, Handler: self.HandleGotoTop, Description: self.Gui.c.Tr.LcGotoTop}, {Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: func() error { return self.HandleClick(nil) }}, {Tag: "navigation", Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: getKey(config.Universal.ScrollLeft), Modifier: gocui.ModNone, Handler: self.HandleScrollLeft}, - {Tag: "navigation", Key: getKey(config.Universal.ScrollRight), Modifier: gocui.ModNone, Handler: self.HandleScrollRight}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Modifier: gocui.ModNone, Handler: self.HandleScrollLeft}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollRight), Modifier: gocui.ModNone, Handler: self.HandleScrollRight}, { - Key: getKey(config.Universal.StartSearch), + Key: opts.GetKey(opts.Config.Universal.StartSearch), Handler: func() error { return self.Gui.handleOpenSearch(self.GetViewName()) }, Description: self.Gui.c.Tr.LcStartSearch, Tag: "navigation", }, { - Key: getKey(config.Universal.GotoBottom), + Key: opts.GetKey(opts.Config.Universal.GotoBottom), Description: self.Gui.c.Tr.LcGotoBottom, Handler: self.HandleGotoBottom, Tag: "navigation", diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index 5d82df653..704ffb4b4 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -13,7 +13,7 @@ import ( ) func (gui *Gui) menuListContext() types.IListContext { - return &ListContext{ + return (&ListContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ ViewName: "menu", Key: "menu", @@ -25,7 +25,7 @@ func (gui *Gui) menuListContext() types.IListContext { Gui: gui, // no GetDisplayStrings field because we do a custom render on menu creation - } + }).attachKeybindings() } func (gui *Gui) filesListContext() *context.WorkingTreeContext { @@ -49,7 +49,7 @@ func (gui *Gui) filesListContext() *context.WorkingTreeContext { } func (gui *Gui) branchesListContext() types.IListContext { - return &ListContext{ + return (&ListContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ ViewName: "branches", WindowName: "branches", @@ -70,11 +70,11 @@ func (gui *Gui) branchesListContext() types.IListContext { } return item.ID() }, - } + }).attachKeybindings() } func (gui *Gui) remotesListContext() types.IListContext { - return &ListContext{ + return (&ListContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ ViewName: "branches", WindowName: "branches", @@ -95,11 +95,11 @@ func (gui *Gui) remotesListContext() types.IListContext { } return item.ID() }, - } + }).attachKeybindings() } func (gui *Gui) remoteBranchesListContext() types.IListContext { - return &ListContext{ + return (&ListContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ ViewName: "branches", WindowName: "branches", @@ -120,7 +120,7 @@ func (gui *Gui) remoteBranchesListContext() types.IListContext { } return item.ID() }, - } + }).attachKeybindings() } func (gui *Gui) withDiffModeCheck(f func() error) func() error { @@ -149,7 +149,7 @@ func (gui *Gui) tagsListContext() *context.TagsContext { func (gui *Gui) branchCommitsListContext() types.IListContext { parseEmoji := gui.c.UserConfig.Git.ParseEmoji - return &ListContext{ + return (&ListContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ ViewName: "commits", WindowName: "commits", @@ -190,12 +190,12 @@ func (gui *Gui) branchCommitsListContext() types.IListContext { return item.ID() }, RenderSelection: true, - } + }).attachKeybindings() } func (gui *Gui) subCommitsListContext() types.IListContext { parseEmoji := gui.c.UserConfig.Git.ParseEmoji - return &ListContext{ + return (&ListContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ ViewName: "branches", WindowName: "branches", @@ -235,7 +235,7 @@ func (gui *Gui) subCommitsListContext() types.IListContext { return item.ID() }, RenderSelection: true, - } + }).attachKeybindings() } func (gui *Gui) shouldShowGraph() bool { @@ -259,7 +259,7 @@ func (gui *Gui) shouldShowGraph() bool { func (gui *Gui) reflogCommitsListContext() types.IListContext { parseEmoji := gui.c.UserConfig.Git.ParseEmoji - return &ListContext{ + return (&ListContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ ViewName: "commits", WindowName: "commits", @@ -286,11 +286,11 @@ func (gui *Gui) reflogCommitsListContext() types.IListContext { } return item.ID() }, - } + }).attachKeybindings() } func (gui *Gui) stashListContext() types.IListContext { - return &ListContext{ + return (&ListContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ ViewName: "stash", WindowName: "stash", @@ -311,7 +311,7 @@ func (gui *Gui) stashListContext() types.IListContext { } return item.ID() }, - } + }).attachKeybindings() } func (gui *Gui) commitFilesListContext() *context.CommitFilesContext { @@ -339,7 +339,7 @@ func (gui *Gui) commitFilesListContext() *context.CommitFilesContext { } func (gui *Gui) submodulesListContext() types.IListContext { - return &ListContext{ + return (&ListContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ ViewName: "files", WindowName: "files", @@ -360,11 +360,11 @@ func (gui *Gui) submodulesListContext() types.IListContext { } return item.ID() }, - } + }).attachKeybindings() } func (gui *Gui) suggestionsListContext() types.IListContext { - return &ListContext{ + return (&ListContext{ BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ ViewName: "suggestions", WindowName: "suggestions", @@ -377,7 +377,7 @@ func (gui *Gui) suggestionsListContext() types.IListContext { GetDisplayStrings: func(startIdx int, length int) [][]string { return presentation.GetSuggestionListDisplayStrings(gui.State.Suggestions) }, - } + }).attachKeybindings() } func (gui *Gui) getListContexts() []types.IListContext { diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index fcbadfd22..e4a11779e 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -28,6 +28,9 @@ type IBaseContext interface { GetKey() ContextKey GetOptionsMap() map[string]string + + GetKeybindings(opts KeybindingsOpts) []*Binding + AddKeybindingsFn(KeybindingsFn) } type Context interface { @@ -46,12 +49,16 @@ type OnFocusOpts struct { type ContextKey string +type KeybindingsOpts struct { + GetKey func(key string) interface{} + Config config.KeybindingConfig + Guards KeybindingGuards +} + +type KeybindingsFn func(opts KeybindingsOpts) []*Binding + type HasKeybindings interface { - Keybindings( - getKey func(key string) interface{}, - config config.KeybindingConfig, - guards KeybindingGuards, - ) []*Binding + GetKeybindings(opts KeybindingsOpts) []*Binding } type IController interface { From 8e3484d8e98faf12f8395eaf5f9e8381f77a8e52 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 5 Feb 2022 11:00:57 +1100 Subject: [PATCH 050/385] add global controller --- pkg/gui/controllers/files_controller.go | 31 ----------- pkg/gui/controllers/global_controller.go | 68 +++++++++++++++++++++++ pkg/gui/controllers/suggestions_helper.go | 16 ++---- pkg/gui/gui.go | 6 ++ pkg/gui/keybindings.go | 1 + 5 files changed, 79 insertions(+), 43 deletions(-) create mode 100644 pkg/gui/controllers/global_controller.go diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index 1f9521867..c8af30e62 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -170,12 +170,6 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types Handler: self.enter, Description: self.c.Tr.FileEnter, }, - { - ViewName: "", - Key: opts.GetKey(opts.Config.Universal.ExecuteCustomCommand), - Handler: self.handleCustomCommand, - Description: self.c.Tr.LcExecuteCustomCommand, - }, { Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), Handler: self.createResetMenu, @@ -577,31 +571,6 @@ func (self *FilesController) switchToMerge() error { return self.switchToMergeFn(file.Name) } -func (self *FilesController) handleCustomCommand() error { - return self.c.Prompt(types.PromptOpts{ - Title: self.c.Tr.CustomCommand, - FindSuggestionsFunc: self.suggestionsHelper.GetCustomCommandsHistorySuggestionsFunc(), - HandleConfirm: func(command string) error { - self.c.GetAppState().CustomCommandsHistory = utils.Limit( - utils.Uniq( - append(self.c.GetAppState().CustomCommandsHistory, command), - ), - 1000, - ) - - err := self.c.SaveAppState() - if err != nil { - self.c.Log.Error(err) - } - - self.c.LogAction(self.c.Tr.Actions.CustomCommand) - return self.c.RunSubprocessAndRefresh( - self.os.Cmd.NewShell(command), - ) - }, - }) -} - func (self *FilesController) createStashMenu() error { return self.c.Menu(types.CreateMenuOptions{ Title: self.c.Tr.LcStashOptions, diff --git a/pkg/gui/controllers/global_controller.go b/pkg/gui/controllers/global_controller.go new file mode 100644 index 000000000..3560a0412 --- /dev/null +++ b/pkg/gui/controllers/global_controller.go @@ -0,0 +1,68 @@ +package controllers + +import ( + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +type GlobalController struct { + c *types.ControllerCommon + os *oscommands.OSCommand +} + +func NewGlobalController( + c *types.ControllerCommon, + os *oscommands.OSCommand, +) *GlobalController { + return &GlobalController{ + c: c, + os: os, + } +} + +func (self *GlobalController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + return []*types.Binding{ + { + Key: opts.GetKey(opts.Config.Universal.ExecuteCustomCommand), + Handler: self.customCommand, + Description: self.c.Tr.LcExecuteCustomCommand, + }, + } +} + +func (self *GlobalController) customCommand() error { + return self.c.Prompt(types.PromptOpts{ + Title: self.c.Tr.CustomCommand, + FindSuggestionsFunc: self.GetCustomCommandsHistorySuggestionsFunc(), + HandleConfirm: func(command string) error { + self.c.GetAppState().CustomCommandsHistory = utils.Limit( + utils.Uniq( + append(self.c.GetAppState().CustomCommandsHistory, command), + ), + 1000, + ) + + err := self.c.SaveAppState() + if err != nil { + self.c.Log.Error(err) + } + + self.c.LogAction(self.c.Tr.Actions.CustomCommand) + return self.c.RunSubprocessAndRefresh( + self.os.Cmd.NewShell(command), + ) + }, + }) +} + +func (self *GlobalController) GetCustomCommandsHistorySuggestionsFunc() func(string) []*types.Suggestion { + // reversing so that we display the latest command first + history := utils.Reverse(self.c.GetAppState().CustomCommandsHistory) + + return FuzzySearchFunc(history) +} + +func (self *GlobalController) Context() types.Context { + return nil +} diff --git a/pkg/gui/controllers/suggestions_helper.go b/pkg/gui/controllers/suggestions_helper.go index 8a58e0e56..e696fdd8e 100644 --- a/pkg/gui/controllers/suggestions_helper.go +++ b/pkg/gui/controllers/suggestions_helper.go @@ -27,7 +27,6 @@ type ISuggestionsHelper interface { GetFilePathSuggestionsFunc() func(string) []*types.Suggestion GetRemoteBranchesSuggestionsFunc(separator string) func(string) []*types.Suggestion GetRefsSuggestionsFunc() func(string) []*types.Suggestion - GetCustomCommandsHistorySuggestionsFunc() func(string) []*types.Suggestion } type SuggestionsHelper struct { @@ -73,7 +72,7 @@ func matchesToSuggestions(matches []string) []*types.Suggestion { func (self *SuggestionsHelper) GetRemoteSuggestionsFunc() func(string) []*types.Suggestion { remoteNames := self.getRemoteNames() - return fuzzySearchFunc(remoteNames) + return FuzzySearchFunc(remoteNames) } func (self *SuggestionsHelper) getBranchNames() []string { @@ -172,7 +171,7 @@ func (self *SuggestionsHelper) getRemoteBranchNames(separator string) []string { } func (self *SuggestionsHelper) GetRemoteBranchesSuggestionsFunc(separator string) func(string) []*types.Suggestion { - return fuzzySearchFunc(self.getRemoteBranchNames(separator)) + return FuzzySearchFunc(self.getRemoteBranchNames(separator)) } func (self *SuggestionsHelper) getTagNames() []string { @@ -191,17 +190,10 @@ func (self *SuggestionsHelper) GetRefsSuggestionsFunc() func(string) []*types.Su refNames := append(append(append(remoteBranchNames, localBranchNames...), tagNames...), additionalRefNames...) - return fuzzySearchFunc(refNames) + return FuzzySearchFunc(refNames) } -func (self *SuggestionsHelper) GetCustomCommandsHistorySuggestionsFunc() func(string) []*types.Suggestion { - // reversing so that we display the latest command first - history := utils.Reverse(self.c.GetAppState().CustomCommandsHistory) - - return fuzzySearchFunc(history) -} - -func fuzzySearchFunc(options []string) func(string) []*types.Suggestion { +func FuzzySearchFunc(options []string) func(string) []*types.Suggestion { return func(input string) []*types.Suggestion { var matches []string if input == "" { diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 116fcee2d..2b4fe66ca 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -222,6 +222,7 @@ type Controllers struct { Bisect *controllers.BisectController Undo *controllers.UndoController Sync *controllers.SyncController + Global *controllers.GlobalController } type listPanelState struct { @@ -591,6 +592,10 @@ func (gui *Gui) resetControllers() { gui.Controllers = Controllers{ Submodules: submodulesController, + Global: controllers.NewGlobalController( + controllerCommon, + osCommand, + ), Files: controllers.NewFilesController( controllerCommon, gui.State.Contexts.Files, @@ -674,6 +679,7 @@ func (gui *Gui) resetControllers() { } gui.State.Contexts.Submodules.AddKeybindingsFn(gui.Controllers.Submodules.GetKeybindings) + gui.Controllers.Files.Attach(gui.State.Contexts.Files) gui.State.Contexts.Files.AddKeybindingsFn(gui.Controllers.Files.GetKeybindings) gui.State.Contexts.Tags.AddKeybindingsFn(gui.Controllers.Tags.GetKeybindings) // TODO: commit to one name here: local commits or branch commits diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 68b878a13..e72e604a1 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -1365,6 +1365,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { for _, controller := range []types.IController{ gui.Controllers.Sync, gui.Controllers.Undo, + gui.Controllers.Global, } { context := controller.Context() viewName := "" From 482bdc4f1ea5448c5e98697ae66221e544ea40dd Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 5 Feb 2022 14:42:56 +1100 Subject: [PATCH 051/385] more refactoring --- pkg/cheatsheet/generate.go | 2 +- pkg/gui/commit_files_panel.go | 2 +- pkg/gui/context.go | 76 +++++----- pkg/gui/context/base_context.go | 20 ++- pkg/gui/context/context.go | 3 + pkg/gui/context_config.go | 14 +- pkg/gui/controllers/attach.go | 10 ++ pkg/gui/controllers/base_controller.go | 16 +++ pkg/gui/controllers/bisect_controller.go | 11 +- pkg/gui/controllers/files_controller.go | 25 ++++ pkg/gui/controllers/global_controller.go | 7 +- .../controllers/local_commits_controller.go | 2 + pkg/gui/controllers/menu_controller.go | 4 + pkg/gui/controllers/remotes_controller.go | 3 + pkg/gui/controllers/submodules_controller.go | 3 + pkg/gui/controllers/sync_controller.go | 11 +- pkg/gui/controllers/tags_controller.go | 3 + pkg/gui/controllers/undo_controller.go | 3 + pkg/gui/global_handlers.go | 14 -- pkg/gui/gui.go | 35 +++-- pkg/gui/gui_test.go | 1 - pkg/gui/keybindings.go | 98 ++++++------- pkg/gui/layout.go | 6 +- pkg/gui/options_menu_panel.go | 23 ++- pkg/gui/refresh.go | 12 +- pkg/gui/types/context.go | 11 +- pkg/gui/window.go | 25 ++-- vendor/github.com/jesseduffield/gocui/gui.go | 133 ++++++++++++++++-- .../jesseduffield/gocui/keybinding.go | 24 ---- vendor/github.com/jesseduffield/gocui/view.go | 2 - 30 files changed, 372 insertions(+), 227 deletions(-) create mode 100644 pkg/gui/controllers/attach.go create mode 100644 pkg/gui/controllers/base_controller.go diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index 15e390356..f499a2f58 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -124,7 +124,7 @@ func formatBinding(binding *types.Binding) string { func getBindingSections(mApp *app.App) []*bindingSection { bindingSections := []*bindingSection{} - bindings := mApp.Gui.GetInitialKeybindings() + bindings, _ := mApp.Gui.GetInitialKeybindings() type contextAndViewType struct { subtitle string diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index f55b3d6c3..05f23374c 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -257,7 +257,7 @@ func (gui *Gui) handleToggleCommitFileDirCollapsed() error { func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesContextOpts) error { // sometimes the commitFiles view is already shown in another window, so we need to ensure that window // no longer considers the commitFiles view as its main view. - gui.resetWindowForView(gui.Views.CommitFiles) + gui.resetWindowContext(gui.State.Contexts.CommitFiles) gui.State.Contexts.CommitFiles.SetSelectedLineIdx(0) gui.State.Contexts.CommitFiles.SetRefName(opts.RefName) diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 09b669b04..657274c1f 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -60,6 +60,10 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { return errors.New("cannot pass multiple opts to pushContext") } + if c.GetKey() == context.GLOBAL_CONTEXT_KEY { + return errors.New("Cannot push global context") + } + gui.State.ContextManager.Lock() // push onto stack @@ -112,6 +116,8 @@ func (gui *Gui) returnFromContext() error { gui.State.ContextManager.ContextStack = gui.State.ContextManager.ContextStack[:n] + gui.g.SetCurrentContext(string(newContext.GetKey())) + gui.State.ContextManager.Unlock() if err := gui.deactivateContext(currentContext); err != nil { @@ -146,12 +152,7 @@ func (gui *Gui) deactivateContext(c types.Context) error { // if the context's view is set to another context we do nothing. // if the context's view is the current view we trigger a focus; re-selecting the current item. func (gui *Gui) postRefreshUpdate(c types.Context) error { - v, err := gui.g.View(c.GetViewName()) - if err != nil { - return nil - } - - if types.ContextKey(v.Context) != c.GetKey() { + if gui.State.ViewContextMap[c.GetViewName()].GetKey() != c.GetKey() { return nil } @@ -174,19 +175,18 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro if err != nil { return err } - originalViewContextKey := types.ContextKey(v.Context) - - // ensure that any other window for which this view was active is now set to the default for that window. - gui.setViewAsActiveForWindow(v) - - if viewName == "main" { - gui.changeMainViewsContext(c.GetKey()) - } else { - gui.changeMainViewsContext(context.MAIN_NORMAL_CONTEXT_KEY) - } + originalViewContextKey := gui.State.ViewContextMap[viewName].GetKey() + gui.setWindowContext(c) gui.setViewTabForContext(c) + if viewName == "main" { + gui.changeMainViewsContext(c) + } else { + gui.changeMainViewsContext(gui.State.Contexts.Normal) + } + + gui.g.SetCurrentContext(string(c.GetKey())) if _, err := gui.g.SetCurrentView(viewName); err != nil { return err } @@ -200,7 +200,7 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro } } - v.Context = string(c.GetKey()) + gui.State.ViewContextMap[viewName] = c gui.g.Cursor = v.Editable @@ -310,21 +310,6 @@ func (gui *Gui) defaultSideContext() types.Context { } } -// remove the need to do this: always use a mapping -func (gui *Gui) setInitialViewContexts() { - // arguably we should only have our ViewContextMap and we should do away with - // contexts on views, or vice versa - for viewName, context := range gui.State.ViewContextMap { - // see if the view exists. If it does, set the context on it - view, err := gui.g.View(viewName) - if err != nil { - continue - } - - view.Context = string(context.GetKey()) - } -} - // getFocusLayout returns a manager function for when view gain and lose focus func (gui *Gui) getFocusLayout() func(g *gocui.Gui) error { var previousView *gocui.View @@ -364,7 +349,7 @@ func (gui *Gui) onViewFocusLost(oldView *gocui.View, newView *gocui.View) error _ = oldView.SetOriginX(0) if oldView == gui.Views.CommitFiles && newView != gui.Views.Main && newView != gui.Views.Secondary && newView != gui.Views.Search { - gui.resetWindowForView(gui.Views.CommitFiles) + gui.resetWindowContext(gui.State.Contexts.CommitFiles) if err := gui.deactivateContext(gui.State.Contexts.CommitFiles); err != nil { return err } @@ -377,20 +362,20 @@ func (gui *Gui) onViewFocusLost(oldView *gocui.View, newView *gocui.View) error // which currently just means a context that affects both the main and secondary views // other views can have their context changed directly but this function helps // keep the main and secondary views in sync -func (gui *Gui) changeMainViewsContext(contextKey types.ContextKey) { - if gui.State.MainContext == contextKey { +func (gui *Gui) changeMainViewsContext(c types.Context) { + if gui.State.MainContext == c.GetKey() { return } - switch contextKey { + switch c.GetKey() { case context.MAIN_NORMAL_CONTEXT_KEY, context.MAIN_PATCH_BUILDING_CONTEXT_KEY, context.MAIN_STAGING_CONTEXT_KEY, context.MAIN_MERGING_CONTEXT_KEY: - gui.Views.Main.Context = string(contextKey) - gui.Views.Secondary.Context = string(contextKey) + gui.State.ViewContextMap[gui.Views.Main.Name()] = c + gui.State.ViewContextMap[gui.Views.Secondary.Name()] = c default: - panic(fmt.Sprintf("unknown context for main: %s", contextKey)) + panic(fmt.Sprintf("unknown context for main: %s", c.GetKey())) } - gui.State.MainContext = contextKey + gui.State.MainContext = c.GetKey() } func (gui *Gui) viewTabNames(viewName string) []string { @@ -452,8 +437,11 @@ func (gui *Gui) contextForContextKey(contextKey types.ContextKey) (types.Context } func (gui *Gui) rerenderView(view *gocui.View) error { - contextKey := types.ContextKey(view.Context) - context := gui.mustContextForContextKey(contextKey) + context, ok := gui.State.ViewContextMap[view.Name()] + + if !ok { + panic("no context set against view " + view.Name()) + } return context.HandleRender() } @@ -467,6 +455,10 @@ func (gui *Gui) getSideContextSelectedItemId() string { return currentSideContext.GetSelectedItemId() } +func (gui *Gui) isContextVisible(c types.Context) bool { + return gui.State.WindowViewNameMap[c.GetWindowName()] == c.GetViewName() && gui.State.ViewContextMap[c.GetViewName()].GetKey() == c.GetKey() +} + // currently unused // func (gui *Gui) getCurrentSideView() *gocui.View { // currentSideContext := gui.currentSideContext() diff --git a/pkg/gui/context/base_context.go b/pkg/gui/context/base_context.go index c61f57cf4..5dbc3cbf4 100644 --- a/pkg/gui/context/base_context.go +++ b/pkg/gui/context/base_context.go @@ -1,6 +1,7 @@ package context import ( + "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -11,8 +12,8 @@ type BaseContext struct { windowName string onGetOptionsMap func() map[string]string - keybindingsFns []types.KeybindingsFn - keybindings []*types.Binding + keybindingsFns []types.KeybindingsFn + mouseKeybindingsFns []types.MouseKeybindingsFn *ParentContextMgr } @@ -80,3 +81,18 @@ func (self *BaseContext) GetKeybindings(opts types.KeybindingsOpts) []*types.Bin func (self *BaseContext) AddKeybindingsFn(fn types.KeybindingsFn) { self.keybindingsFns = append(self.keybindingsFns, fn) } + +func (self *BaseContext) AddMouseKeybindingsFn(fn types.MouseKeybindingsFn) { + self.mouseKeybindingsFns = append(self.mouseKeybindingsFns, fn) +} + +func (self *BaseContext) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { + bindings := []*gocui.ViewMouseBinding{} + for i := range self.mouseKeybindingsFns { + // the first binding in the bindings array takes precedence but we want the + // last keybindingsFn to take precedence to we add them in reverse + bindings = append(bindings, self.mouseKeybindingsFns[len(self.mouseKeybindingsFns)-1-i](opts)...) + } + + return bindings +} diff --git a/pkg/gui/context/context.go b/pkg/gui/context/context.go index 20d67a5a7..b45a089be 100644 --- a/pkg/gui/context/context.go +++ b/pkg/gui/context/context.go @@ -3,6 +3,7 @@ package context import "github.com/jesseduffield/lazygit/pkg/gui/types" const ( + GLOBAL_CONTEXT_KEY types.ContextKey = "global" STATUS_CONTEXT_KEY types.ContextKey = "status" FILES_CONTEXT_KEY types.ContextKey = "files" LOCAL_BRANCHES_CONTEXT_KEY types.ContextKey = "localBranches" @@ -29,6 +30,7 @@ const ( ) var AllContextKeys = []types.ContextKey{ + GLOBAL_CONTEXT_KEY, STATUS_CONTEXT_KEY, FILES_CONTEXT_KEY, LOCAL_BRANCHES_CONTEXT_KEY, @@ -55,6 +57,7 @@ var AllContextKeys = []types.ContextKey{ } type ContextTree struct { + Global types.Context Status types.Context Files *WorkingTreeContext Submodules types.IListContext diff --git a/pkg/gui/context_config.go b/pkg/gui/context_config.go index eec6cdd69..4e5c241d0 100644 --- a/pkg/gui/context_config.go +++ b/pkg/gui/context_config.go @@ -7,6 +7,7 @@ import ( func (gui *Gui) allContexts() []types.Context { return []types.Context{ + gui.State.Contexts.Global, gui.State.Contexts.Status, gui.State.Contexts.Files, gui.State.Contexts.Submodules, @@ -34,12 +35,23 @@ func (gui *Gui) allContexts() []types.Context { func (gui *Gui) contextTree() *context.ContextTree { return &context.ContextTree{ + Global: NewSimpleContext( + context.NewBaseContext(context.NewBaseContextOpts{ + Kind: types.GLOBAL_CONTEXT, + ViewName: "", + WindowName: "", + Key: context.GLOBAL_CONTEXT_KEY, + }), + NewSimpleContextOpts{ + OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain), + }, + ), Status: NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.SIDE_CONTEXT, ViewName: "status", - Key: context.STATUS_CONTEXT_KEY, WindowName: "status", + Key: context.STATUS_CONTEXT_KEY, }), NewSimpleContextOpts{ OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain), diff --git a/pkg/gui/controllers/attach.go b/pkg/gui/controllers/attach.go new file mode 100644 index 000000000..008c15505 --- /dev/null +++ b/pkg/gui/controllers/attach.go @@ -0,0 +1,10 @@ +package controllers + +import "github.com/jesseduffield/lazygit/pkg/gui/types" + +func AttachControllers(context types.Context, controllers ...types.IController) { + for _, controller := range controllers { + context.AddKeybindingsFn(controller.GetKeybindings) + context.AddMouseKeybindingsFn(controller.GetMouseKeybindings) + } +} diff --git a/pkg/gui/controllers/base_controller.go b/pkg/gui/controllers/base_controller.go new file mode 100644 index 000000000..e510c1a9f --- /dev/null +++ b/pkg/gui/controllers/base_controller.go @@ -0,0 +1,16 @@ +package controllers + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type baseController struct{} + +func (self *baseController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + return nil +} + +func (self *baseController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { + return nil +} diff --git a/pkg/gui/controllers/bisect_controller.go b/pkg/gui/controllers/bisect_controller.go index 9841b5e59..58c8a6db7 100644 --- a/pkg/gui/controllers/bisect_controller.go +++ b/pkg/gui/controllers/bisect_controller.go @@ -11,6 +11,8 @@ import ( ) type BisectController struct { + baseController + c *types.ControllerCommon context types.IListContext git *commands.GitCommand @@ -32,10 +34,11 @@ func NewBisectController( getCommits func() []*models.Commit, ) *BisectController { return &BisectController{ - c: c, - context: context, - git: git, - bisectHelper: bisectHelper, + baseController: baseController{}, + c: c, + context: context, + git: git, + bisectHelper: bisectHelper, getSelectedLocalCommit: getSelectedLocalCommit, getCommits: getCommits, diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index c8af30e62..d853ba731 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -190,6 +190,21 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types } } +func (self *FilesController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { + return []*gocui.ViewMouseBinding{ + { + ViewName: "main", + Key: gocui.MouseLeft, + Handler: self.onClickMain, + }, + { + ViewName: "secondary", + Key: gocui.MouseLeft, + Handler: self.onClickSecondary, + }, + } +} + func (self *FilesController) press(node *filetree.FileNode) error { if node.IsLeaf() { file := node.File @@ -672,3 +687,13 @@ func (self *FilesController) handleStashSave(stashFunc func(message string) erro }, }) } + +func (self *FilesController) onClickMain(opts gocui.ViewMouseBindingOpts) error { + clickedViewLineIdx := opts.Cy + opts.Oy + return self.EnterFile(types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: clickedViewLineIdx}) +} + +func (self *FilesController) onClickSecondary(opts gocui.ViewMouseBindingOpts) error { + clickedViewLineIdx := opts.Cy + opts.Oy + return self.EnterFile(types.OnFocusOpts{ClickedViewName: "secondary", ClickedViewLineIdx: clickedViewLineIdx}) +} diff --git a/pkg/gui/controllers/global_controller.go b/pkg/gui/controllers/global_controller.go index 3560a0412..dd0c8ea3b 100644 --- a/pkg/gui/controllers/global_controller.go +++ b/pkg/gui/controllers/global_controller.go @@ -7,6 +7,8 @@ import ( ) type GlobalController struct { + baseController + c *types.ControllerCommon os *oscommands.OSCommand } @@ -16,8 +18,9 @@ func NewGlobalController( os *oscommands.OSCommand, ) *GlobalController { return &GlobalController{ - c: c, - os: os, + baseController: baseController{}, + c: c, + os: os, } } diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index 5458697e3..e962ea48e 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -22,6 +22,7 @@ type ( ) type LocalCommitsController struct { + baseController c *types.ControllerCommon context types.IListContext os *oscommands.OSCommand @@ -68,6 +69,7 @@ func NewLocalCommitsController( setShowWholeGitGraph func(bool), ) *LocalCommitsController { return &LocalCommitsController{ + baseController: baseController{}, c: c, context: context, os: os, diff --git a/pkg/gui/controllers/menu_controller.go b/pkg/gui/controllers/menu_controller.go index 7c93ef6f7..cbd24e188 100644 --- a/pkg/gui/controllers/menu_controller.go +++ b/pkg/gui/controllers/menu_controller.go @@ -6,6 +6,8 @@ import ( ) type MenuController struct { + baseController + c *types.ControllerCommon context types.IListContext @@ -20,6 +22,8 @@ func NewMenuController( getSelectedMenuItem func() *types.MenuItem, ) *MenuController { return &MenuController{ + baseController: baseController{}, + c: c, context: context, getSelectedMenuItem: getSelectedMenuItem, diff --git a/pkg/gui/controllers/remotes_controller.go b/pkg/gui/controllers/remotes_controller.go index 9f7acb9d0..73b1c57ab 100644 --- a/pkg/gui/controllers/remotes_controller.go +++ b/pkg/gui/controllers/remotes_controller.go @@ -10,6 +10,8 @@ import ( ) type RemotesController struct { + baseController + c *types.ControllerCommon context types.IListContext git *commands.GitCommand @@ -30,6 +32,7 @@ func NewRemotesController( setRemoteBranches func([]*models.RemoteBranch), ) *RemotesController { return &RemotesController{ + baseController: baseController{}, c: c, git: git, contexts: contexts, diff --git a/pkg/gui/controllers/submodules_controller.go b/pkg/gui/controllers/submodules_controller.go index f1ac7acf3..1db27f6e6 100644 --- a/pkg/gui/controllers/submodules_controller.go +++ b/pkg/gui/controllers/submodules_controller.go @@ -13,6 +13,8 @@ import ( ) type SubmodulesController struct { + baseController + c *types.ControllerCommon context types.IListContext git *commands.GitCommand @@ -31,6 +33,7 @@ func NewSubmodulesController( getSelectedSubmodule func() *models.SubmoduleConfig, ) *SubmodulesController { return &SubmodulesController{ + baseController: baseController{}, c: c, context: context, git: git, diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go index 106b4c516..f3f2894b0 100644 --- a/pkg/gui/controllers/sync_controller.go +++ b/pkg/gui/controllers/sync_controller.go @@ -11,10 +11,8 @@ import ( ) type SyncController struct { - // I've said publicly that I'm against single-letter variable names but in this - // case I would actually prefer a _zero_ letter variable name in the form of - // struct embedding, but Go does not allow hiding public fields in an embedded struct - // to the client + baseController + c *types.ControllerCommon git *commands.GitCommand @@ -35,8 +33,9 @@ func NewSyncController( CheckMergeOrRebase func(error) error, ) *SyncController { return &SyncController{ - c: c, - git: git, + baseController: baseController{}, + c: c, + git: git, getCheckedOutBranch: getCheckedOutBranch, suggestionsHelper: suggestionsHelper, diff --git a/pkg/gui/controllers/tags_controller.go b/pkg/gui/controllers/tags_controller.go index 231f12736..508820061 100644 --- a/pkg/gui/controllers/tags_controller.go +++ b/pkg/gui/controllers/tags_controller.go @@ -9,6 +9,8 @@ import ( ) type TagsController struct { + baseController + c *types.ControllerCommon context *context.TagsContext git *commands.GitCommand @@ -35,6 +37,7 @@ func NewTagsController( switchToSubCommitsContext func(string) error, ) *TagsController { return &TagsController{ + baseController: baseController{}, c: c, context: context, git: git, diff --git a/pkg/gui/controllers/undo_controller.go b/pkg/gui/controllers/undo_controller.go index 0f288957c..683fb2b84 100644 --- a/pkg/gui/controllers/undo_controller.go +++ b/pkg/gui/controllers/undo_controller.go @@ -19,6 +19,8 @@ import ( // two user actions, meaning we end up undoing reflog entry C. Redoing works in a similar way. type UndoController struct { + baseController + c *types.ControllerCommon git *commands.GitCommand @@ -39,6 +41,7 @@ func NewUndoController( getFilteredReflogCommits func() []*models.Commit, ) *UndoController { return &UndoController{ + baseController: baseController{}, c: c, git: git, refsHelper: refsHelper, diff --git a/pkg/gui/global_handlers.go b/pkg/gui/global_handlers.go index 04f7efb61..ba8a0a237 100644 --- a/pkg/gui/global_handlers.go +++ b/pkg/gui/global_handlers.go @@ -182,11 +182,6 @@ func (gui *Gui) handleRefresh() error { func (gui *Gui) handleMouseDownMain() error { switch gui.currentSideContext() { - case gui.State.Contexts.Files: - // set filename, set primary/secondary selected, set line number, then switch context - // I'll need to know it was changed though. - // Could I pass something along to the context change? - return gui.Controllers.Files.EnterFile(types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: gui.Views.Main.SelectedLineIdx()}) case gui.State.Contexts.CommitFiles: return gui.enterCommitFile(types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: gui.Views.Main.SelectedLineIdx()}) } @@ -194,15 +189,6 @@ func (gui *Gui) handleMouseDownMain() error { return nil } -func (gui *Gui) handleMouseDownSecondary() error { - switch gui.g.CurrentView() { - case gui.Views.Files: - return gui.Controllers.Files.EnterFile(types.OnFocusOpts{ClickedViewName: "secondary", ClickedViewLineIdx: gui.Views.Secondary.SelectedLineIdx()}) - } - - return nil -} - func (gui *Gui) fetch() (err error) { gui.c.LogAction("Fetch") err = gui.git.Sync.Fetch(git_commands.FetchOptions{}) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 2b4fe66ca..ccb032175 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -590,6 +590,15 @@ func (gui *Gui) resetControllers() { gui.getSelectedSubmodule, ) + bisectController := controllers.NewBisectController( + controllerCommon, + gui.State.Contexts.BranchCommits, + gui.git, + gui.helpers.Bisect, + gui.getSelectedLocalCommit, + func() []*models.Commit { return gui.State.Model.Commits }, + ) + gui.Controllers = Controllers{ Submodules: submodulesController, Global: controllers.NewGlobalController( @@ -660,14 +669,6 @@ func (gui *Gui) resetControllers() { gui.State.Contexts.Menu, gui.getSelectedMenuItem, ), - Bisect: controllers.NewBisectController( - controllerCommon, - gui.State.Contexts.BranchCommits, - gui.git, - gui.helpers.Bisect, - gui.getSelectedLocalCommit, - func() []*models.Commit { return gui.State.Model.Commits }, - ), Undo: controllers.NewUndoController( controllerCommon, gui.git, @@ -678,17 +679,13 @@ func (gui *Gui) resetControllers() { Sync: syncController, } - gui.State.Contexts.Submodules.AddKeybindingsFn(gui.Controllers.Submodules.GetKeybindings) - gui.Controllers.Files.Attach(gui.State.Contexts.Files) - gui.State.Contexts.Files.AddKeybindingsFn(gui.Controllers.Files.GetKeybindings) - gui.State.Contexts.Tags.AddKeybindingsFn(gui.Controllers.Tags.GetKeybindings) - // TODO: commit to one name here: local commits or branch commits - gui.State.Contexts.BranchCommits.AddKeybindingsFn(gui.Controllers.LocalCommits.GetKeybindings) - gui.State.Contexts.BranchCommits.AddKeybindingsFn(gui.Controllers.Bisect.GetKeybindings) - gui.State.Contexts.Remotes.AddKeybindingsFn(gui.Controllers.Remotes.GetKeybindings) - gui.State.Contexts.Menu.AddKeybindingsFn(gui.Controllers.Menu.GetKeybindings) - gui.State.Contexts.Menu.AddKeybindingsFn(gui.Controllers.Menu.GetKeybindings) - // TODO: handle global contexts + controllers.AttachControllers(gui.State.Contexts.Files, gui.Controllers.Files) + controllers.AttachControllers(gui.State.Contexts.Tags, gui.Controllers.Tags) + controllers.AttachControllers(gui.State.Contexts.Submodules, gui.Controllers.Submodules) + controllers.AttachControllers(gui.State.Contexts.BranchCommits, gui.Controllers.LocalCommits, bisectController) + controllers.AttachControllers(gui.State.Contexts.Remotes, gui.Controllers.Remotes) + controllers.AttachControllers(gui.State.Contexts.Menu, gui.Controllers.Menu) + controllers.AttachControllers(gui.State.Contexts.Global, gui.Controllers.Sync, gui.Controllers.Undo, gui.Controllers.Global) } var RuneReplacements = map[rune]string{ diff --git a/pkg/gui/gui_test.go b/pkg/gui/gui_test.go index 1290f3185..e35ab1896 100644 --- a/pkg/gui/gui_test.go +++ b/pkg/gui/gui_test.go @@ -39,7 +39,6 @@ import ( // original playback speed. Speed may be a decimal. func Test(t *testing.T) { - return mode := integration.GetModeFromEnv() speedEnv := os.Getenv("SPEED") includeSkipped := os.Getenv("INCLUDE_SKIPPED") != "" diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index e72e604a1..50a8587ec 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -194,8 +194,7 @@ func (gui *Gui) noPopupPanel(f func() error) func() error { } } -// GetInitialKeybindings is a function. -func (gui *Gui) GetInitialKeybindings() []*types.Binding { +func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBinding) { config := gui.c.UserConfig.Keybinding guards := types.KeybindingGuards{ @@ -306,12 +305,6 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Modifier: gocui.ModNone, Handler: gui.handleCreateOptionsMenu, }, - { - ViewName: "", - Key: gocui.MouseMiddle, - Modifier: gocui.ModNone, - Handler: gui.handleCreateOptionsMenu, - }, { ViewName: "status", Key: gui.getKey(config.Universal.Edit), @@ -788,13 +781,6 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Modifier: gocui.ModNone, Handler: gui.scrollDownSecondary, }, - { - ViewName: "secondary", - Contexts: []string{string(context.MAIN_NORMAL_CONTEXT_KEY)}, - Key: gocui.MouseLeft, - Modifier: gocui.ModNone, - Handler: gui.handleMouseDownSecondary, - }, { ViewName: "main", Contexts: []string{string(context.MAIN_NORMAL_CONTEXT_KEY)}, @@ -1361,35 +1347,24 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { Guards: guards, } - // global bindings - for _, controller := range []types.IController{ - gui.Controllers.Sync, - gui.Controllers.Undo, - gui.Controllers.Global, - } { - context := controller.Context() - viewName := "" - var contextKeys []string - // nil context means global keybinding - if context != nil { - viewName = context.GetViewName() - contextKeys = []string{string(context.GetKey())} - } - - for _, binding := range controller.GetKeybindings(keybindingsOpts) { - binding.Contexts = contextKeys + mouseKeybindings := []*gocui.ViewMouseBinding{} + for _, c := range gui.allContexts() { + viewName := c.GetViewName() + contextKey := c.GetKey() + for _, binding := range c.GetKeybindings(keybindingsOpts) { + // TODO: move all mouse keybindings into the mouse keybindings approach below + if !gocui.IsMouseKey(binding.Key) && contextKey != context.GLOBAL_CONTEXT_KEY { + binding.Contexts = []string{string(contextKey)} + } binding.ViewName = viewName bindings = append(bindings, binding) } - } - for _, context := range gui.allContexts() { - viewName := context.GetViewName() - contextKey := context.GetKey() - for _, binding := range context.GetKeybindings(keybindingsOpts) { - binding.Contexts = []string{string(contextKey)} - binding.ViewName = viewName - bindings = append(bindings, binding) + for _, binding := range c.GetMouseKeybindings(keybindingsOpts) { + if contextKey != context.GLOBAL_CONTEXT_KEY { + binding.FromContext = string(contextKey) + } + mouseKeybindings = append(mouseKeybindings, binding) } } @@ -1438,7 +1413,7 @@ func (gui *Gui) GetInitialKeybindings() []*types.Binding { }...) } - return bindings + return bindings, mouseKeybindings } func (gui *Gui) resetKeybindings() error { @@ -1446,7 +1421,10 @@ func (gui *Gui) resetKeybindings() error { bindings := gui.GetCustomCommandKeybindings() - bindings = append(bindings, gui.GetInitialKeybindings()...) + bindings, mouseBindings := gui.GetInitialKeybindings() + + // prepending because we want to give our custom keybindings precedence over default keybindings + bindings = append(gui.GetCustomCommandKeybindings(), bindings...) for _, binding := range bindings { if err := gui.SetKeybinding(binding); err != nil { @@ -1454,6 +1432,12 @@ func (gui *Gui) resetKeybindings() error { } } + for _, binding := range mouseBindings { + if err := gui.SetMouseKeybinding(binding); err != nil { + return err + } + } + for viewName := range gui.State.Contexts.InitialViewTabContextMap() { viewName := viewName tabClickCallback := func(tabIndex int) error { return gui.onViewTabClick(viewName, tabIndex) } @@ -1474,7 +1458,8 @@ func (gui *Gui) wrappedHandler(f func() error) func(g *gocui.Gui, v *gocui.View) func (gui *Gui) SetKeybinding(binding *types.Binding) error { handler := binding.Handler - if isMouseKey(binding.Key) { + // TODO: move all mouse-ey stuff into new mouse approach + if gocui.IsMouseKey(binding.Key) { handler = func() error { // we ignore click events on views that aren't popup panels, when a popup panel is focused if gui.popupPanelFocused() && gui.currentViewName() != binding.ViewName { @@ -1488,19 +1473,18 @@ func (gui *Gui) SetKeybinding(binding *types.Binding) error { return gui.g.SetKeybinding(binding.ViewName, binding.Contexts, binding.Key, binding.Modifier, gui.wrappedHandler(handler)) } -func isMouseKey(key interface{}) bool { - switch key { - case - gocui.MouseLeft, - gocui.MouseRight, - gocui.MouseMiddle, - gocui.MouseRelease, - gocui.MouseWheelUp, - gocui.MouseWheelDown, - gocui.MouseWheelLeft, - gocui.MouseWheelRight: - return true - default: - return false +// warning: mutates the binding +func (gui *Gui) SetMouseKeybinding(binding *gocui.ViewMouseBinding) error { + baseHandler := binding.Handler + newHandler := func(opts gocui.ViewMouseBindingOpts) error { + // we ignore click events on views that aren't popup panels, when a popup panel is focused + if gui.popupPanelFocused() && gui.currentViewName() != binding.ViewName { + return nil + } + + return baseHandler(opts) } + binding.Handler = newHandler + + return gui.g.SetViewClickBinding(binding) } diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index 7a0d98384..7f8e9edef 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -2,7 +2,6 @@ package gui import ( "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/theme" ) @@ -262,8 +261,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { continue } - // ignore contexts whose view is owned by another context right now - if types.ContextKey(view.Context) != listContext.GetKey() { + if !gui.isContextVisible(listContext) { continue } @@ -300,8 +298,6 @@ func (gui *Gui) prepareView(viewName string) (*gocui.View, error) { } func (gui *Gui) onInitialViewsCreationForRepo() error { - gui.setInitialViewContexts() - // hide any popup views. This only applies when we've just switched repos for _, viewName := range gui.popupViewNames() { view, err := gui.g.View(viewName) diff --git a/pkg/gui/options_menu_panel.go b/pkg/gui/options_menu_panel.go index 8afcaeccb..b9df16722 100644 --- a/pkg/gui/options_menu_panel.go +++ b/pkg/gui/options_menu_panel.go @@ -3,28 +3,25 @@ package gui import ( "strings" - "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) -func (gui *Gui) getBindings(v *gocui.View) []*types.Binding { +func (gui *Gui) getBindings(context types.Context) []*types.Binding { var ( bindingsGlobal, bindingsPanel []*types.Binding ) - bindings := append(gui.GetCustomCommandKeybindings(), gui.GetInitialKeybindings()...) + bindings, _ := gui.GetInitialKeybindings() + bindings = append(gui.GetCustomCommandKeybindings(), bindings...) for _, binding := range bindings { if GetKeyDisplay(binding.Key) != "" && binding.Description != "" { - switch binding.ViewName { - case "": + if len(binding.Contexts) == 0 { bindingsGlobal = append(bindingsGlobal, binding) - case v.Name(): - if len(binding.Contexts) == 0 || utils.IncludesString(binding.Contexts, v.Context) { - bindingsPanel = append(bindingsPanel, binding) - } + } else if utils.IncludesString(binding.Contexts, string(context.GetKey())) { + bindingsPanel = append(bindingsPanel, binding) } } } @@ -48,12 +45,8 @@ func opensMenuStyle(str string) string { } func (gui *Gui) handleCreateOptionsMenu() error { - view := gui.g.CurrentView() - if view == nil { - return nil - } - - bindings := gui.getBindings(view) + context := gui.currentContext() + bindings := gui.getBindings(context) menuItems := make([]*types.MenuItem, len(bindings)) diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go index 3b1932c81..a19a685dc 100644 --- a/pkg/gui/refresh.go +++ b/pkg/gui/refresh.go @@ -318,7 +318,7 @@ func (gui *Gui) refreshFilesAndSubmodules() error { gui.c.Log.Error(err) } - if types.ContextKey(gui.Views.Files.Context) == context.FILES_CONTEXT_KEY { + if gui.isContextVisible(gui.State.Contexts.Files) { // doing this a little custom (as opposed to using gui.c.PostRefreshUpdate) because we handle selecting the file explicitly below if err := gui.State.Contexts.Files.HandleRender(); err != nil { return err @@ -503,7 +503,15 @@ func (gui *Gui) refreshRemotes() error { } } - return gui.c.PostRefreshUpdate(gui.mustContextForContextKey(types.ContextKey(gui.Views.Branches.Context))) + if err := gui.c.PostRefreshUpdate(gui.State.Contexts.Remotes); err != nil { + return err + } + + if err := gui.c.PostRefreshUpdate(gui.State.Contexts.RemoteBranches); err != nil { + return err + } + + return nil } func (gui *Gui) refreshStashEntries() error { diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index e4a11779e..381374adf 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -1,6 +1,9 @@ package types -import "github.com/jesseduffield/lazygit/pkg/config" +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/config" +) type ContextKind int @@ -10,6 +13,8 @@ const ( TEMPORARY_POPUP PERSISTENT_POPUP EXTRAS_CONTEXT + // only used by the one global context + GLOBAL_CONTEXT ) type ParentContexter interface { @@ -31,6 +36,8 @@ type IBaseContext interface { GetKeybindings(opts KeybindingsOpts) []*Binding AddKeybindingsFn(KeybindingsFn) + GetMouseKeybindings(opts KeybindingsOpts) []*gocui.ViewMouseBinding + AddMouseKeybindingsFn(MouseKeybindingsFn) } type Context interface { @@ -56,9 +63,11 @@ type KeybindingsOpts struct { } type KeybindingsFn func(opts KeybindingsOpts) []*Binding +type MouseKeybindingsFn func(opts KeybindingsOpts) []*gocui.ViewMouseBinding type HasKeybindings interface { GetKeybindings(opts KeybindingsOpts) []*Binding + GetMouseKeybindings(opts KeybindingsOpts) []*gocui.ViewMouseBinding } type IController interface { diff --git a/pkg/gui/window.go b/pkg/gui/window.go index 3dccde7e7..4ea33292a 100644 --- a/pkg/gui/window.go +++ b/pkg/gui/window.go @@ -1,6 +1,8 @@ package gui -import "github.com/jesseduffield/gocui" +import ( + "github.com/jesseduffield/lazygit/pkg/gui/types" +) // A window refers to a place on the screen which can hold one or more views. // A view is a box that renders content, and within a window only one view will @@ -17,28 +19,21 @@ func (gui *Gui) getViewNameForWindow(window string) string { return viewName } -func (gui *Gui) getWindowForView(view *gocui.View) string { - if view == gui.Views.CommitFiles { - return gui.State.Contexts.CommitFiles.GetWindowName() - } - - return view.Name() -} - -func (gui *Gui) setViewAsActiveForWindow(view *gocui.View) { +// for now all we actually care about is the context's view so we're storing that +func (gui *Gui) setWindowContext(c types.Context) { if gui.State.WindowViewNameMap == nil { gui.State.WindowViewNameMap = map[string]string{} } - gui.State.WindowViewNameMap[gui.getWindowForView(view)] = view.Name() + gui.State.WindowViewNameMap[c.GetWindowName()] = c.GetViewName() } func (gui *Gui) currentWindow() string { - return gui.getWindowForView(gui.g.CurrentView()) + return gui.currentContext().GetWindowName() } -func (gui *Gui) resetWindowForView(view *gocui.View) { - window := gui.getWindowForView(view) +func (gui *Gui) resetWindowContext(c types.Context) { // we assume here that the window contains as its default view a view with the same name as the window - gui.State.WindowViewNameMap[window] = window + windowName := c.GetWindowName() + gui.State.WindowViewNameMap[windowName] = windowName } diff --git a/vendor/github.com/jesseduffield/gocui/gui.go b/vendor/github.com/jesseduffield/gocui/gui.go index 1c3b4a9cb..b374c82c0 100644 --- a/vendor/github.com/jesseduffield/gocui/gui.go +++ b/vendor/github.com/jesseduffield/gocui/gui.go @@ -69,6 +69,30 @@ type tabClickBinding struct { handler tabClickHandler } +type ViewMouseBinding struct { + // the view that is clicked + ViewName string + + // the context we are in when the click occurs. Not necessarily the context + // of the view we're clicking. If this is blank then it is a global binding. + FromContext string + + Handler func(ViewMouseBindingOpts) error + + // must be a mouse key + Key Key +} + +type ViewMouseBindingOpts struct { + // cursor x/y + Cx int + Cy int + + // origin x/y + Ox int + Oy int +} + type GuiMutexes struct { // tickingMutex ensures we don't have two loops ticking. The point of 'ticking' // is to refresh the gui rapidly so that loader characters can be animated. @@ -110,17 +134,18 @@ type Gui struct { PlayMode PlayMode StartTime time.Time - tabClickBindings []*tabClickBinding - gEvents chan GocuiEvent - userEvents chan userEvent - views []*View - currentView *View - managers []Manager - keybindings []*keybinding - maxX, maxY int - outputMode OutputMode - stop chan struct{} - blacklist []Key + tabClickBindings []*tabClickBinding + viewMouseBindings []*ViewMouseBinding + gEvents chan GocuiEvent + userEvents chan userEvent + views []*View + currentView *View + managers []Manager + keybindings []*keybinding + maxX, maxY int + outputMode OutputMode + stop chan struct{} + blacklist []Key // BgColor and FgColor allow to configure the background and foreground // colors of the GUI. @@ -162,6 +187,8 @@ type Gui struct { screen tcell.Screen suspendedMutex sync.Mutex suspended bool + + currentContext string } // NewGui returns a new Gui object with a given output mode. @@ -237,6 +264,10 @@ func (g *Gui) Size() (x, y int) { return g.maxX, g.maxY } +func (g *Gui) SetCurrentContext(context string) { + g.currentContext = context +} + // SetRune writes a rune at the given point, relative to the top-left // corner of the terminal. It checks if the position is valid and applies // the given colors. @@ -472,6 +503,7 @@ func (g *Gui) DeleteKeybinding(viewname string, key interface{}, mod Modifier) e func (g *Gui) DeleteAllKeybindings() { g.keybindings = []*keybinding{} g.tabClickBindings = []*tabClickBinding{} + g.viewMouseBindings = []*ViewMouseBinding{} } // DeleteKeybindings deletes all keybindings of view. @@ -495,6 +527,12 @@ func (g *Gui) SetTabClickBinding(viewName string, handler tabClickHandler) error return nil } +func (g *Gui) SetViewClickBinding(binding *ViewMouseBinding) error { + g.viewMouseBindings = append(g.viewMouseBindings, binding) + + return nil +} + // BlackListKeybinding adds a keybinding to the blacklist func (g *Gui) BlacklistKeybinding(k Key) error { for _, j := range g.blacklist { @@ -1098,6 +1136,17 @@ func (g *Gui) onKey(ev *GocuiEvent) error { return err } + if ev.Mod == ModNone && IsMouseKey(ev.Key) { + opts := ViewMouseBindingOpts{Cx: newCx, Cy: newCy, Ox: v.ox, Oy: v.oy} + matched, err := g.execMouseKeybindings(v.Name(), ev, opts) + if err != nil { + return err + } + if matched { + return nil + } + } + if _, err := g.execKeybindings(v, ev); err != nil { return err } @@ -1106,6 +1155,40 @@ func (g *Gui) onKey(ev *GocuiEvent) error { return nil } +func (g *Gui) execMouseKeybindings(viewName string, ev *GocuiEvent, opts ViewMouseBindingOpts) (bool, error) { + // first pass looks for ones that match both the view and the current context + for _, binding := range g.viewMouseBindings { + if binding.ViewName == viewName && binding.FromContext == g.currentContext && ev.Key == binding.Key { + return true, binding.Handler(opts) + } + } + + for _, binding := range g.viewMouseBindings { + if binding.ViewName == viewName && ev.Key == binding.Key { + return true, binding.Handler(opts) + } + } + + return false, nil +} + +func IsMouseKey(key interface{}) bool { + switch key { + case + MouseLeft, + MouseRight, + MouseMiddle, + MouseRelease, + MouseWheelUp, + MouseWheelDown, + MouseWheelLeft, + MouseWheelRight: + return true + default: + return false + } +} + // execKeybindings executes the keybinding handlers that match the passed view // and event. The value of matched is true if there is a match and no errors. func (g *Gui) execKeybindings(v *View, ev *GocuiEvent) (matched bool, err error) { @@ -1136,10 +1219,10 @@ func (g *Gui) execKeybindings(v *View, ev *GocuiEvent) (matched bool, err error) if !kb.matchKeypress(Key(ev.Key), ev.Ch, Modifier(ev.Mod)) { continue } - if kb.matchView(v) { + if g.matchView(v, kb) { return g.execKeybinding(v, kb) } - if v != nil && kb.matchView(v.ParentView) { + if v != nil && g.matchView(v.ParentView, kb) { matchingParentViewKb = kb } if globalKb == nil && kb.viewName == "" && ((v != nil && !v.Editable) || (kb.ch == 0 && kb.key != KeyCtrlU && kb.key != KeyCtrlA && kb.key != KeyCtrlE)) { @@ -1340,3 +1423,27 @@ func (g *Gui) Resume() error { return g.screen.Resume() } + +// matchView returns if the keybinding matches the current view (and the view's context) +func (g *Gui) matchView(v *View, kb *keybinding) bool { + // if the user is typing in a field, ignore char keys + if v == nil { + return false + } + if v.Editable == true && kb.ch != 0 { + return false + } + if kb.viewName != v.name { + return false + } + // if the keybinding doesn't specify contexts, it applies for all contexts + if len(kb.contexts) == 0 { + return true + } + for _, context := range kb.contexts { + if context == g.currentContext { + return true + } + } + return false +} diff --git a/vendor/github.com/jesseduffield/gocui/keybinding.go b/vendor/github.com/jesseduffield/gocui/keybinding.go index 95857656e..7a675d55b 100644 --- a/vendor/github.com/jesseduffield/gocui/keybinding.go +++ b/vendor/github.com/jesseduffield/gocui/keybinding.go @@ -124,30 +124,6 @@ func (kb *keybinding) matchKeypress(key Key, ch rune, mod Modifier) bool { return kb.key == key && kb.ch == ch && kb.mod == mod } -// matchView returns if the keybinding matches the current view (and the view's context) -func (kb *keybinding) matchView(v *View) bool { - // if the user is typing in a field, ignore char keys - if v == nil { - return false - } - if v.Editable == true && kb.ch != 0 { - return false - } - if kb.viewName != v.name { - return false - } - // if the keybinding doesn't specify contexts, it applies for all contexts - if len(kb.contexts) == 0 { - return true - } - for _, context := range kb.contexts { - if context == v.Context { - return true - } - } - return false -} - // translations for strings to keys var translate = map[string]Key{ "F1": KeyF1, diff --git a/vendor/github.com/jesseduffield/gocui/view.go b/vendor/github.com/jesseduffield/gocui/view.go index 1316ced2e..9783d7637 100644 --- a/vendor/github.com/jesseduffield/gocui/view.go +++ b/vendor/github.com/jesseduffield/gocui/view.go @@ -149,8 +149,6 @@ type View struct { // ParentView is the view which catches events bubbled up from the given view if there's no matching handler ParentView *View - Context string // this is for assigning keybindings to a view only in certain contexts - searcher *searcher // KeybindOnEdit should be set to true when you want to execute keybindings even when the view is editable From 145c69d9ae32ec8fbdd6d1e6116efec466a0a709 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 5 Feb 2022 16:56:36 +1100 Subject: [PATCH 052/385] working again --- pkg/gui/commit_files_panel.go | 10 +- pkg/gui/context.go | 58 +++---- pkg/gui/context/base_context.go | 8 + pkg/gui/context/commit_files_context.go | 1 + pkg/gui/context/context.go | 62 +++++-- pkg/gui/context/tags_context.go | 1 + pkg/gui/context/working_tree_context.go | 1 + pkg/gui/context_config.go | 13 +- pkg/gui/files_panel.go | 15 +- pkg/gui/gui.go | 160 +++++++++++++++++- pkg/gui/keybindings.go | 2 +- pkg/gui/layout.go | 124 +------------- pkg/gui/list_context_config.go | 10 ++ pkg/gui/main_panels.go | 8 + pkg/gui/merge_panel.go | 7 +- pkg/gui/patch_building_panel.go | 1 + pkg/gui/types/context.go | 1 + vendor/github.com/jesseduffield/gocui/gui.go | 2 +- vendor/github.com/jesseduffield/gocui/view.go | 2 + 19 files changed, 297 insertions(+), 189 deletions(-) diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index 05f23374c..d4cef7b14 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -46,10 +46,16 @@ func (gui *Gui) commitFilesRenderToMain() error { cmdObj := gui.git.WorkingTree.ShowFileDiffCmdObj(from, to, reverse, node.GetPath(), false) task := NewRunPtyTask(cmdObj.GetCmd()) + mainContext := gui.State.Contexts.Normal + if node.File != nil { + mainContext = gui.State.Contexts.PatchBuilding + } + return gui.refreshMainViews(refreshMainOpts{ main: &viewUpdateOpts{ - title: "Patch", - task: task, + title: "Patch", + task: task, + context: mainContext, }, secondary: gui.secondaryPatchPanelUpdateOpts(), }) diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 657274c1f..f8aa9134e 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -11,7 +11,7 @@ import ( func (gui *Gui) popupViewNames() []string { result := []string{} - for _, context := range gui.allContexts() { + for _, context := range gui.State.Contexts.Flatten() { if context.GetKind() == types.PERSISTENT_POPUP || context.GetKind() == types.TEMPORARY_POPUP { result = append(result, context.GetViewName()) } @@ -44,6 +44,10 @@ func (gui *Gui) replaceContext(c types.Context) error { gui.State.ContextManager.Lock() defer gui.State.ContextManager.Unlock() + if !c.IsFocusable() { + return nil + } + if len(gui.State.ContextManager.ContextStack) == 0 { gui.State.ContextManager.ContextStack = []types.Context{c} } else { @@ -60,8 +64,9 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { return errors.New("cannot pass multiple opts to pushContext") } - if c.GetKey() == context.GLOBAL_CONTEXT_KEY { - return errors.New("Cannot push global context") + if !c.IsFocusable() { + panic(c.GetKey()) + return nil } gui.State.ContextManager.Lock() @@ -97,7 +102,7 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { // want to switch to: you only know the view that you want to switch to. It will // look up the context currently active for that view and switch to that context func (gui *Gui) pushContextWithView(viewName string) error { - return gui.c.PushContext(gui.State.ViewContextMap[viewName]) + return gui.c.PushContext(gui.State.ViewContextMap.Get(viewName)) } func (gui *Gui) returnFromContext() error { @@ -152,7 +157,7 @@ func (gui *Gui) deactivateContext(c types.Context) error { // if the context's view is set to another context we do nothing. // if the context's view is the current view we trigger a focus; re-selecting the current item. func (gui *Gui) postRefreshUpdate(c types.Context) error { - if gui.State.ViewContextMap[c.GetViewName()].GetKey() != c.GetKey() { + if gui.State.ViewContextMap.Get(c.GetViewName()).GetKey() != c.GetKey() { return nil } @@ -175,7 +180,7 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro if err != nil { return err } - originalViewContextKey := gui.State.ViewContextMap[viewName].GetKey() + originalViewContextKey := gui.State.ViewContextMap.Get(viewName).GetKey() gui.setWindowContext(c) gui.setViewTabForContext(c) @@ -200,7 +205,7 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro } } - gui.State.ViewContextMap[viewName] = c + gui.ViewContextMapSet(viewName, c) gui.g.Cursor = v.Editable @@ -215,12 +220,19 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro return err } - // TODO: consider removing this and instead depending on the .Context field of views - gui.State.ViewContextMap[c.GetViewName()] = c - return nil } +// also setting context on view for now. We'll need to pick one of these two approaches to stick with. +func (gui *Gui) ViewContextMapSet(viewName string, c types.Context) { + gui.State.ViewContextMap.Set(viewName, c) + view, err := gui.g.View(viewName) + if err != nil { + panic(err) + } + view.Context = string(c.GetKey()) +} + // // currently unused // func (gui *Gui) renderContextStack() string { // result := "" @@ -369,8 +381,8 @@ func (gui *Gui) changeMainViewsContext(c types.Context) { switch c.GetKey() { case context.MAIN_NORMAL_CONTEXT_KEY, context.MAIN_PATCH_BUILDING_CONTEXT_KEY, context.MAIN_STAGING_CONTEXT_KEY, context.MAIN_MERGING_CONTEXT_KEY: - gui.State.ViewContextMap[gui.Views.Main.Name()] = c - gui.State.ViewContextMap[gui.Views.Secondary.Name()] = c + gui.ViewContextMapSet(gui.Views.Main.Name(), c) + gui.ViewContextMapSet(gui.Views.Secondary.Name(), c) default: panic(fmt.Sprintf("unknown context for main: %s", c.GetKey())) } @@ -416,18 +428,8 @@ func (gui *Gui) setViewTabForContext(c types.Context) { } } -func (gui *Gui) mustContextForContextKey(contextKey types.ContextKey) types.Context { - context, ok := gui.contextForContextKey(contextKey) - - if !ok { - panic(fmt.Sprintf("context not found for key %s", contextKey)) - } - - return context -} - func (gui *Gui) contextForContextKey(contextKey types.ContextKey) (types.Context, bool) { - for _, context := range gui.allContexts() { + for _, context := range gui.State.Contexts.Flatten() { if context.GetKey() == contextKey { return context, true } @@ -437,13 +439,7 @@ func (gui *Gui) contextForContextKey(contextKey types.ContextKey) (types.Context } func (gui *Gui) rerenderView(view *gocui.View) error { - context, ok := gui.State.ViewContextMap[view.Name()] - - if !ok { - panic("no context set against view " + view.Name()) - } - - return context.HandleRender() + return gui.State.ViewContextMap.Get(view.Name()).HandleRender() } func (gui *Gui) getSideContextSelectedItemId() string { @@ -456,7 +452,7 @@ func (gui *Gui) getSideContextSelectedItemId() string { } func (gui *Gui) isContextVisible(c types.Context) bool { - return gui.State.WindowViewNameMap[c.GetWindowName()] == c.GetViewName() && gui.State.ViewContextMap[c.GetViewName()].GetKey() == c.GetKey() + return gui.State.WindowViewNameMap[c.GetWindowName()] == c.GetViewName() && gui.State.ViewContextMap.Get(c.GetViewName()).GetKey() == c.GetKey() } // currently unused diff --git a/pkg/gui/context/base_context.go b/pkg/gui/context/base_context.go index 5dbc3cbf4..b4beb293d 100644 --- a/pkg/gui/context/base_context.go +++ b/pkg/gui/context/base_context.go @@ -15,6 +15,8 @@ type BaseContext struct { keybindingsFns []types.KeybindingsFn mouseKeybindingsFns []types.MouseKeybindingsFn + focusable bool + *ParentContextMgr } @@ -25,6 +27,7 @@ type NewBaseContextOpts struct { Key types.ContextKey ViewName string WindowName string + Focusable bool OnGetOptionsMap func() map[string]string } @@ -36,6 +39,7 @@ func NewBaseContext(opts NewBaseContextOpts) *BaseContext { ViewName: opts.ViewName, windowName: opts.WindowName, onGetOptionsMap: opts.OnGetOptionsMap, + focusable: opts.Focusable, ParentContextMgr: &ParentContextMgr{}, } } @@ -96,3 +100,7 @@ func (self *BaseContext) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocu return bindings } + +func (self *BaseContext) IsFocusable() bool { + return self.focusable +} diff --git a/pkg/gui/context/commit_files_context.go b/pkg/gui/context/commit_files_context.go index 49a9f34da..e729fb3c1 100644 --- a/pkg/gui/context/commit_files_context.go +++ b/pkg/gui/context/commit_files_context.go @@ -31,6 +31,7 @@ func NewCommitFilesContext( WindowName: "commits", Key: COMMIT_FILES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }) self := &CommitFilesContext{} diff --git a/pkg/gui/context/context.go b/pkg/gui/context/context.go index b45a089be..710e9a590 100644 --- a/pkg/gui/context/context.go +++ b/pkg/gui/context/context.go @@ -30,7 +30,7 @@ const ( ) var AllContextKeys = []types.ContextKey{ - GLOBAL_CONTEXT_KEY, + GLOBAL_CONTEXT_KEY, // not focusable STATUS_CONTEXT_KEY, FILES_CONTEXT_KEY, LOCAL_BRANCHES_CONTEXT_KEY, @@ -42,10 +42,10 @@ var AllContextKeys = []types.ContextKey{ SUB_COMMITS_CONTEXT_KEY, COMMIT_FILES_CONTEXT_KEY, STASH_CONTEXT_KEY, - MAIN_NORMAL_CONTEXT_KEY, + MAIN_NORMAL_CONTEXT_KEY, // not focusable MAIN_MERGING_CONTEXT_KEY, MAIN_PATCH_BUILDING_CONTEXT_KEY, - MAIN_STAGING_CONTEXT_KEY, + MAIN_STAGING_CONTEXT_KEY, // not focusable for secondary view MENU_CONTEXT_KEY, CREDENTIALS_CONTEXT_KEY, CONFIRMATION_CONTEXT_KEY, @@ -83,24 +83,50 @@ type ContextTree struct { CommandLog types.Context } -func (tree ContextTree) InitialViewContextMap() map[string]types.Context { - return map[string]types.Context{ - "status": tree.Status, - "files": tree.Files, - "branches": tree.Branches, - "commits": tree.BranchCommits, - "commitFiles": tree.CommitFiles, - "stash": tree.Stash, - "menu": tree.Menu, - "confirmation": tree.Confirmation, - "credentials": tree.Credentials, - "commitMessage": tree.CommitMessage, - "main": tree.Normal, - "secondary": tree.Normal, - "extras": tree.CommandLog, +func (self *ContextTree) Flatten() []types.Context { + return []types.Context{ + self.Global, + self.Status, + self.Files, + self.Submodules, + self.Branches, + self.Remotes, + self.RemoteBranches, + self.Tags, + self.BranchCommits, + self.CommitFiles, + self.ReflogCommits, + self.Stash, + self.Menu, + self.Confirmation, + self.Credentials, + self.CommitMessage, + self.Normal, + self.Staging, + self.Merging, + self.PatchBuilding, + self.SubCommits, + self.Suggestions, + self.CommandLog, } } +type ViewContextMap struct { + content map[string]types.Context +} + +func NewViewContextMap() *ViewContextMap { + return &ViewContextMap{content: map[string]types.Context{}} +} + +func (self *ViewContextMap) Get(viewName string) types.Context { + return self.content[viewName] +} + +func (self *ViewContextMap) Set(viewName string, context types.Context) { + self.content[viewName] = context +} + type TabContext struct { Tab string Contexts []types.Context diff --git a/pkg/gui/context/tags_context.go b/pkg/gui/context/tags_context.go index 8644b15dc..2f20c4363 100644 --- a/pkg/gui/context/tags_context.go +++ b/pkg/gui/context/tags_context.go @@ -31,6 +31,7 @@ func NewTagsContext( WindowName: "branches", Key: TAGS_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }) self := &TagsContext{} diff --git a/pkg/gui/context/working_tree_context.go b/pkg/gui/context/working_tree_context.go index 8ab4a1403..6179e7270 100644 --- a/pkg/gui/context/working_tree_context.go +++ b/pkg/gui/context/working_tree_context.go @@ -31,6 +31,7 @@ func NewWorkingTreeContext( WindowName: "files", Key: FILES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }) self := &WorkingTreeContext{} diff --git a/pkg/gui/context_config.go b/pkg/gui/context_config.go index 4e5c241d0..d62f9f5e1 100644 --- a/pkg/gui/context_config.go +++ b/pkg/gui/context_config.go @@ -5,7 +5,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/types" ) -func (gui *Gui) allContexts() []types.Context { +func (gui *Gui) allContexts2() []types.Context { return []types.Context{ gui.State.Contexts.Global, gui.State.Contexts.Status, @@ -41,6 +41,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "", WindowName: "", Key: context.GLOBAL_CONTEXT_KEY, + Focusable: false, }), NewSimpleContextOpts{ OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain), @@ -52,6 +53,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "status", WindowName: "status", Key: context.STATUS_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{ OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain), @@ -76,6 +78,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "main", WindowName: "main", Key: context.MAIN_NORMAL_CONTEXT_KEY, + Focusable: false, }), NewSimpleContextOpts{ OnFocus: func(opts ...types.OnFocusOpts) error { @@ -89,6 +92,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "main", WindowName: "main", Key: context.MAIN_STAGING_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{ OnFocus: func(opts ...types.OnFocusOpts) error { @@ -112,6 +116,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "main", WindowName: "main", Key: context.MAIN_PATCH_BUILDING_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{ OnFocus: func(opts ...types.OnFocusOpts) error { @@ -131,6 +136,7 @@ func (gui *Gui) contextTree() *context.ContextTree { WindowName: "main", Key: context.MAIN_MERGING_CONTEXT_KEY, OnGetOptionsMap: gui.getMergingOptions, + Focusable: true, }), NewSimpleContextOpts{ OnFocus: OnFocusWrapper(func() error { return gui.renderConflictsWithLock(true) }), @@ -142,6 +148,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "credentials", WindowName: "credentials", Key: context.CREDENTIALS_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{ OnFocus: OnFocusWrapper(gui.handleAskFocused), @@ -153,6 +160,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "confirmation", WindowName: "confirmation", Key: context.CONFIRMATION_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{ OnFocus: OnFocusWrapper(gui.handleAskFocused), @@ -164,6 +172,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "commitMessage", WindowName: "commitMessage", Key: context.COMMIT_MESSAGE_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{ OnFocus: OnFocusWrapper(gui.handleCommitMessageFocused), @@ -175,6 +184,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "search", WindowName: "search", Key: context.SEARCH_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{}, ), @@ -185,6 +195,7 @@ func (gui *Gui) contextTree() *context.ContextTree { WindowName: "extras", Key: context.COMMAND_LOG_CONTEXT_KEY, OnGetOptionsMap: gui.getMergingOptions, + Focusable: true, }), NewSimpleContextOpts{ OnFocusLost: func() error { diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index 0ffdcfc6c..5d5d65c8f 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -55,9 +55,15 @@ func (gui *Gui) filesRenderToMain() error { cmdObj := gui.git.WorkingTree.WorktreeFileDiffCmdObj(node, false, !node.GetHasUnstagedChanges() && node.GetHasStagedChanges(), gui.IgnoreWhitespaceInDiffView) + mainContext := gui.State.Contexts.Normal + if node.File != nil { + mainContext = gui.State.Contexts.Staging + } + refreshOpts := refreshMainOpts{main: &viewUpdateOpts{ - title: gui.c.Tr.UnstagedChanges, - task: NewRunPtyTask(cmdObj.GetCmd()), + title: gui.c.Tr.UnstagedChanges, + task: NewRunPtyTask(cmdObj.GetCmd()), + context: mainContext, }} if node.GetHasUnstagedChanges() { @@ -65,8 +71,9 @@ func (gui *Gui) filesRenderToMain() error { cmdObj := gui.git.WorkingTree.WorktreeFileDiffCmdObj(node, false, true, gui.IgnoreWhitespaceInDiffView) refreshOpts.secondary = &viewUpdateOpts{ - title: gui.c.Tr.StagedChanges, - task: NewRunPtyTask(cmdObj.GetCmd()), + title: gui.c.Tr.StagedChanges, + task: NewRunPtyTask(cmdObj.GetCmd()), + context: mainContext, } } } else { diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index ccb032175..f8479c111 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -193,7 +193,7 @@ type GuiRepoState struct { MainContext types.ContextKey // used to keep the main and secondary views' contexts in sync ContextManager ContextManager Contexts *context.ContextTree - ViewContextMap map[string]types.Context + ViewContextMap *context.ViewContextMap ViewTabContextMap map[string][]context.TabContext // WindowViewNameMap is a mapping of windows to the current view of that window. @@ -417,13 +417,23 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { } } - contexts := gui.contextTree() + contextTree := gui.contextTree() screenMode := SCREEN_NORMAL - var initialContext types.IListContext = contexts.Files + var initialContext types.IListContext = contextTree.Files if filterPath != "" { screenMode = SCREEN_HALF - initialContext = contexts.BranchCommits + initialContext = contextTree.BranchCommits + } + + viewContextMap := context.NewViewContextMap() + for viewName, context := range initialViewContextMapping(contextTree) { + viewContextMap.Set(viewName, context) + view, err := gui.g.View(viewName) + if err != nil { + panic(err) + } + view.Context = string(context.GetKey()) } gui.State = &GuiRepoState{ @@ -461,17 +471,35 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { CherryPicking: cherrypicking.New(), Diffing: diffing.New(), }, - ViewContextMap: contexts.InitialViewContextMap(), - ViewTabContextMap: contexts.InitialViewTabContextMap(), + ViewContextMap: viewContextMap, + ViewTabContextMap: contextTree.InitialViewTabContextMap(), ScreenMode: screenMode, // TODO: put contexts in the context manager ContextManager: NewContextManager(initialContext), - Contexts: contexts, + Contexts: contextTree, } gui.RepoStateMap[Repo(currentDir)] = gui.State } +func initialViewContextMapping(contextTree *context.ContextTree) map[string]types.Context { + return map[string]types.Context{ + "status": contextTree.Status, + "files": contextTree.Files, + "branches": contextTree.Branches, + "commits": contextTree.BranchCommits, + "commitFiles": contextTree.CommitFiles, + "stash": contextTree.Stash, + "menu": contextTree.Menu, + "confirmation": contextTree.Confirmation, + "credentials": contextTree.Credentials, + "commitMessage": contextTree.CommitMessage, + "main": contextTree.Normal, + "secondary": contextTree.Normal, + "extras": contextTree.CommandLog, + } +} + // for now the split view will always be on // NewGui builds a new gui handler func NewGui( @@ -760,6 +788,10 @@ func (gui *Gui) Run(filterPath string) error { gui.g.SetManager(gocui.ManagerFunc(gui.layout), gocui.ManagerFunc(gui.getFocusLayout())) + if err := gui.createAllViews(); err != nil { + return err + } + // onNewRepo must be called after g.SetManager because SetManager deletes keybindings if err := gui.onNewRepo(filterPath, false); err != nil { return err @@ -777,6 +809,120 @@ func (gui *Gui) Run(filterPath string) error { return gui.g.MainLoop() } +func (gui *Gui) createAllViews() error { + viewNameMappings := []struct { + viewPtr **gocui.View + name string + }{ + {viewPtr: &gui.Views.Status, name: "status"}, + {viewPtr: &gui.Views.Files, name: "files"}, + {viewPtr: &gui.Views.Branches, name: "branches"}, + {viewPtr: &gui.Views.Commits, name: "commits"}, + {viewPtr: &gui.Views.Stash, name: "stash"}, + {viewPtr: &gui.Views.CommitFiles, name: "commitFiles"}, + {viewPtr: &gui.Views.Main, name: "main"}, + {viewPtr: &gui.Views.Secondary, name: "secondary"}, + {viewPtr: &gui.Views.Options, name: "options"}, + {viewPtr: &gui.Views.AppStatus, name: "appStatus"}, + {viewPtr: &gui.Views.Information, name: "information"}, + {viewPtr: &gui.Views.Search, name: "search"}, + {viewPtr: &gui.Views.SearchPrefix, name: "searchPrefix"}, + {viewPtr: &gui.Views.CommitMessage, name: "commitMessage"}, + {viewPtr: &gui.Views.Credentials, name: "credentials"}, + {viewPtr: &gui.Views.Menu, name: "menu"}, + {viewPtr: &gui.Views.Suggestions, name: "suggestions"}, + {viewPtr: &gui.Views.Confirmation, name: "confirmation"}, + {viewPtr: &gui.Views.Limit, name: "limit"}, + {viewPtr: &gui.Views.Extras, name: "extras"}, + } + + var err error + for _, mapping := range viewNameMappings { + *mapping.viewPtr, err = gui.prepareView(mapping.name) + if err != nil && err.Error() != UNKNOWN_VIEW_ERROR_MSG { + return err + } + } + + gui.Views.Options.Frame = false + gui.Views.Options.FgColor = theme.OptionsColor + + gui.Views.SearchPrefix.BgColor = gocui.ColorDefault + gui.Views.SearchPrefix.FgColor = gocui.ColorGreen + gui.Views.SearchPrefix.Frame = false + gui.setViewContent(gui.Views.SearchPrefix, SEARCH_PREFIX) + + gui.Views.Stash.Title = gui.c.Tr.StashTitle + gui.Views.Stash.FgColor = theme.GocuiDefaultTextColor + + gui.Views.Commits.Title = gui.c.Tr.CommitsTitle + gui.Views.Commits.FgColor = theme.GocuiDefaultTextColor + + gui.Views.CommitFiles.Title = gui.c.Tr.CommitFiles + gui.Views.CommitFiles.FgColor = theme.GocuiDefaultTextColor + + gui.Views.Branches.Title = gui.c.Tr.BranchesTitle + gui.Views.Branches.FgColor = theme.GocuiDefaultTextColor + + gui.Views.Files.Highlight = true + gui.Views.Files.Title = gui.c.Tr.FilesTitle + gui.Views.Files.FgColor = theme.GocuiDefaultTextColor + + gui.Views.Secondary.Title = gui.c.Tr.DiffTitle + gui.Views.Secondary.Wrap = true + gui.Views.Secondary.FgColor = theme.GocuiDefaultTextColor + gui.Views.Secondary.IgnoreCarriageReturns = true + + gui.Views.Main.Title = gui.c.Tr.DiffTitle + gui.Views.Main.Wrap = true + gui.Views.Main.FgColor = theme.GocuiDefaultTextColor + gui.Views.Main.IgnoreCarriageReturns = true + + gui.Views.Limit.Title = gui.c.Tr.NotEnoughSpace + gui.Views.Limit.Wrap = true + + gui.Views.Status.Title = gui.c.Tr.StatusTitle + gui.Views.Status.FgColor = theme.GocuiDefaultTextColor + + gui.Views.Search.BgColor = gocui.ColorDefault + gui.Views.Search.FgColor = gocui.ColorGreen + gui.Views.Search.Frame = false + gui.Views.Search.Editable = true + + gui.Views.AppStatus.BgColor = gocui.ColorDefault + gui.Views.AppStatus.FgColor = gocui.ColorCyan + gui.Views.AppStatus.Frame = false + gui.Views.AppStatus.Visible = false + + gui.Views.CommitMessage.Visible = false + gui.Views.CommitMessage.Title = gui.c.Tr.CommitMessage + gui.Views.CommitMessage.FgColor = theme.GocuiDefaultTextColor + gui.Views.CommitMessage.Editable = true + gui.Views.CommitMessage.Editor = gocui.EditorFunc(gui.commitMessageEditor) + + gui.Views.Confirmation.Visible = false + + gui.Views.Credentials.Visible = false + gui.Views.Credentials.Title = gui.c.Tr.CredentialsUsername + gui.Views.Credentials.FgColor = theme.GocuiDefaultTextColor + gui.Views.Credentials.Editable = true + + gui.Views.Suggestions.Visible = false + + gui.Views.Menu.Visible = false + + gui.Views.Information.BgColor = gocui.ColorDefault + gui.Views.Information.FgColor = gocui.ColorGreen + gui.Views.Information.Frame = false + + gui.Views.Extras.Title = gui.c.Tr.CommandLog + gui.Views.Extras.FgColor = theme.GocuiDefaultTextColor + gui.Views.Extras.Autoscroll = true + gui.Views.Extras.Wrap = true + + return nil +} + func (gui *Gui) RunAndHandleError(filterPath string) error { gui.stopChan = make(chan struct{}) return utils.SafeWithError(func() error { diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 50a8587ec..0083cd940 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -1348,7 +1348,7 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin } mouseKeybindings := []*gocui.ViewMouseBinding{} - for _, c := range gui.allContexts() { + for _, c := range gui.State.Contexts.Flatten() { viewName := c.GetViewName() contextKey := c.GetKey() for _, binding := range c.GetKeybindings(keybindingsOpts) { diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index 7f8e9edef..097625f4c 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -7,130 +7,12 @@ import ( const SEARCH_PREFIX = "search: " -func (gui *Gui) createAllViews() error { - viewNameMappings := []struct { - viewPtr **gocui.View - name string - }{ - {viewPtr: &gui.Views.Status, name: "status"}, - {viewPtr: &gui.Views.Files, name: "files"}, - {viewPtr: &gui.Views.Branches, name: "branches"}, - {viewPtr: &gui.Views.Commits, name: "commits"}, - {viewPtr: &gui.Views.Stash, name: "stash"}, - {viewPtr: &gui.Views.CommitFiles, name: "commitFiles"}, - {viewPtr: &gui.Views.Main, name: "main"}, - {viewPtr: &gui.Views.Secondary, name: "secondary"}, - {viewPtr: &gui.Views.Options, name: "options"}, - {viewPtr: &gui.Views.AppStatus, name: "appStatus"}, - {viewPtr: &gui.Views.Information, name: "information"}, - {viewPtr: &gui.Views.Search, name: "search"}, - {viewPtr: &gui.Views.SearchPrefix, name: "searchPrefix"}, - {viewPtr: &gui.Views.CommitMessage, name: "commitMessage"}, - {viewPtr: &gui.Views.Credentials, name: "credentials"}, - {viewPtr: &gui.Views.Menu, name: "menu"}, - {viewPtr: &gui.Views.Suggestions, name: "suggestions"}, - {viewPtr: &gui.Views.Confirmation, name: "confirmation"}, - {viewPtr: &gui.Views.Limit, name: "limit"}, - {viewPtr: &gui.Views.Extras, name: "extras"}, - } - - var err error - for _, mapping := range viewNameMappings { - *mapping.viewPtr, err = gui.prepareView(mapping.name) - if err != nil && err.Error() != UNKNOWN_VIEW_ERROR_MSG { - return err - } - } - - gui.Views.Options.Frame = false - gui.Views.Options.FgColor = theme.OptionsColor - - gui.Views.SearchPrefix.BgColor = gocui.ColorDefault - gui.Views.SearchPrefix.FgColor = gocui.ColorGreen - gui.Views.SearchPrefix.Frame = false - gui.setViewContent(gui.Views.SearchPrefix, SEARCH_PREFIX) - - gui.Views.Stash.Title = gui.c.Tr.StashTitle - gui.Views.Stash.FgColor = theme.GocuiDefaultTextColor - - gui.Views.Commits.Title = gui.c.Tr.CommitsTitle - gui.Views.Commits.FgColor = theme.GocuiDefaultTextColor - - gui.Views.CommitFiles.Title = gui.c.Tr.CommitFiles - gui.Views.CommitFiles.FgColor = theme.GocuiDefaultTextColor - - gui.Views.Branches.Title = gui.c.Tr.BranchesTitle - gui.Views.Branches.FgColor = theme.GocuiDefaultTextColor - - gui.Views.Files.Highlight = true - gui.Views.Files.Title = gui.c.Tr.FilesTitle - gui.Views.Files.FgColor = theme.GocuiDefaultTextColor - - gui.Views.Secondary.Title = gui.c.Tr.DiffTitle - gui.Views.Secondary.Wrap = true - gui.Views.Secondary.FgColor = theme.GocuiDefaultTextColor - gui.Views.Secondary.IgnoreCarriageReturns = true - - gui.Views.Main.Title = gui.c.Tr.DiffTitle - gui.Views.Main.Wrap = true - gui.Views.Main.FgColor = theme.GocuiDefaultTextColor - gui.Views.Main.IgnoreCarriageReturns = true - - gui.Views.Limit.Title = gui.c.Tr.NotEnoughSpace - gui.Views.Limit.Wrap = true - - gui.Views.Status.Title = gui.c.Tr.StatusTitle - gui.Views.Status.FgColor = theme.GocuiDefaultTextColor - - gui.Views.Search.BgColor = gocui.ColorDefault - gui.Views.Search.FgColor = gocui.ColorGreen - gui.Views.Search.Frame = false - gui.Views.Search.Editable = true - - gui.Views.AppStatus.BgColor = gocui.ColorDefault - gui.Views.AppStatus.FgColor = gocui.ColorCyan - gui.Views.AppStatus.Frame = false - gui.Views.AppStatus.Visible = false - - gui.Views.CommitMessage.Visible = false - gui.Views.CommitMessage.Title = gui.c.Tr.CommitMessage - gui.Views.CommitMessage.FgColor = theme.GocuiDefaultTextColor - gui.Views.CommitMessage.Editable = true - gui.Views.CommitMessage.Editor = gocui.EditorFunc(gui.commitMessageEditor) - - gui.Views.Confirmation.Visible = false - - gui.Views.Credentials.Visible = false - gui.Views.Credentials.Title = gui.c.Tr.CredentialsUsername - gui.Views.Credentials.FgColor = theme.GocuiDefaultTextColor - gui.Views.Credentials.Editable = true - - gui.Views.Suggestions.Visible = false - - gui.Views.Menu.Visible = false - - gui.Views.Information.BgColor = gocui.ColorDefault - gui.Views.Information.FgColor = gocui.ColorGreen - gui.Views.Information.Frame = false - - gui.Views.Extras.Title = gui.c.Tr.CommandLog - gui.Views.Extras.FgColor = theme.GocuiDefaultTextColor - gui.Views.Extras.Autoscroll = true - gui.Views.Extras.Wrap = true - - gui.printCommandLogHeader() - - if _, err := gui.g.SetCurrentView(gui.defaultSideContext().GetViewName()); err != nil { - return err - } - - return nil -} - // layout is called for every screen re-render e.g. when the screen is resized func (gui *Gui) layout(g *gocui.Gui) error { if !gui.ViewsSetup { - if err := gui.createAllViews(); err != nil { + gui.printCommandLogHeader() + + if _, err := gui.g.SetCurrentView(gui.defaultSideContext().GetViewName()); err != nil { return err } } diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index 704ffb4b4..dedcab4cc 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -19,6 +19,7 @@ func (gui *Gui) menuListContext() types.IListContext { Key: "menu", Kind: types.PERSISTENT_POPUP, OnGetOptionsMap: gui.getMenuOptions, + Focusable: true, }), GetItemsLength: func() int { return gui.Views.Menu.LinesHeight() }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Menu }, @@ -55,6 +56,7 @@ func (gui *Gui) branchesListContext() types.IListContext { WindowName: "branches", Key: context.LOCAL_BRANCHES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.Branches) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Branches }, @@ -80,6 +82,7 @@ func (gui *Gui) remotesListContext() types.IListContext { WindowName: "branches", Key: context.REMOTES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.Remotes) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Remotes }, @@ -105,6 +108,7 @@ func (gui *Gui) remoteBranchesListContext() types.IListContext { WindowName: "branches", Key: context.REMOTE_BRANCHES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.RemoteBranches) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.RemoteBranches }, @@ -155,6 +159,7 @@ func (gui *Gui) branchCommitsListContext() types.IListContext { WindowName: "commits", Key: context.BRANCH_COMMITS_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.Commits) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Commits }, @@ -201,6 +206,7 @@ func (gui *Gui) subCommitsListContext() types.IListContext { WindowName: "branches", Key: context.SUB_COMMITS_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.SubCommits) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.SubCommits }, @@ -265,6 +271,7 @@ func (gui *Gui) reflogCommitsListContext() types.IListContext { WindowName: "commits", Key: context.REFLOG_COMMITS_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.FilteredReflogCommits) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.ReflogCommits }, @@ -296,6 +303,7 @@ func (gui *Gui) stashListContext() types.IListContext { WindowName: "stash", Key: context.STASH_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.StashEntries) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Stash }, @@ -345,6 +353,7 @@ func (gui *Gui) submodulesListContext() types.IListContext { WindowName: "files", Key: context.SUBMODULES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.Submodules) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Submodules }, @@ -370,6 +379,7 @@ func (gui *Gui) suggestionsListContext() types.IListContext { WindowName: "suggestions", Key: context.SUGGESTIONS_CONTEXT_KEY, Kind: types.PERSISTENT_POPUP, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Suggestions) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Suggestions }, diff --git a/pkg/gui/main_panels.go b/pkg/gui/main_panels.go index bb0644585..cbb478446 100644 --- a/pkg/gui/main_panels.go +++ b/pkg/gui/main_panels.go @@ -4,6 +4,7 @@ import ( "os/exec" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) type viewUpdateOpts struct { @@ -16,6 +17,8 @@ type viewUpdateOpts struct { highlight bool task updateTask + + context types.Context } type refreshMainOpts struct { @@ -100,6 +103,11 @@ func (gui *Gui) refreshMainView(opts *viewUpdateOpts, view *gocui.View) error { view.Title = opts.title view.Wrap = !opts.noWrap view.Highlight = opts.highlight + context := opts.context + if context == nil { + context = gui.State.Contexts.Normal + } + gui.ViewContextMapSet(view.Name(), context) if err := gui.runTaskForView(view, opts.task); err != nil { gui.c.Log.Error(err) diff --git a/pkg/gui/merge_panel.go b/pkg/gui/merge_panel.go index 54783e986..60aa93a17 100644 --- a/pkg/gui/merge_panel.go +++ b/pkg/gui/merge_panel.go @@ -153,9 +153,10 @@ func (gui *Gui) renderConflicts(hasFocus bool) error { return gui.refreshMainViews(refreshMainOpts{ main: &viewUpdateOpts{ - title: gui.c.Tr.MergeConflictsTitle, - task: NewRenderStringWithoutScrollTask(content), - noWrap: true, + title: gui.c.Tr.MergeConflictsTitle, + task: NewRenderStringWithoutScrollTask(content), + context: gui.State.Contexts.Merging, + noWrap: true, }, }) } diff --git a/pkg/gui/patch_building_panel.go b/pkg/gui/patch_building_panel.go index ac09a898c..fc41bd603 100644 --- a/pkg/gui/patch_building_panel.go +++ b/pkg/gui/patch_building_panel.go @@ -136,6 +136,7 @@ func (gui *Gui) secondaryPatchPanelUpdateOpts() *viewUpdateOpts { title: "Custom Patch", noWrap: true, highlight: true, + context: gui.State.Contexts.PatchBuilding, task: NewRenderStringWithoutScrollTask(patch), } } diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index 381374adf..7b9f47001 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -31,6 +31,7 @@ type IBaseContext interface { GetWindowName() string SetWindowName(string) GetKey() ContextKey + IsFocusable() bool GetOptionsMap() map[string]string diff --git a/vendor/github.com/jesseduffield/gocui/gui.go b/vendor/github.com/jesseduffield/gocui/gui.go index b374c82c0..1c7829b57 100644 --- a/vendor/github.com/jesseduffield/gocui/gui.go +++ b/vendor/github.com/jesseduffield/gocui/gui.go @@ -1441,7 +1441,7 @@ func (g *Gui) matchView(v *View, kb *keybinding) bool { return true } for _, context := range kb.contexts { - if context == g.currentContext { + if context == v.Context { return true } } diff --git a/vendor/github.com/jesseduffield/gocui/view.go b/vendor/github.com/jesseduffield/gocui/view.go index 9783d7637..1316ced2e 100644 --- a/vendor/github.com/jesseduffield/gocui/view.go +++ b/vendor/github.com/jesseduffield/gocui/view.go @@ -149,6 +149,8 @@ type View struct { // ParentView is the view which catches events bubbled up from the given view if there's no matching handler ParentView *View + Context string // this is for assigning keybindings to a view only in certain contexts + searcher *searcher // KeybindOnEdit should be set to true when you want to execute keybindings even when the view is editable From d82f175e79f18756769d91de94458b095130297c Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 5 Feb 2022 17:04:10 +1100 Subject: [PATCH 053/385] refactor contexts --- pkg/gui/branches_panel.go | 55 ++- pkg/gui/commit_files_panel.go | 26 +- pkg/gui/commits_panel.go | 14 +- pkg/gui/confirmation_panel.go | 32 +- pkg/gui/context.go | 1 - pkg/gui/context/branches_context.go | 86 +++++ pkg/gui/context/commit_files_context.go | 58 ++-- pkg/gui/context/context.go | 32 +- pkg/gui/context/list_context_trait.go | 202 ++--------- pkg/gui/context/local_commits_context.go | 87 +++++ pkg/gui/context/menu_context.go | 108 ++++++ pkg/gui/context/reflog_commits_context.go | 86 +++++ pkg/gui/context/remote_branches_context.go | 86 +++++ pkg/gui/context/remotes_context.go | 86 +++++ pkg/gui/{ => context}/simple_context.go | 23 +- pkg/gui/context/stash_context.go | 86 +++++ pkg/gui/context/sub_commits_context.go | 87 +++++ pkg/gui/context/submodules_context.go | 86 +++++ pkg/gui/context/suggestions_context.go | 85 +++++ pkg/gui/context/tags_context.go | 84 ++--- pkg/gui/context/view_trait.go | 46 +-- .../context/viewport_list_context_trait.go | 22 ++ pkg/gui/context/working_tree_context.go | 56 ++- pkg/gui/context_config.go | 44 +-- pkg/gui/controllers/bisect_controller.go | 16 +- pkg/gui/controllers/files_controller.go | 8 +- pkg/gui/controllers/list_controller.go | 144 ++++++++ .../controllers/local_commits_controller.go | 51 ++- pkg/gui/controllers/menu_controller.go | 24 +- pkg/gui/controllers/remotes_controller.go | 18 +- pkg/gui/controllers/submodules_controller.go | 31 +- pkg/gui/controllers/tags_controller.go | 2 +- pkg/gui/custom_commands.go | 16 +- pkg/gui/diffing.go | 2 +- pkg/gui/filtering_menu_panel.go | 2 +- pkg/gui/git_flow.go | 2 +- pkg/gui/gui.go | 94 +---- pkg/gui/list_context.go | 267 -------------- pkg/gui/list_context_config.go | 327 ++++++------------ pkg/gui/menu_panel.go | 35 +- pkg/gui/options_menu_panel.go | 7 +- pkg/gui/patch_building_panel.go | 4 +- pkg/gui/patch_options_panel.go | 2 +- pkg/gui/presentation/menu.go | 7 + pkg/gui/reflog_panel.go | 22 +- pkg/gui/refresh.go | 4 +- pkg/gui/remote_branches_panel.go | 26 +- pkg/gui/remotes_panel.go | 12 +- pkg/gui/stash_panel.go | 7 +- pkg/gui/sub_commits_panel.go | 28 +- pkg/gui/submodules_panel.go | 11 +- pkg/gui/suggestions_panel.go | 9 +- pkg/gui/tags_panel.go | 2 +- pkg/gui/types/context.go | 52 +-- 54 files changed, 1562 insertions(+), 1248 deletions(-) create mode 100644 pkg/gui/context/branches_context.go create mode 100644 pkg/gui/context/local_commits_context.go create mode 100644 pkg/gui/context/menu_context.go create mode 100644 pkg/gui/context/reflog_commits_context.go create mode 100644 pkg/gui/context/remote_branches_context.go create mode 100644 pkg/gui/context/remotes_context.go rename pkg/gui/{ => context}/simple_context.go (86%) create mode 100644 pkg/gui/context/stash_context.go create mode 100644 pkg/gui/context/sub_commits_context.go create mode 100644 pkg/gui/context/submodules_context.go create mode 100644 pkg/gui/context/suggestions_context.go create mode 100644 pkg/gui/context/viewport_list_context_trait.go create mode 100644 pkg/gui/controllers/list_controller.go delete mode 100644 pkg/gui/list_context.go create mode 100644 pkg/gui/presentation/menu.go diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index f295c9470..072ee257b 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -13,22 +13,9 @@ import ( // list panel functions -func (gui *Gui) getSelectedBranch() *models.Branch { - if len(gui.State.Model.Branches) == 0 { - return nil - } - - selectedLine := gui.State.Panels.Branches.SelectedLineIdx - if selectedLine == -1 { - return nil - } - - return gui.State.Model.Branches[selectedLine] -} - func (gui *Gui) branchesRenderToMain() error { var task updateTask - branch := gui.getSelectedBranch() + branch := gui.State.Contexts.Branches.GetSelected() if branch == nil { task = NewRenderStringTask(gui.c.Tr.NoBranchesThisRepo) } else { @@ -48,24 +35,26 @@ func (gui *Gui) branchesRenderToMain() error { // specific functions func (gui *Gui) handleBranchPress() error { - if gui.State.Panels.Branches.SelectedLineIdx == -1 { + branch := gui.State.Contexts.Branches.GetSelected() + if branch == nil { return nil } - if gui.State.Panels.Branches.SelectedLineIdx == 0 { + + if branch == gui.getCheckedOutBranch() { return gui.c.ErrorMsg(gui.c.Tr.AlreadyCheckedOutBranch) } - branch := gui.getSelectedBranch() + gui.c.LogAction(gui.c.Tr.Actions.CheckoutBranch) return gui.helpers.Refs.CheckoutRef(branch.Name, types.CheckoutRefOptions{}) } func (gui *Gui) handleCreatePullRequestPress() error { - branch := gui.getSelectedBranch() + branch := gui.State.Contexts.Branches.GetSelected() return gui.createPullRequest(branch.Name, "") } func (gui *Gui) handleCreatePullRequestMenu() error { - selectedBranch := gui.getSelectedBranch() + selectedBranch := gui.State.Contexts.Branches.GetSelected() if selectedBranch == nil { return nil } @@ -77,7 +66,7 @@ func (gui *Gui) handleCreatePullRequestMenu() error { func (gui *Gui) handleCopyPullRequestURLPress() error { hostingServiceMgr := gui.getHostingServiceMgr() - branch := gui.getSelectedBranch() + branch := gui.State.Contexts.Branches.GetSelected() branchExistsOnRemote := gui.git.Remote.CheckRemoteBranchExists(branch.Name) @@ -109,7 +98,7 @@ func (gui *Gui) handleGitFetch() error { } func (gui *Gui) handleForceCheckout() error { - branch := gui.getSelectedBranch() + branch := gui.State.Contexts.Branches.GetSelected() message := gui.c.Tr.SureForceCheckout title := gui.c.Tr.ForceCheckoutBranch @@ -156,7 +145,7 @@ func (gui *Gui) getCheckedOutBranch() *models.Branch { } func (gui *Gui) createNewBranchWithName(newBranchName string) error { - branch := gui.getSelectedBranch() + branch := gui.State.Contexts.Branches.GetSelected() if branch == nil { return nil } @@ -165,7 +154,7 @@ func (gui *Gui) createNewBranchWithName(newBranchName string) error { return gui.c.Error(err) } - gui.State.Panels.Branches.SelectedLineIdx = 0 + gui.State.Contexts.Branches.SetSelectedLineIdx(0) return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) } @@ -174,7 +163,7 @@ func (gui *Gui) handleDeleteBranch() error { } func (gui *Gui) deleteBranch(force bool) error { - selectedBranch := gui.getSelectedBranch() + selectedBranch := gui.State.Contexts.Branches.GetSelected() if selectedBranch == nil { return nil } @@ -245,12 +234,12 @@ func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error { } func (gui *Gui) handleMerge() error { - selectedBranchName := gui.getSelectedBranch().Name + selectedBranchName := gui.State.Contexts.Branches.GetSelected().Name return gui.mergeBranchIntoCheckedOutBranch(selectedBranchName) } func (gui *Gui) handleRebaseOntoLocalBranch() error { - selectedBranchName := gui.getSelectedBranch().Name + selectedBranchName := gui.State.Contexts.Branches.GetSelected().Name return gui.handleRebaseOntoBranch(selectedBranchName) } @@ -279,7 +268,7 @@ func (gui *Gui) handleRebaseOntoBranch(selectedBranchName string) error { } func (gui *Gui) handleFastForward() error { - branch := gui.getSelectedBranch() + branch := gui.State.Contexts.Branches.GetSelected() if branch == nil || !branch.IsRealBranch() { return nil } @@ -305,7 +294,7 @@ func (gui *Gui) handleFastForward() error { ) return gui.c.WithLoaderPanel(message, func() error { - if gui.State.Panels.Branches.SelectedLineIdx == 0 { + if branch == gui.getCheckedOutBranch() { gui.c.LogAction(action) err := gui.git.Sync.Pull( @@ -334,7 +323,7 @@ func (gui *Gui) handleFastForward() error { } func (gui *Gui) handleCreateResetToBranchMenu() error { - branch := gui.getSelectedBranch() + branch := gui.State.Contexts.Branches.GetSelected() if branch == nil { return nil } @@ -343,7 +332,7 @@ func (gui *Gui) handleCreateResetToBranchMenu() error { } func (gui *Gui) handleRenameBranch() error { - branch := gui.getSelectedBranch() + branch := gui.State.Contexts.Branches.GetSelected() if branch == nil || !branch.IsRealBranch() { return nil } @@ -364,7 +353,7 @@ func (gui *Gui) handleRenameBranch() error { // now that we've got our stuff again we need to find that branch and reselect it. for i, newBranch := range gui.State.Model.Branches { if newBranch.Name == newBranchName { - gui.State.Panels.Branches.SetSelectedLineIdx(i) + gui.State.Contexts.Branches.SetSelectedLineIdx(i) if err := gui.State.Contexts.Branches.HandleRender(); err != nil { return err } @@ -391,7 +380,7 @@ func (gui *Gui) handleRenameBranch() error { } func (gui *Gui) handleEnterBranch() error { - branch := gui.getSelectedBranch() + branch := gui.State.Contexts.Branches.GetSelected() if branch == nil { return nil } @@ -400,7 +389,7 @@ func (gui *Gui) handleEnterBranch() error { } func (gui *Gui) handleNewBranchOffBranch() error { - selectedBranch := gui.getSelectedBranch() + selectedBranch := gui.State.Contexts.Branches.GetSelected() if selectedBranch == nil { return nil } diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index d4cef7b14..fbbedcb6f 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -5,16 +5,11 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/patch" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/controllers" - "github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/types" ) -func (gui *Gui) getSelectedCommitFileNode() *filetree.CommitFileNode { - return gui.State.Contexts.CommitFiles.GetSelectedFileNode() -} - func (gui *Gui) getSelectedCommitFile() *models.CommitFile { - node := gui.getSelectedCommitFileNode() + node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() if node == nil { return nil } @@ -22,20 +17,21 @@ func (gui *Gui) getSelectedCommitFile() *models.CommitFile { } func (gui *Gui) getSelectedCommitFilePath() string { - node := gui.getSelectedCommitFileNode() + node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() if node == nil { return "" } return node.GetPath() } +// TODO: do we need this? func (gui *Gui) onCommitFileFocus() error { gui.escapeLineByLinePanel() return nil } func (gui *Gui) commitFilesRenderToMain() error { - node := gui.getSelectedCommitFileNode() + node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() if node == nil { return nil } @@ -62,7 +58,7 @@ func (gui *Gui) commitFilesRenderToMain() error { } func (gui *Gui) handleCheckoutCommitFile() error { - node := gui.getSelectedCommitFileNode() + node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() if node == nil { return nil } @@ -88,7 +84,7 @@ func (gui *Gui) handleDiscardOldFileChange() error { HandleConfirm: func() error { return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { gui.c.LogAction(gui.c.Tr.Actions.DiscardOldFileChange) - if err := gui.git.Rebase.DiscardOldFileChanges(gui.State.Model.Commits, gui.State.Panels.Commits.SelectedLineIdx, fileName); err != nil { + if err := gui.git.Rebase.DiscardOldFileChanges(gui.State.Model.Commits, gui.State.Contexts.BranchCommits.GetSelectedLineIdx(), fileName); err != nil { if err := gui.helpers.Rebase.CheckMergeOrRebase(err); err != nil { return err } @@ -122,7 +118,7 @@ func (gui *Gui) refreshCommitFilesView() error { } func (gui *Gui) handleOpenOldCommitFile() error { - node := gui.getSelectedCommitFileNode() + node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() if node == nil { return nil } @@ -131,7 +127,7 @@ func (gui *Gui) handleOpenOldCommitFile() error { } func (gui *Gui) handleEditCommitFile() error { - node := gui.getSelectedCommitFileNode() + node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() if node == nil { return nil } @@ -144,7 +140,7 @@ func (gui *Gui) handleEditCommitFile() error { } func (gui *Gui) handleToggleFileForPatch() error { - node := gui.getSelectedCommitFileNode() + node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() if node == nil { return nil } @@ -212,7 +208,7 @@ func (gui *Gui) handleEnterCommitFile() error { } func (gui *Gui) enterCommitFile(opts types.OnFocusOpts) error { - node := gui.getSelectedCommitFileNode() + node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() if node == nil { return nil } @@ -246,7 +242,7 @@ func (gui *Gui) enterCommitFile(opts types.OnFocusOpts) error { } func (gui *Gui) handleToggleCommitFileDirCollapsed() error { - node := gui.getSelectedCommitFileNode() + node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() if node == nil { return nil } diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index 4175918ea..37e234e82 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -11,18 +11,12 @@ const COMMIT_THRESHOLD = 200 // list panel functions func (gui *Gui) getSelectedLocalCommit() *models.Commit { - selectedLine := gui.State.Panels.Commits.SelectedLineIdx - if selectedLine == -1 || selectedLine > len(gui.State.Model.Commits)-1 { - return nil - } - - return gui.State.Model.Commits[selectedLine] + return gui.State.Contexts.BranchCommits.GetSelected() } func (gui *Gui) onCommitFocus() error { - state := gui.State.Panels.Commits - if state.SelectedLineIdx > COMMIT_THRESHOLD && state.LimitCommits { - state.LimitCommits = false + if gui.State.Contexts.BranchCommits.GetSelectedLineIdx() > COMMIT_THRESHOLD && gui.State.LimitCommits { + gui.State.LimitCommits = false go utils.Safe(func() { if err := gui.refreshCommitsWithLimit(); err != nil { _ = gui.c.Error(err) @@ -37,7 +31,7 @@ func (gui *Gui) onCommitFocus() error { func (gui *Gui) branchCommitsRenderToMain() error { var task updateTask - commit := gui.getSelectedLocalCommit() + commit := gui.State.Contexts.BranchCommits.GetSelected() if commit == nil { task = NewRenderStringTask(gui.c.Tr.NoCommitsThisBranch) } else { diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index 8ed16ea39..b2cfabfab 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -77,7 +77,29 @@ func (gui *Gui) getMessageHeight(wrap bool, message string, width int) int { } func (gui *Gui) getConfirmationPanelDimensions(wrap bool, prompt string) (int, int, int, int) { + panelWidth := gui.getConfirmationPanelWidth() + panelHeight := gui.getMessageHeight(wrap, prompt, panelWidth) + return gui.getConfirmationPanelDimensionsAux(panelWidth, panelHeight) +} + +func (gui *Gui) getConfirmationPanelDimensionsForContentHeight(contentHeight int) (int, int, int, int) { + panelWidth := gui.getConfirmationPanelWidth() + return gui.getConfirmationPanelDimensionsAux(panelWidth, contentHeight) +} + +func (gui *Gui) getConfirmationPanelDimensionsAux(panelWidth int, panelHeight int) (int, int, int, int) { width, height := gui.g.Size() + if panelHeight > height*3/4 { + panelHeight = height * 3 / 4 + } + return width/2 - panelWidth/2, + height/2 - panelHeight/2 - panelHeight%2 - 1, + width/2 + panelWidth/2, + height/2 + panelHeight/2 +} + +func (gui *Gui) getConfirmationPanelWidth() int { + width, _ := gui.g.Size() // we want a minimum width up to a point, then we do it based on ratio. panelWidth := 4 * width / 7 minWidth := 80 @@ -88,14 +110,8 @@ func (gui *Gui) getConfirmationPanelDimensions(wrap bool, prompt string) (int, i panelWidth = minWidth } } - panelHeight := gui.getMessageHeight(wrap, prompt, panelWidth) - if panelHeight > height*3/4 { - panelHeight = height * 3 / 4 - } - return width/2 - panelWidth/2, - height/2 - panelHeight/2 - panelHeight%2 - 1, - width/2 + panelWidth/2, - height/2 + panelHeight/2 + + return panelWidth } func (gui *Gui) prepareConfirmationPanel( diff --git a/pkg/gui/context.go b/pkg/gui/context.go index f8aa9134e..b59f0a448 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -65,7 +65,6 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { } if !c.IsFocusable() { - panic(c.GetKey()) return nil } diff --git a/pkg/gui/context/branches_context.go b/pkg/gui/context/branches_context.go new file mode 100644 index 000000000..0be6e1dce --- /dev/null +++ b/pkg/gui/context/branches_context.go @@ -0,0 +1,86 @@ +package context + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context/traits" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type BranchesContext struct { + *BranchesViewModel + *ListContextTrait +} + +var _ types.IListContext = (*BranchesContext)(nil) + +func NewBranchesContext( + getModel func() []*models.Branch, + view *gocui.View, + getDisplayStrings func(startIdx int, length int) [][]string, + + onFocus func(...types.OnFocusOpts) error, + onRenderToMain func(...types.OnFocusOpts) error, + onFocusLost func() error, + + c *types.ControllerCommon, +) *BranchesContext { + viewModel := NewBranchesViewModel(getModel) + + return &BranchesContext{ + BranchesViewModel: viewModel, + ListContextTrait: &ListContextTrait{ + Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ + ViewName: "branches", + WindowName: "branches", + Key: LOCAL_BRANCHES_CONTEXT_KEY, + Kind: types.SIDE_CONTEXT, + Focusable: true, + }), ContextCallbackOpts{ + OnFocus: onFocus, + OnFocusLost: onFocusLost, + OnRenderToMain: onRenderToMain, + }), + list: viewModel, + viewTrait: NewViewTrait(view), + getDisplayStrings: getDisplayStrings, + c: c, + }, + } +} + +func (self *BranchesContext) GetSelectedItemId() string { + item := self.GetSelected() + if item == nil { + return "" + } + + return item.ID() +} + +type BranchesViewModel struct { + *traits.ListCursor + getModel func() []*models.Branch +} + +func NewBranchesViewModel(getModel func() []*models.Branch) *BranchesViewModel { + self := &BranchesViewModel{ + getModel: getModel, + } + + self.ListCursor = traits.NewListCursor(self) + + return self +} + +func (self *BranchesViewModel) GetItemsLength() int { + return len(self.getModel()) +} + +func (self *BranchesViewModel) GetSelected() *models.Branch { + if self.GetItemsLength() == 0 { + return nil + } + + return self.getModel()[self.GetSelectedLineIdx()] +} diff --git a/pkg/gui/context/commit_files_context.go b/pkg/gui/context/commit_files_context.go index e729fb3c1..1c555387b 100644 --- a/pkg/gui/context/commit_files_context.go +++ b/pkg/gui/context/commit_files_context.go @@ -9,7 +9,6 @@ import ( type CommitFilesContext struct { *filetree.CommitFileTreeViewModel - *BaseContext *ListContextTrait } @@ -17,7 +16,7 @@ var _ types.IListContext = (*CommitFilesContext)(nil) func NewCommitFilesContext( getModel func() []*models.CommitFile, - getView func() *gocui.View, + view *gocui.View, getDisplayStrings func(startIdx int, length int) [][]string, onFocus func(...types.OnFocusOpts) error, @@ -26,43 +25,30 @@ func NewCommitFilesContext( c *types.ControllerCommon, ) *CommitFilesContext { - baseContext := NewBaseContext(NewBaseContextOpts{ - ViewName: "commitFiles", - WindowName: "commits", - Key: COMMIT_FILES_CONTEXT_KEY, - Kind: types.SIDE_CONTEXT, - Focusable: true, - }) - - self := &CommitFilesContext{} - takeFocus := func() error { return c.PushContext(self) } - viewModel := filetree.NewCommitFileTreeViewModel(getModel, c.Log, c.UserConfig.Gui.ShowFileTree) - viewTrait := NewViewTrait(getView) - listContextTrait := &ListContextTrait{ - base: baseContext, - list: viewModel, - viewTrait: viewTrait, - GetDisplayStrings: getDisplayStrings, - OnFocus: onFocus, - OnRenderToMain: onRenderToMain, - OnFocusLost: onFocusLost, - takeFocus: takeFocus, - - // TODO: handle this in a trait - RenderSelection: false, - - c: c, + return &CommitFilesContext{ + CommitFileTreeViewModel: viewModel, + ListContextTrait: &ListContextTrait{ + Context: NewSimpleContext( + NewBaseContext(NewBaseContextOpts{ + ViewName: "commitFiles", + WindowName: "commits", + Key: COMMIT_FILES_CONTEXT_KEY, + Kind: types.SIDE_CONTEXT, + Focusable: true, + }), + ContextCallbackOpts{ + OnFocus: onFocus, + OnFocusLost: onFocusLost, + OnRenderToMain: onRenderToMain, + }), + list: viewModel, + viewTrait: NewViewTrait(view), + getDisplayStrings: getDisplayStrings, + c: c, + }, } - - baseContext.AddKeybindingsFn(listContextTrait.keybindings) - - self.BaseContext = baseContext - self.ListContextTrait = listContextTrait - self.CommitFileTreeViewModel = viewModel - - return self } func (self *CommitFilesContext) GetSelectedItemId() string { diff --git a/pkg/gui/context/context.go b/pkg/gui/context/context.go index 710e9a590..5f7c8f163 100644 --- a/pkg/gui/context/context.go +++ b/pkg/gui/context/context.go @@ -1,6 +1,10 @@ package context -import "github.com/jesseduffield/lazygit/pkg/gui/types" +import ( + "sync" + + "github.com/jesseduffield/lazygit/pkg/gui/types" +) const ( GLOBAL_CONTEXT_KEY types.ContextKey = "global" @@ -60,18 +64,18 @@ type ContextTree struct { Global types.Context Status types.Context Files *WorkingTreeContext - Submodules types.IListContext - Menu types.IListContext - Branches types.IListContext - Remotes types.IListContext - RemoteBranches types.IListContext + Menu *MenuContext + Branches *BranchesContext Tags *TagsContext - BranchCommits types.IListContext + BranchCommits *LocalCommitsContext CommitFiles *CommitFilesContext - ReflogCommits types.IListContext - SubCommits types.IListContext - Stash types.IListContext - Suggestions types.IListContext + Remotes *RemotesContext + Submodules *SubmodulesContext + RemoteBranches *RemoteBranchesContext + ReflogCommits *ReflogCommitsContext + SubCommits *SubCommitsContext + Stash *StashContext + Suggestions *SuggestionsContext Normal types.Context Staging types.Context PatchBuilding types.Context @@ -113,6 +117,7 @@ func (self *ContextTree) Flatten() []types.Context { type ViewContextMap struct { content map[string]types.Context + sync.RWMutex } func NewViewContextMap() *ViewContextMap { @@ -120,10 +125,15 @@ func NewViewContextMap() *ViewContextMap { } func (self *ViewContextMap) Get(viewName string) types.Context { + self.RLock() + defer self.RUnlock() + return self.content[viewName] } func (self *ViewContextMap) Set(viewName string, context types.Context) { + self.Lock() + defer self.Unlock() self.content[viewName] = context } diff --git a/pkg/gui/context/list_context_trait.go b/pkg/gui/context/list_context_trait.go index 50a91b827..e4fab30bf 100644 --- a/pkg/gui/context/list_context_trait.go +++ b/pkg/gui/context/list_context_trait.go @@ -3,44 +3,35 @@ package context import ( "fmt" - "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) type ListContextTrait struct { - base types.IBaseContext - list types.IList - viewTrait *ViewTrait + types.Context - takeFocus func() error - - GetDisplayStrings func(startIdx int, length int) [][]string - OnFocus func(...types.OnFocusOpts) error - OnRenderToMain func(...types.OnFocusOpts) error - OnFocusLost func() error - - // if this is true, we'll call GetDisplayStrings for just the visible part of the - // view and re-render that. This is useful when you need to render different - // content based on the selection (e.g. for showing the selected commit) - RenderSelection bool - - c *types.ControllerCommon + c *types.ControllerCommon + list types.IList + viewTrait *ViewTrait + getDisplayStrings func(startIdx int, length int) [][]string } +func (self *ListContextTrait) GetList() types.IList { + return self.list +} + +// TODO: remove func (self *ListContextTrait) GetPanelState() types.IListPanelState { return self.list } +func (self *ListContextTrait) GetViewTrait() types.IViewTrait { + return self.viewTrait +} + func (self *ListContextTrait) FocusLine() { // we need a way of knowing whether we've rendered to the view yet. self.viewTrait.FocusPoint(self.list.GetSelectedLineIdx()) - if self.RenderSelection { - min, max := self.viewTrait.ViewPortYBounds() - displayStrings := self.GetDisplayStrings(min, max) - content := utils.RenderDisplayStrings(displayStrings) - self.viewTrait.SetViewPortContent(content) - } self.viewTrait.SetFooter(formatListFooter(self.list.GetSelectedLineIdx(), self.list.GetItemsLength())) } @@ -48,164 +39,29 @@ func formatListFooter(selectedLineIdx int, length int) string { return fmt.Sprintf("%d of %d", selectedLineIdx+1, length) } -// OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view -func (self *ListContextTrait) HandleRender() error { - if self.GetDisplayStrings != nil { - self.list.RefreshSelectedIdx() - content := utils.RenderDisplayStrings(self.GetDisplayStrings(0, self.list.GetItemsLength())) - self.viewTrait.SetContent(content) - self.c.Render() - } - - return nil -} - -func (self *ListContextTrait) HandleFocusLost() error { - if self.OnFocusLost != nil { - return self.OnFocusLost() - } - - self.viewTrait.SetOriginX(0) - - return nil -} - func (self *ListContextTrait) HandleFocus(opts ...types.OnFocusOpts) error { self.FocusLine() - if self.OnFocus != nil { - if err := self.OnFocus(opts...); err != nil { - return err - } - } + return self.Context.HandleFocus(opts...) +} - if self.OnRenderToMain != nil { - if err := self.OnRenderToMain(opts...); err != nil { - return err - } - } +func (self *ListContextTrait) HandleFocusLost() error { + self.viewTrait.SetOriginX(0) + + return self.Context.HandleFocus() +} + +// OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view +func (self *ListContextTrait) HandleRender() error { + self.list.RefreshSelectedIdx() + content := utils.RenderDisplayStrings(self.getDisplayStrings(0, self.list.GetItemsLength())) + self.viewTrait.SetContent(content) + self.c.Render() return nil } -func (self *ListContextTrait) HandlePrevLine() error { - return self.handleLineChange(-1) -} - -func (self *ListContextTrait) HandleNextLine() error { - return self.handleLineChange(1) -} - -func (self *ListContextTrait) HandleScrollLeft() error { - return self.scroll(self.viewTrait.ScrollLeft) -} - -func (self *ListContextTrait) HandleScrollRight() error { - return self.scroll(self.viewTrait.ScrollRight) -} - -func (self *ListContextTrait) scroll(scrollFunc func()) error { - scrollFunc() - - return self.HandleFocus() -} - -func (self *ListContextTrait) handleLineChange(change int) error { - before := self.list.GetSelectedLineIdx() - self.list.MoveSelectedLine(change) - after := self.list.GetSelectedLineIdx() - - // doing this check so that if we're holding the up key at the start of the list - // we're not constantly re-rendering the main view. - if before != after { - return self.HandleFocus() - } - - return nil -} - -func (self *ListContextTrait) HandlePrevPage() error { - return self.handleLineChange(-self.viewTrait.PageDelta()) -} - -func (self *ListContextTrait) HandleNextPage() error { - return self.handleLineChange(self.viewTrait.PageDelta()) -} - -func (self *ListContextTrait) HandleGotoTop() error { - return self.handleLineChange(-self.list.GetItemsLength()) -} - -func (self *ListContextTrait) HandleGotoBottom() error { - return self.handleLineChange(self.list.GetItemsLength()) -} - -func (self *ListContextTrait) HandleClick(onClick func() error) error { - prevSelectedLineIdx := self.list.GetSelectedLineIdx() - // because we're handling a click, we need to determine the new line idx based - // on the view itself. - newSelectedLineIdx := self.viewTrait.SelectedLineIdx() - - currentContextKey := self.c.CurrentContext().GetKey() - alreadyFocused := currentContextKey == self.base.GetKey() - - // we need to focus the view - if !alreadyFocused { - if err := self.takeFocus(); err != nil { - return err - } - } - - if newSelectedLineIdx > self.list.GetItemsLength()-1 { - return nil - } - - self.list.SetSelectedLineIdx(newSelectedLineIdx) - - if prevSelectedLineIdx == newSelectedLineIdx && alreadyFocused && onClick != nil { - return onClick() - } - return self.HandleFocus() -} - func (self *ListContextTrait) OnSearchSelect(selectedLineIdx int) error { - self.list.SetSelectedLineIdx(selectedLineIdx) + self.GetList().SetSelectedLineIdx(selectedLineIdx) return self.HandleFocus() } - -func (self *ListContextTrait) HandleRenderToMain() error { - if self.OnRenderToMain != nil { - return self.OnRenderToMain() - } - - return nil -} - -func (self *ListContextTrait) keybindings(opts types.KeybindingsOpts) []*types.Binding { - return []*types.Binding{ - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItem), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevPage), Modifier: gocui.ModNone, Handler: self.HandlePrevPage, Description: self.c.Tr.LcPrevPage}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextPage), Modifier: gocui.ModNone, Handler: self.HandleNextPage, Description: self.c.Tr.LcNextPage}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Modifier: gocui.ModNone, Handler: self.HandleGotoTop, Description: self.c.Tr.LcGotoTop}, - {Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: func() error { return self.HandleClick(nil) }}, - {Tag: "navigation", Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Modifier: gocui.ModNone, Handler: self.HandleScrollLeft}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollRight), Modifier: gocui.ModNone, Handler: self.HandleScrollRight}, - { - Key: opts.GetKey(opts.Config.Universal.StartSearch), - Handler: func() error { self.c.OpenSearch(); return nil }, - Description: self.c.Tr.LcStartSearch, - Tag: "navigation", - }, - { - Key: opts.GetKey(opts.Config.Universal.GotoBottom), - Description: self.c.Tr.LcGotoBottom, - Handler: self.HandleGotoBottom, - Tag: "navigation", - }, - } -} diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go new file mode 100644 index 000000000..0345ecb81 --- /dev/null +++ b/pkg/gui/context/local_commits_context.go @@ -0,0 +1,87 @@ +package context + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context/traits" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type LocalCommitsContext struct { + *LocalCommitsViewModel + *ViewportListContextTrait +} + +var _ types.IListContext = (*LocalCommitsContext)(nil) + +func NewLocalCommitsContext( + getModel func() []*models.Commit, + view *gocui.View, + getDisplayStrings func(startIdx int, length int) [][]string, + + onFocus func(...types.OnFocusOpts) error, + onRenderToMain func(...types.OnFocusOpts) error, + onFocusLost func() error, + + c *types.ControllerCommon, +) *LocalCommitsContext { + viewModel := NewLocalCommitsViewModel(getModel) + + return &LocalCommitsContext{ + LocalCommitsViewModel: viewModel, + ViewportListContextTrait: &ViewportListContextTrait{ + ListContextTrait: &ListContextTrait{ + Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ + ViewName: "commits", + WindowName: "commits", + Key: BRANCH_COMMITS_CONTEXT_KEY, + Kind: types.SIDE_CONTEXT, + Focusable: true, + }), ContextCallbackOpts{ + OnFocus: onFocus, + OnFocusLost: onFocusLost, + OnRenderToMain: onRenderToMain, + }), + list: viewModel, + viewTrait: NewViewTrait(view), + getDisplayStrings: getDisplayStrings, + c: c, + }}, + } +} + +func (self *LocalCommitsContext) GetSelectedItemId() string { + item := self.GetSelected() + if item == nil { + return "" + } + + return item.ID() +} + +type LocalCommitsViewModel struct { + *traits.ListCursor + getModel func() []*models.Commit +} + +func NewLocalCommitsViewModel(getModel func() []*models.Commit) *LocalCommitsViewModel { + self := &LocalCommitsViewModel{ + getModel: getModel, + } + + self.ListCursor = traits.NewListCursor(self) + + return self +} + +func (self *LocalCommitsViewModel) GetItemsLength() int { + return len(self.getModel()) +} + +func (self *LocalCommitsViewModel) GetSelected() *models.Commit { + if self.GetItemsLength() == 0 { + return nil + } + + return self.getModel()[self.GetSelectedLineIdx()] +} diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go new file mode 100644 index 000000000..47c6b885f --- /dev/null +++ b/pkg/gui/context/menu_context.go @@ -0,0 +1,108 @@ +package context + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/context/traits" + "github.com/jesseduffield/lazygit/pkg/gui/presentation" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type MenuContext struct { + *MenuViewModel + *ListContextTrait +} + +var _ types.IListContext = (*MenuContext)(nil) + +func NewMenuContext( + view *gocui.View, + + onFocus func(...types.OnFocusOpts) error, + onRenderToMain func(...types.OnFocusOpts) error, + onFocusLost func() error, + + c *types.ControllerCommon, + getOptionsMap func() map[string]string, +) *MenuContext { + viewModel := NewMenuViewModel() + + return &MenuContext{ + MenuViewModel: viewModel, + ListContextTrait: &ListContextTrait{ + Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ + ViewName: "menu", + Key: "menu", + Kind: types.PERSISTENT_POPUP, + OnGetOptionsMap: getOptionsMap, + Focusable: true, + }), ContextCallbackOpts{ + OnFocus: onFocus, + OnFocusLost: onFocusLost, + OnRenderToMain: onRenderToMain, + }), + getDisplayStrings: viewModel.GetDisplayStrings, + list: viewModel, + viewTrait: NewViewTrait(view), + c: c, + }, + } +} + +// TODO: remove this thing. +func (self *MenuContext) GetSelectedItemId() string { + item := self.GetSelected() + if item == nil { + return "" + } + + return item.DisplayString +} + +type MenuViewModel struct { + *traits.ListCursor + menuItems []*types.MenuItem +} + +func NewMenuViewModel() *MenuViewModel { + self := &MenuViewModel{ + menuItems: nil, + } + + self.ListCursor = traits.NewListCursor(self) + + return self +} + +func (self *MenuViewModel) GetItemsLength() int { + return len(self.menuItems) +} + +func (self *MenuViewModel) GetSelected() *types.MenuItem { + if self.GetItemsLength() == 0 { + return nil + } + + return self.menuItems[self.GetSelectedLineIdx()] +} + +func (self *MenuViewModel) SetMenuItems(items []*types.MenuItem) { + self.menuItems = items +} + +// TODO: move into presentation package +func (self *MenuViewModel) GetDisplayStrings(startIdx int, length int) [][]string { + stringArrays := make([][]string, len(self.menuItems)) + for i, item := range self.menuItems { + if item.DisplayStrings == nil { + styledStr := item.DisplayString + if item.OpensMenu { + styledStr = presentation.OpensMenuStyle(styledStr) + } + stringArrays[i] = []string{styledStr} + } else { + stringArrays[i] = item.DisplayStrings + } + } + + return stringArrays +} diff --git a/pkg/gui/context/reflog_commits_context.go b/pkg/gui/context/reflog_commits_context.go new file mode 100644 index 000000000..e3130c251 --- /dev/null +++ b/pkg/gui/context/reflog_commits_context.go @@ -0,0 +1,86 @@ +package context + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context/traits" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type ReflogCommitsContext struct { + *ReflogCommitsViewModel + *ListContextTrait +} + +var _ types.IListContext = (*ReflogCommitsContext)(nil) + +func NewReflogCommitsContext( + getModel func() []*models.Commit, + view *gocui.View, + getDisplayStrings func(startIdx int, length int) [][]string, + + onFocus func(...types.OnFocusOpts) error, + onRenderToMain func(...types.OnFocusOpts) error, + onFocusLost func() error, + + c *types.ControllerCommon, +) *ReflogCommitsContext { + viewModel := NewReflogCommitsViewModel(getModel) + + return &ReflogCommitsContext{ + ReflogCommitsViewModel: viewModel, + ListContextTrait: &ListContextTrait{ + Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ + ViewName: "commits", + WindowName: "commits", + Key: REFLOG_COMMITS_CONTEXT_KEY, + Kind: types.SIDE_CONTEXT, + Focusable: true, + }), ContextCallbackOpts{ + OnFocus: onFocus, + OnFocusLost: onFocusLost, + OnRenderToMain: onRenderToMain, + }), + list: viewModel, + viewTrait: NewViewTrait(view), + getDisplayStrings: getDisplayStrings, + c: c, + }, + } +} + +func (self *ReflogCommitsContext) GetSelectedItemId() string { + item := self.GetSelected() + if item == nil { + return "" + } + + return item.ID() +} + +type ReflogCommitsViewModel struct { + *traits.ListCursor + getModel func() []*models.Commit +} + +func NewReflogCommitsViewModel(getModel func() []*models.Commit) *ReflogCommitsViewModel { + self := &ReflogCommitsViewModel{ + getModel: getModel, + } + + self.ListCursor = traits.NewListCursor(self) + + return self +} + +func (self *ReflogCommitsViewModel) GetItemsLength() int { + return len(self.getModel()) +} + +func (self *ReflogCommitsViewModel) GetSelected() *models.Commit { + if self.GetItemsLength() == 0 { + return nil + } + + return self.getModel()[self.GetSelectedLineIdx()] +} diff --git a/pkg/gui/context/remote_branches_context.go b/pkg/gui/context/remote_branches_context.go new file mode 100644 index 000000000..e15e80261 --- /dev/null +++ b/pkg/gui/context/remote_branches_context.go @@ -0,0 +1,86 @@ +package context + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context/traits" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type RemoteBranchesContext struct { + *RemoteBranchesViewModel + *ListContextTrait +} + +var _ types.IListContext = (*RemoteBranchesContext)(nil) + +func NewRemoteBranchesContext( + getModel func() []*models.RemoteBranch, + view *gocui.View, + getDisplayStrings func(startIdx int, length int) [][]string, + + onFocus func(...types.OnFocusOpts) error, + onRenderToMain func(...types.OnFocusOpts) error, + onFocusLost func() error, + + c *types.ControllerCommon, +) *RemoteBranchesContext { + viewModel := NewRemoteBranchesViewModel(getModel) + + return &RemoteBranchesContext{ + RemoteBranchesViewModel: viewModel, + ListContextTrait: &ListContextTrait{ + Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ + ViewName: "branches", + WindowName: "branches", + Key: REMOTE_BRANCHES_CONTEXT_KEY, + Kind: types.SIDE_CONTEXT, + Focusable: true, + }), ContextCallbackOpts{ + OnFocus: onFocus, + OnFocusLost: onFocusLost, + OnRenderToMain: onRenderToMain, + }), + list: viewModel, + viewTrait: NewViewTrait(view), + getDisplayStrings: getDisplayStrings, + c: c, + }, + } +} + +func (self *RemoteBranchesContext) GetSelectedItemId() string { + item := self.GetSelected() + if item == nil { + return "" + } + + return item.ID() +} + +type RemoteBranchesViewModel struct { + *traits.ListCursor + getModel func() []*models.RemoteBranch +} + +func NewRemoteBranchesViewModel(getModel func() []*models.RemoteBranch) *RemoteBranchesViewModel { + self := &RemoteBranchesViewModel{ + getModel: getModel, + } + + self.ListCursor = traits.NewListCursor(self) + + return self +} + +func (self *RemoteBranchesViewModel) GetItemsLength() int { + return len(self.getModel()) +} + +func (self *RemoteBranchesViewModel) GetSelected() *models.RemoteBranch { + if self.GetItemsLength() == 0 { + return nil + } + + return self.getModel()[self.GetSelectedLineIdx()] +} diff --git a/pkg/gui/context/remotes_context.go b/pkg/gui/context/remotes_context.go new file mode 100644 index 000000000..28d0db20a --- /dev/null +++ b/pkg/gui/context/remotes_context.go @@ -0,0 +1,86 @@ +package context + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context/traits" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type RemotesContext struct { + *RemotesViewModel + *ListContextTrait +} + +var _ types.IListContext = (*RemotesContext)(nil) + +func NewRemotesContext( + getModel func() []*models.Remote, + view *gocui.View, + getDisplayStrings func(startIdx int, length int) [][]string, + + onFocus func(...types.OnFocusOpts) error, + onRenderToMain func(...types.OnFocusOpts) error, + onFocusLost func() error, + + c *types.ControllerCommon, +) *RemotesContext { + viewModel := NewRemotesViewModel(getModel) + + return &RemotesContext{ + RemotesViewModel: viewModel, + ListContextTrait: &ListContextTrait{ + Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ + ViewName: "branches", + WindowName: "branches", + Key: REMOTES_CONTEXT_KEY, + Kind: types.SIDE_CONTEXT, + Focusable: true, + }), ContextCallbackOpts{ + OnFocus: onFocus, + OnFocusLost: onFocusLost, + OnRenderToMain: onRenderToMain, + }), + list: viewModel, + viewTrait: NewViewTrait(view), + getDisplayStrings: getDisplayStrings, + c: c, + }, + } +} + +func (self *RemotesContext) GetSelectedItemId() string { + item := self.GetSelected() + if item == nil { + return "" + } + + return item.ID() +} + +type RemotesViewModel struct { + *traits.ListCursor + getModel func() []*models.Remote +} + +func NewRemotesViewModel(getModel func() []*models.Remote) *RemotesViewModel { + self := &RemotesViewModel{ + getModel: getModel, + } + + self.ListCursor = traits.NewListCursor(self) + + return self +} + +func (self *RemotesViewModel) GetItemsLength() int { + return len(self.getModel()) +} + +func (self *RemotesViewModel) GetSelected() *models.Remote { + if self.GetItemsLength() == 0 { + return nil + } + + return self.getModel()[self.GetSelectedLineIdx()] +} diff --git a/pkg/gui/simple_context.go b/pkg/gui/context/simple_context.go similarity index 86% rename from pkg/gui/simple_context.go rename to pkg/gui/context/simple_context.go index e9a3ca933..ae201295b 100644 --- a/pkg/gui/simple_context.go +++ b/pkg/gui/context/simple_context.go @@ -1,7 +1,6 @@ -package gui +package context import ( - "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -12,10 +11,10 @@ type SimpleContext struct { // this is for pushing some content to the main view OnRenderToMain func(opts ...types.OnFocusOpts) error - *context.BaseContext + *BaseContext } -type NewSimpleContextOpts struct { +type ContextCallbackOpts struct { OnFocus func(opts ...types.OnFocusOpts) error OnFocusLost func() error OnRender func() error @@ -23,7 +22,7 @@ type NewSimpleContextOpts struct { OnRenderToMain func(opts ...types.OnFocusOpts) error } -func NewSimpleContext(baseContext *context.BaseContext, opts NewSimpleContextOpts) *SimpleContext { +func NewSimpleContext(baseContext *BaseContext, opts ContextCallbackOpts) *SimpleContext { return &SimpleContext{ OnFocus: opts.OnFocus, OnFocusLost: opts.OnFocusLost, @@ -35,13 +34,6 @@ func NewSimpleContext(baseContext *context.BaseContext, opts NewSimpleContextOpt var _ types.Context = &SimpleContext{} -func (self *SimpleContext) HandleRender() error { - if self.OnRender != nil { - return self.OnRender() - } - return nil -} - func (self *SimpleContext) HandleFocus(opts ...types.OnFocusOpts) error { if self.OnFocus != nil { if err := self.OnFocus(opts...); err != nil { @@ -65,6 +57,13 @@ func (self *SimpleContext) HandleFocusLost() error { return nil } +func (self *SimpleContext) HandleRender() error { + if self.OnRender != nil { + return self.OnRender() + } + return nil +} + func (self *SimpleContext) HandleRenderToMain() error { if self.OnRenderToMain != nil { return self.OnRenderToMain() diff --git a/pkg/gui/context/stash_context.go b/pkg/gui/context/stash_context.go new file mode 100644 index 000000000..9c22e7b06 --- /dev/null +++ b/pkg/gui/context/stash_context.go @@ -0,0 +1,86 @@ +package context + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context/traits" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type StashContext struct { + *StashViewModel + *ListContextTrait +} + +var _ types.IListContext = (*StashContext)(nil) + +func NewStashContext( + getModel func() []*models.StashEntry, + view *gocui.View, + getDisplayStrings func(startIdx int, length int) [][]string, + + onFocus func(...types.OnFocusOpts) error, + onRenderToMain func(...types.OnFocusOpts) error, + onFocusLost func() error, + + c *types.ControllerCommon, +) *StashContext { + viewModel := NewStashViewModel(getModel) + + return &StashContext{ + StashViewModel: viewModel, + ListContextTrait: &ListContextTrait{ + Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ + ViewName: "stash", + WindowName: "stash", + Key: STASH_CONTEXT_KEY, + Kind: types.SIDE_CONTEXT, + Focusable: true, + }), ContextCallbackOpts{ + OnFocus: onFocus, + OnFocusLost: onFocusLost, + OnRenderToMain: onRenderToMain, + }), + list: viewModel, + viewTrait: NewViewTrait(view), + getDisplayStrings: getDisplayStrings, + c: c, + }, + } +} + +func (self *StashContext) GetSelectedItemId() string { + item := self.GetSelected() + if item == nil { + return "" + } + + return item.ID() +} + +type StashViewModel struct { + *traits.ListCursor + getModel func() []*models.StashEntry +} + +func NewStashViewModel(getModel func() []*models.StashEntry) *StashViewModel { + self := &StashViewModel{ + getModel: getModel, + } + + self.ListCursor = traits.NewListCursor(self) + + return self +} + +func (self *StashViewModel) GetItemsLength() int { + return len(self.getModel()) +} + +func (self *StashViewModel) GetSelected() *models.StashEntry { + if self.GetItemsLength() == 0 { + return nil + } + + return self.getModel()[self.GetSelectedLineIdx()] +} diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go new file mode 100644 index 000000000..aed0e01a2 --- /dev/null +++ b/pkg/gui/context/sub_commits_context.go @@ -0,0 +1,87 @@ +package context + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context/traits" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type SubCommitsContext struct { + *SubCommitsViewModel + *ViewportListContextTrait +} + +var _ types.IListContext = (*SubCommitsContext)(nil) + +func NewSubCommitsContext( + getModel func() []*models.Commit, + view *gocui.View, + getDisplayStrings func(startIdx int, length int) [][]string, + + onFocus func(...types.OnFocusOpts) error, + onRenderToMain func(...types.OnFocusOpts) error, + onFocusLost func() error, + + c *types.ControllerCommon, +) *SubCommitsContext { + viewModel := NewSubCommitsViewModel(getModel) + + return &SubCommitsContext{ + SubCommitsViewModel: viewModel, + ViewportListContextTrait: &ViewportListContextTrait{ + ListContextTrait: &ListContextTrait{ + Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ + ViewName: "branches", + WindowName: "branches", + Key: SUB_COMMITS_CONTEXT_KEY, + Kind: types.SIDE_CONTEXT, + Focusable: true, + }), ContextCallbackOpts{ + OnFocus: onFocus, + OnFocusLost: onFocusLost, + OnRenderToMain: onRenderToMain, + }), + list: viewModel, + viewTrait: NewViewTrait(view), + getDisplayStrings: getDisplayStrings, + c: c, + }}, + } +} + +func (self *SubCommitsContext) GetSelectedItemId() string { + item := self.GetSelected() + if item == nil { + return "" + } + + return item.ID() +} + +type SubCommitsViewModel struct { + *traits.ListCursor + getModel func() []*models.Commit +} + +func NewSubCommitsViewModel(getModel func() []*models.Commit) *SubCommitsViewModel { + self := &SubCommitsViewModel{ + getModel: getModel, + } + + self.ListCursor = traits.NewListCursor(self) + + return self +} + +func (self *SubCommitsViewModel) GetItemsLength() int { + return len(self.getModel()) +} + +func (self *SubCommitsViewModel) GetSelected() *models.Commit { + if self.GetItemsLength() == 0 { + return nil + } + + return self.getModel()[self.GetSelectedLineIdx()] +} diff --git a/pkg/gui/context/submodules_context.go b/pkg/gui/context/submodules_context.go new file mode 100644 index 000000000..c58755985 --- /dev/null +++ b/pkg/gui/context/submodules_context.go @@ -0,0 +1,86 @@ +package context + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context/traits" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type SubmodulesContext struct { + *SubmodulesViewModel + *ListContextTrait +} + +var _ types.IListContext = (*SubmodulesContext)(nil) + +func NewSubmodulesContext( + getModel func() []*models.SubmoduleConfig, + view *gocui.View, + getDisplayStrings func(startIdx int, length int) [][]string, + + onFocus func(...types.OnFocusOpts) error, + onRenderToMain func(...types.OnFocusOpts) error, + onFocusLost func() error, + + c *types.ControllerCommon, +) *SubmodulesContext { + viewModel := NewSubmodulesViewModel(getModel) + + return &SubmodulesContext{ + SubmodulesViewModel: viewModel, + ListContextTrait: &ListContextTrait{ + Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ + ViewName: "files", + WindowName: "files", + Key: SUBMODULES_CONTEXT_KEY, + Kind: types.SIDE_CONTEXT, + Focusable: true, + }), ContextCallbackOpts{ + OnFocus: onFocus, + OnFocusLost: onFocusLost, + OnRenderToMain: onRenderToMain, + }), + list: viewModel, + viewTrait: NewViewTrait(view), + getDisplayStrings: getDisplayStrings, + c: c, + }, + } +} + +func (self *SubmodulesContext) GetSelectedItemId() string { + item := self.GetSelected() + if item == nil { + return "" + } + + return item.ID() +} + +type SubmodulesViewModel struct { + *traits.ListCursor + getModel func() []*models.SubmoduleConfig +} + +func NewSubmodulesViewModel(getModel func() []*models.SubmoduleConfig) *SubmodulesViewModel { + self := &SubmodulesViewModel{ + getModel: getModel, + } + + self.ListCursor = traits.NewListCursor(self) + + return self +} + +func (self *SubmodulesViewModel) GetItemsLength() int { + return len(self.getModel()) +} + +func (self *SubmodulesViewModel) GetSelected() *models.SubmoduleConfig { + if self.GetItemsLength() == 0 { + return nil + } + + return self.getModel()[self.GetSelectedLineIdx()] +} diff --git a/pkg/gui/context/suggestions_context.go b/pkg/gui/context/suggestions_context.go new file mode 100644 index 000000000..5320e40c6 --- /dev/null +++ b/pkg/gui/context/suggestions_context.go @@ -0,0 +1,85 @@ +package context + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/context/traits" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type SuggestionsContext struct { + *SuggestionsViewModel + *ListContextTrait +} + +var _ types.IListContext = (*SuggestionsContext)(nil) + +func NewSuggestionsContext( + getModel func() []*types.Suggestion, + view *gocui.View, + getDisplayStrings func(startIdx int, length int) [][]string, + + onFocus func(...types.OnFocusOpts) error, + onRenderToMain func(...types.OnFocusOpts) error, + onFocusLost func() error, + + c *types.ControllerCommon, +) *SuggestionsContext { + viewModel := NewSuggestionsViewModel(getModel) + + return &SuggestionsContext{ + SuggestionsViewModel: viewModel, + ListContextTrait: &ListContextTrait{ + Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ + ViewName: "suggestions", + WindowName: "suggestions", + Key: SUGGESTIONS_CONTEXT_KEY, + Kind: types.PERSISTENT_POPUP, + Focusable: true, + }), ContextCallbackOpts{ + OnFocus: onFocus, + OnFocusLost: onFocusLost, + OnRenderToMain: onRenderToMain, + }), + list: viewModel, + viewTrait: NewViewTrait(view), + getDisplayStrings: getDisplayStrings, + c: c, + }, + } +} + +func (self *SuggestionsContext) GetSelectedItemId() string { + item := self.GetSelected() + if item == nil { + return "" + } + + return item.Value +} + +type SuggestionsViewModel struct { + *traits.ListCursor + getModel func() []*types.Suggestion +} + +func NewSuggestionsViewModel(getModel func() []*types.Suggestion) *SuggestionsViewModel { + self := &SuggestionsViewModel{ + getModel: getModel, + } + + self.ListCursor = traits.NewListCursor(self) + + return self +} + +func (self *SuggestionsViewModel) GetItemsLength() int { + return len(self.getModel()) +} + +func (self *SuggestionsViewModel) GetSelected() *types.Suggestion { + if self.GetItemsLength() == 0 { + return nil + } + + return self.getModel()[self.GetSelectedLineIdx()] +} diff --git a/pkg/gui/context/tags_context.go b/pkg/gui/context/tags_context.go index 2f20c4363..e0409cfba 100644 --- a/pkg/gui/context/tags_context.go +++ b/pkg/gui/context/tags_context.go @@ -9,7 +9,6 @@ import ( type TagsContext struct { *TagsViewModel - *BaseContext *ListContextTrait } @@ -17,7 +16,7 @@ var _ types.IListContext = (*TagsContext)(nil) func NewTagsContext( getModel func() []*models.Tag, - getView func() *gocui.View, + view *gocui.View, getDisplayStrings func(startIdx int, length int) [][]string, onFocus func(...types.OnFocusOpts) error, @@ -26,47 +25,32 @@ func NewTagsContext( c *types.ControllerCommon, ) *TagsContext { - baseContext := NewBaseContext(NewBaseContextOpts{ - ViewName: "branches", - WindowName: "branches", - Key: TAGS_CONTEXT_KEY, - Kind: types.SIDE_CONTEXT, - Focusable: true, - }) + viewModel := NewTagsViewModel(getModel) - self := &TagsContext{} - takeFocus := func() error { return c.PushContext(self) } - - list := NewTagsViewModel(getModel) - viewTrait := NewViewTrait(getView) - listContextTrait := &ListContextTrait{ - base: baseContext, - list: list, - viewTrait: viewTrait, - - GetDisplayStrings: getDisplayStrings, - OnFocus: onFocus, - OnRenderToMain: onRenderToMain, - OnFocusLost: onFocusLost, - takeFocus: takeFocus, - - // TODO: handle this in a trait - RenderSelection: false, - - c: c, + return &TagsContext{ + TagsViewModel: viewModel, + ListContextTrait: &ListContextTrait{ + Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ + ViewName: "branches", + WindowName: "branches", + Key: TAGS_CONTEXT_KEY, + Kind: types.SIDE_CONTEXT, + Focusable: true, + }), ContextCallbackOpts{ + OnFocus: onFocus, + OnFocusLost: onFocusLost, + OnRenderToMain: onRenderToMain, + }), + list: viewModel, + viewTrait: NewViewTrait(view), + getDisplayStrings: getDisplayStrings, + c: c, + }, } - - baseContext.AddKeybindingsFn(listContextTrait.keybindings) - - self.BaseContext = baseContext - self.ListContextTrait = listContextTrait - self.TagsViewModel = list - - return self } func (self *TagsContext) GetSelectedItemId() string { - item := self.GetSelectedTag() + item := self.GetSelected() if item == nil { return "" } @@ -79,18 +63,6 @@ type TagsViewModel struct { getModel func() []*models.Tag } -func (self *TagsViewModel) GetItemsLength() int { - return len(self.getModel()) -} - -func (self *TagsViewModel) GetSelectedTag() *models.Tag { - if self.GetItemsLength() == 0 { - return nil - } - - return self.getModel()[self.GetSelectedLineIdx()] -} - func NewTagsViewModel(getModel func() []*models.Tag) *TagsViewModel { self := &TagsViewModel{ getModel: getModel, @@ -100,3 +72,15 @@ func NewTagsViewModel(getModel func() []*models.Tag) *TagsViewModel { return self } + +func (self *TagsViewModel) GetItemsLength() int { + return len(self.getModel()) +} + +func (self *TagsViewModel) GetSelected() *models.Tag { + if self.GetItemsLength() == 0 { + return nil + } + + return self.getModel()[self.GetSelectedLineIdx()] +} diff --git a/pkg/gui/context/view_trait.go b/pkg/gui/context/view_trait.go index 1409ed561..f7981ebfa 100644 --- a/pkg/gui/context/view_trait.go +++ b/pkg/gui/context/view_trait.go @@ -2,70 +2,62 @@ package context import ( "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) const HORIZONTAL_SCROLL_FACTOR = 3 type ViewTrait struct { - getView func() *gocui.View + view *gocui.View } -func NewViewTrait(getView func() *gocui.View) *ViewTrait { - return &ViewTrait{getView: getView} +var _ types.IViewTrait = &ViewTrait{} + +func NewViewTrait(view *gocui.View) *ViewTrait { + return &ViewTrait{view: view} } func (self *ViewTrait) FocusPoint(yIdx int) { - view := self.getView() - view.FocusPoint(view.OriginX(), yIdx) + self.view.FocusPoint(self.view.OriginX(), yIdx) } func (self *ViewTrait) SetViewPortContent(content string) { - view := self.getView() - - _, y := view.Origin() - view.OverwriteLines(y, content) + _, y := self.view.Origin() + self.view.OverwriteLines(y, content) } func (self *ViewTrait) SetContent(content string) { - self.getView().SetContent(content) + self.view.SetContent(content) } func (self *ViewTrait) SetFooter(value string) { - self.getView().Footer = value + self.view.Footer = value } func (self *ViewTrait) SetOriginX(value int) { - _ = self.getView().SetOriginX(value) + _ = self.view.SetOriginX(value) } // tells us the bounds of line indexes shown in the view currently func (self *ViewTrait) ViewPortYBounds() (int, int) { - view := self.getView() - - _, min := view.Origin() - max := view.InnerHeight() + 1 + _, min := self.view.Origin() + max := self.view.InnerHeight() + 1 return min, max } func (self *ViewTrait) ScrollLeft() { - view := self.getView() - - newOriginX := utils.Max(view.OriginX()-view.InnerWidth()/HORIZONTAL_SCROLL_FACTOR, 0) - _ = view.SetOriginX(newOriginX) + newOriginX := utils.Max(self.view.OriginX()-self.view.InnerWidth()/HORIZONTAL_SCROLL_FACTOR, 0) + _ = self.view.SetOriginX(newOriginX) } func (self *ViewTrait) ScrollRight() { - view := self.getView() - - _ = view.SetOriginX(view.OriginX() + view.InnerWidth()/HORIZONTAL_SCROLL_FACTOR) + _ = self.view.SetOriginX(self.view.OriginX() + self.view.InnerWidth()/HORIZONTAL_SCROLL_FACTOR) } // this returns the amount we'll scroll if we want to scroll by a page. func (self *ViewTrait) PageDelta() int { - view := self.getView() - - _, height := view.Size() + _, height := self.view.Size() delta := height - 1 if delta == 0 { @@ -76,5 +68,5 @@ func (self *ViewTrait) PageDelta() int { } func (self *ViewTrait) SelectedLineIdx() int { - return self.getView().SelectedLineIdx() + return self.view.SelectedLineIdx() } diff --git a/pkg/gui/context/viewport_list_context_trait.go b/pkg/gui/context/viewport_list_context_trait.go new file mode 100644 index 000000000..ab9b04fb8 --- /dev/null +++ b/pkg/gui/context/viewport_list_context_trait.go @@ -0,0 +1,22 @@ +package context + +import ( + "github.com/jesseduffield/lazygit/pkg/utils" +) + +// This embeds a list context trait and adds logic to re-render the viewport +// whenever a line is focused. We use this in the commits panel because different +// sections of the log graph need to be highlighted depending on the currently selected line + +type ViewportListContextTrait struct { + *ListContextTrait +} + +func (self *ViewportListContextTrait) FocusLine() { + self.ListContextTrait.FocusLine() + + min, max := self.GetViewTrait().ViewPortYBounds() + displayStrings := self.ListContextTrait.getDisplayStrings(min, max) + content := utils.RenderDisplayStrings(displayStrings) + self.GetViewTrait().SetViewPortContent(content) +} diff --git a/pkg/gui/context/working_tree_context.go b/pkg/gui/context/working_tree_context.go index 6179e7270..c1021ba23 100644 --- a/pkg/gui/context/working_tree_context.go +++ b/pkg/gui/context/working_tree_context.go @@ -9,7 +9,6 @@ import ( type WorkingTreeContext struct { *filetree.FileTreeViewModel - *BaseContext *ListContextTrait } @@ -17,7 +16,7 @@ var _ types.IListContext = (*WorkingTreeContext)(nil) func NewWorkingTreeContext( getModel func() []*models.File, - getView func() *gocui.View, + view *gocui.View, getDisplayStrings func(startIdx int, length int) [][]string, onFocus func(...types.OnFocusOpts) error, @@ -26,43 +25,28 @@ func NewWorkingTreeContext( c *types.ControllerCommon, ) *WorkingTreeContext { - baseContext := NewBaseContext(NewBaseContextOpts{ - ViewName: "files", - WindowName: "files", - Key: FILES_CONTEXT_KEY, - Kind: types.SIDE_CONTEXT, - Focusable: true, - }) - - self := &WorkingTreeContext{} - takeFocus := func() error { return c.PushContext(self) } - viewModel := filetree.NewFileTreeViewModel(getModel, c.Log, c.UserConfig.Gui.ShowFileTree) - viewTrait := NewViewTrait(getView) - listContextTrait := &ListContextTrait{ - base: baseContext, - list: viewModel, - viewTrait: viewTrait, - GetDisplayStrings: getDisplayStrings, - OnFocus: onFocus, - OnRenderToMain: onRenderToMain, - OnFocusLost: onFocusLost, - takeFocus: takeFocus, - - // TODO: handle this in a trait - RenderSelection: false, - - c: c, + return &WorkingTreeContext{ + FileTreeViewModel: viewModel, + ListContextTrait: &ListContextTrait{ + Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ + ViewName: "files", + WindowName: "files", + Key: FILES_CONTEXT_KEY, + Kind: types.SIDE_CONTEXT, + Focusable: true, + }), ContextCallbackOpts{ + OnFocus: onFocus, + OnFocusLost: onFocusLost, + OnRenderToMain: onRenderToMain, + }), + list: viewModel, + viewTrait: NewViewTrait(view), + getDisplayStrings: getDisplayStrings, + c: c, + }, } - - baseContext.AddKeybindingsFn(listContextTrait.keybindings) - - self.BaseContext = baseContext - self.ListContextTrait = listContextTrait - self.FileTreeViewModel = viewModel - - return self } func (self *WorkingTreeContext) GetSelectedItemId() string { diff --git a/pkg/gui/context_config.go b/pkg/gui/context_config.go index d62f9f5e1..54f139141 100644 --- a/pkg/gui/context_config.go +++ b/pkg/gui/context_config.go @@ -35,7 +35,7 @@ func (gui *Gui) allContexts2() []types.Context { func (gui *Gui) contextTree() *context.ContextTree { return &context.ContextTree{ - Global: NewSimpleContext( + Global: context.NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.GLOBAL_CONTEXT, ViewName: "", @@ -43,11 +43,11 @@ func (gui *Gui) contextTree() *context.ContextTree { Key: context.GLOBAL_CONTEXT_KEY, Focusable: false, }), - NewSimpleContextOpts{ + context.ContextCallbackOpts{ OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain), }, ), - Status: NewSimpleContext( + Status: context.NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.SIDE_CONTEXT, ViewName: "status", @@ -55,7 +55,7 @@ func (gui *Gui) contextTree() *context.ContextTree { Key: context.STATUS_CONTEXT_KEY, Focusable: true, }), - NewSimpleContextOpts{ + context.ContextCallbackOpts{ OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain), }, ), @@ -72,7 +72,7 @@ func (gui *Gui) contextTree() *context.ContextTree { Tags: gui.tagsListContext(), Stash: gui.stashListContext(), Suggestions: gui.suggestionsListContext(), - Normal: NewSimpleContext( + Normal: context.NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.MAIN_CONTEXT, ViewName: "main", @@ -80,13 +80,13 @@ func (gui *Gui) contextTree() *context.ContextTree { Key: context.MAIN_NORMAL_CONTEXT_KEY, Focusable: false, }), - NewSimpleContextOpts{ + context.ContextCallbackOpts{ OnFocus: func(opts ...types.OnFocusOpts) error { return nil // TODO: should we do something here? We should allow for scrolling the panel }, }, ), - Staging: NewSimpleContext( + Staging: context.NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.MAIN_CONTEXT, ViewName: "main", @@ -94,7 +94,7 @@ func (gui *Gui) contextTree() *context.ContextTree { Key: context.MAIN_STAGING_CONTEXT_KEY, Focusable: true, }), - NewSimpleContextOpts{ + context.ContextCallbackOpts{ OnFocus: func(opts ...types.OnFocusOpts) error { forceSecondaryFocused := false selectedLineIdx := -1 @@ -110,7 +110,7 @@ func (gui *Gui) contextTree() *context.ContextTree { }, }, ), - PatchBuilding: NewSimpleContext( + PatchBuilding: context.NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.MAIN_CONTEXT, ViewName: "main", @@ -118,7 +118,7 @@ func (gui *Gui) contextTree() *context.ContextTree { Key: context.MAIN_PATCH_BUILDING_CONTEXT_KEY, Focusable: true, }), - NewSimpleContextOpts{ + context.ContextCallbackOpts{ OnFocus: func(opts ...types.OnFocusOpts) error { selectedLineIdx := -1 if len(opts) > 0 && (opts[0].ClickedViewName == "main" || opts[0].ClickedViewName == "secondary") { @@ -129,7 +129,7 @@ func (gui *Gui) contextTree() *context.ContextTree { }, }, ), - Merging: NewSimpleContext( + Merging: context.NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.MAIN_CONTEXT, ViewName: "main", @@ -138,11 +138,11 @@ func (gui *Gui) contextTree() *context.ContextTree { OnGetOptionsMap: gui.getMergingOptions, Focusable: true, }), - NewSimpleContextOpts{ + context.ContextCallbackOpts{ OnFocus: OnFocusWrapper(func() error { return gui.renderConflictsWithLock(true) }), }, ), - Credentials: NewSimpleContext( + Credentials: context.NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.PERSISTENT_POPUP, ViewName: "credentials", @@ -150,11 +150,11 @@ func (gui *Gui) contextTree() *context.ContextTree { Key: context.CREDENTIALS_CONTEXT_KEY, Focusable: true, }), - NewSimpleContextOpts{ + context.ContextCallbackOpts{ OnFocus: OnFocusWrapper(gui.handleAskFocused), }, ), - Confirmation: NewSimpleContext( + Confirmation: context.NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.TEMPORARY_POPUP, ViewName: "confirmation", @@ -162,11 +162,11 @@ func (gui *Gui) contextTree() *context.ContextTree { Key: context.CONFIRMATION_CONTEXT_KEY, Focusable: true, }), - NewSimpleContextOpts{ + context.ContextCallbackOpts{ OnFocus: OnFocusWrapper(gui.handleAskFocused), }, ), - CommitMessage: NewSimpleContext( + CommitMessage: context.NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.PERSISTENT_POPUP, ViewName: "commitMessage", @@ -174,11 +174,11 @@ func (gui *Gui) contextTree() *context.ContextTree { Key: context.COMMIT_MESSAGE_CONTEXT_KEY, Focusable: true, }), - NewSimpleContextOpts{ + context.ContextCallbackOpts{ OnFocus: OnFocusWrapper(gui.handleCommitMessageFocused), }, ), - Search: NewSimpleContext( + Search: context.NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.PERSISTENT_POPUP, ViewName: "search", @@ -186,9 +186,9 @@ func (gui *Gui) contextTree() *context.ContextTree { Key: context.SEARCH_CONTEXT_KEY, Focusable: true, }), - NewSimpleContextOpts{}, + context.ContextCallbackOpts{}, ), - CommandLog: NewSimpleContext( + CommandLog: context.NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.EXTRAS_CONTEXT, ViewName: "extras", @@ -197,7 +197,7 @@ func (gui *Gui) contextTree() *context.ContextTree { OnGetOptionsMap: gui.getMergingOptions, Focusable: true, }), - NewSimpleContextOpts{ + context.ContextCallbackOpts{ OnFocusLost: func() error { gui.Views.Extras.Autoscroll = true return nil diff --git a/pkg/gui/controllers/bisect_controller.go b/pkg/gui/controllers/bisect_controller.go index 58c8a6db7..99ae9c2df 100644 --- a/pkg/gui/controllers/bisect_controller.go +++ b/pkg/gui/controllers/bisect_controller.go @@ -7,6 +7,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -14,23 +15,21 @@ type BisectController struct { baseController c *types.ControllerCommon - context types.IListContext + context *context.LocalCommitsContext git *commands.GitCommand bisectHelper *BisectHelper - getSelectedLocalCommit func() *models.Commit - getCommits func() []*models.Commit + getCommits func() []*models.Commit } var _ types.IController = &BisectController{} func NewBisectController( c *types.ControllerCommon, - context types.IListContext, + context *context.LocalCommitsContext, git *commands.GitCommand, bisectHelper *BisectHelper, - getSelectedLocalCommit func() *models.Commit, getCommits func() []*models.Commit, ) *BisectController { return &BisectController{ @@ -40,8 +39,7 @@ func NewBisectController( git: git, bisectHelper: bisectHelper, - getSelectedLocalCommit: getSelectedLocalCommit, - getCommits: getCommits, + getCommits: getCommits, } } @@ -234,7 +232,7 @@ func (self *BisectController) selectCurrentBisectCommit() { // find index of commit with that sha, move cursor to that. for i, commit := range self.getCommits() { if commit.Sha == info.GetCurrentSha() { - self.context.GetPanelState().SetSelectedLineIdx(i) + self.context.SetSelectedLineIdx(i) _ = self.context.HandleFocus() break } @@ -244,7 +242,7 @@ func (self *BisectController) selectCurrentBisectCommit() { func (self *BisectController) checkSelected(callback func(*models.Commit) error) func() error { return func() error { - commit := self.getSelectedLocalCommit() + commit := self.context.GetSelected() if commit == nil { return nil } diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index d853ba731..de085607d 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -94,10 +94,10 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types Handler: self.checkSelectedFileNode(self.press), Description: self.c.Tr.LcToggleStaged, }, - { - Key: gocui.MouseLeft, - Handler: func() error { return self.context.HandleClick(self.checkSelectedFileNode(self.press)) }, - }, + // { + // Key: gocui.MouseLeft, + // Handler: func() error { return self.context.HandleClick(self.checkSelectedFileNode(self.press)) }, + // }, { Key: opts.GetKey(" "), // TODO: softcode Handler: self.handleStatusFilterPressed, diff --git a/pkg/gui/controllers/list_controller.go b/pkg/gui/controllers/list_controller.go new file mode 100644 index 000000000..8473fad83 --- /dev/null +++ b/pkg/gui/controllers/list_controller.go @@ -0,0 +1,144 @@ +package controllers + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type ListControllerFactory struct { + c *types.ControllerCommon +} + +func NewListControllerFactory(c *types.ControllerCommon) *ListControllerFactory { + return &ListControllerFactory{ + c: c, + } +} + +func (self *ListControllerFactory) Create(context types.IListContext) *ListController { + return &ListController{ + baseController: baseController{}, + c: self.c, + context: context, + } +} + +type ListController struct { + baseController + c *types.ControllerCommon + + context types.IListContext +} + +func (self *ListController) Context() types.Context { + return self.context +} + +func (self *ListController) HandlePrevLine() error { + return self.handleLineChange(-1) +} + +func (self *ListController) HandleNextLine() error { + return self.handleLineChange(1) +} + +func (self *ListController) HandleScrollLeft() error { + return self.scroll(self.context.GetViewTrait().ScrollLeft) +} + +func (self *ListController) HandleScrollRight() error { + return self.scroll(self.context.GetViewTrait().ScrollRight) +} + +func (self *ListController) scroll(scrollFunc func()) error { + scrollFunc() + + return self.context.HandleFocus() +} + +func (self *ListController) handleLineChange(change int) error { + before := self.context.GetList().GetSelectedLineIdx() + self.context.GetList().MoveSelectedLine(change) + after := self.context.GetList().GetSelectedLineIdx() + + // doing this check so that if we're holding the up key at the start of the list + // we're not constantly re-rendering the main view. + if before != after { + return self.context.HandleFocus() + } + + return nil +} + +func (self *ListController) HandlePrevPage() error { + return self.handleLineChange(-self.context.GetViewTrait().PageDelta()) +} + +func (self *ListController) HandleNextPage() error { + return self.handleLineChange(self.context.GetViewTrait().PageDelta()) +} + +func (self *ListController) HandleGotoTop() error { + return self.handleLineChange(-self.context.GetList().GetItemsLength()) +} + +func (self *ListController) HandleGotoBottom() error { + return self.handleLineChange(self.context.GetList().GetItemsLength()) +} + +func (self *ListController) HandleClick(onClick func() error) error { + prevSelectedLineIdx := self.context.GetList().GetSelectedLineIdx() + // because we're handling a click, we need to determine the new line idx based + // on the view itself. + newSelectedLineIdx := self.context.GetViewTrait().SelectedLineIdx() + + currentContextKey := self.c.CurrentContext().GetKey() + alreadyFocused := currentContextKey == self.context.GetKey() + + // we need to focus the view + if !alreadyFocused { + if err := self.c.PushContext(self.context); err != nil { + return err + } + } + + if newSelectedLineIdx > self.context.GetList().GetItemsLength()-1 { + return nil + } + + self.context.GetList().SetSelectedLineIdx(newSelectedLineIdx) + + if prevSelectedLineIdx == newSelectedLineIdx && alreadyFocused && onClick != nil { + return onClick() + } + return self.context.HandleFocus() +} + +func (self *ListController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + return []*types.Binding{ + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, + {Tag: "navigation", Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItem), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevPage), Modifier: gocui.ModNone, Handler: self.HandlePrevPage, Description: self.c.Tr.LcPrevPage}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextPage), Modifier: gocui.ModNone, Handler: self.HandleNextPage, Description: self.c.Tr.LcNextPage}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Modifier: gocui.ModNone, Handler: self.HandleGotoTop, Description: self.c.Tr.LcGotoTop}, + {Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: func() error { return self.HandleClick(nil) }}, + {Tag: "navigation", Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: self.HandleNextLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Modifier: gocui.ModNone, Handler: self.HandleScrollLeft}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollRight), Modifier: gocui.ModNone, Handler: self.HandleScrollRight}, + { + Key: opts.GetKey(opts.Config.Universal.StartSearch), + Handler: func() error { self.c.OpenSearch(); return nil }, + Description: self.c.Tr.LcStartSearch, + Tag: "navigation", + }, + { + Key: opts.GetKey(opts.Config.Universal.GotoBottom), + Description: self.c.Tr.LcGotoBottom, + Handler: self.HandleGotoBottom, + Tag: "navigation", + }, + } +} diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index e962ea48e..4ce7b88da 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -8,6 +8,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/hosting_service" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -24,7 +25,7 @@ type ( type LocalCommitsController struct { baseController c *types.ControllerCommon - context types.IListContext + context *context.LocalCommitsContext os *oscommands.OSCommand git *commands.GitCommand tagsHelper *TagsHelper @@ -32,9 +33,7 @@ type LocalCommitsController struct { cherryPickHelper *CherryPickHelper rebaseHelper *RebaseHelper - getSelectedLocalCommit func() *models.Commit model *types.Model - getSelectedLocalCommitIdx func() int CheckMergeOrRebase CheckMergeOrRebase pullFiles PullFilesFn getHostingServiceMgr GetHostingServiceMgrFn @@ -49,16 +48,14 @@ var _ types.IController = &LocalCommitsController{} func NewLocalCommitsController( c *types.ControllerCommon, - context types.IListContext, + context *context.LocalCommitsContext, os *oscommands.OSCommand, git *commands.GitCommand, tagsHelper *TagsHelper, refsHelper IRefsHelper, cherryPickHelper *CherryPickHelper, rebaseHelper *RebaseHelper, - getSelectedLocalCommit func() *models.Commit, model *types.Model, - getSelectedLocalCommitIdx func() int, CheckMergeOrRebase CheckMergeOrRebase, pullFiles PullFilesFn, getHostingServiceMgr GetHostingServiceMgrFn, @@ -78,9 +75,7 @@ func NewLocalCommitsController( refsHelper: refsHelper, cherryPickHelper: cherryPickHelper, rebaseHelper: rebaseHelper, - getSelectedLocalCommit: getSelectedLocalCommit, model: model, - getSelectedLocalCommitIdx: getSelectedLocalCommitIdx, CheckMergeOrRebase: CheckMergeOrRebase, pullFiles: pullFiles, getHostingServiceMgr: getHostingServiceMgr, @@ -194,10 +189,10 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ Description: self.c.Tr.LcGotoBottom, Tag: "navigation", }, - { - Key: gocui.MouseLeft, - Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, - }, + // { + // Key: gocui.MouseLeft, + // Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, + // }, } for _, binding := range outsideFilterModeBindings { @@ -316,7 +311,7 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error { InitialContent: message, HandleConfirm: func(response string) error { self.c.LogAction(self.c.Tr.Actions.RewordCommit) - if err := self.git.Rebase.RewordCommit(self.model.Commits, self.getSelectedLocalCommitIdx(), response); err != nil { + if err := self.git.Rebase.RewordCommit(self.model.Commits, self.context.GetSelectedLineIdx(), response); err != nil { return self.c.Error(err) } @@ -336,7 +331,7 @@ func (self *LocalCommitsController) rewordEditor() error { self.c.LogAction(self.c.Tr.Actions.RewordCommit) subProcess, err := self.git.Rebase.RewordCommitInEditor( - self.model.Commits, self.getSelectedLocalCommitIdx(), + self.model.Commits, self.context.GetSelectedLineIdx(), ) if err != nil { return self.c.Error(err) @@ -399,7 +394,7 @@ func (self *LocalCommitsController) pick() error { } func (self *LocalCommitsController) interactiveRebase(action string) error { - err := self.git.Rebase.InteractiveRebase(self.model.Commits, self.getSelectedLocalCommitIdx(), action) + err := self.git.Rebase.InteractiveRebase(self.model.Commits, self.context.GetSelectedLineIdx(), action) return self.CheckMergeOrRebase(err) } @@ -407,7 +402,7 @@ func (self *LocalCommitsController) interactiveRebase(action string) error { // commit meaning you are trying to edit the todo file rather than actually // begin a rebase. It then updates the todo file with that action func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool, error) { - selectedCommit := self.getSelectedLocalCommit() + selectedCommit := self.context.GetSelected() if selectedCommit.Status != "rebasing" { return false, nil } @@ -427,7 +422,7 @@ func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool, ) if err := self.git.Rebase.EditRebaseTodo( - self.getSelectedLocalCommitIdx(), action, + self.context.GetSelectedLineIdx(), action, ); err != nil { return false, self.c.Error(err) } @@ -438,7 +433,7 @@ func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool, } func (self *LocalCommitsController) handleCommitMoveDown() error { - index := self.context.GetPanelState().GetSelectedLineIdx() + index := self.context.GetSelectedLineIdx() commits := self.model.Commits selectedCommit := self.model.Commits[index] if selectedCommit.Status == "rebasing" { @@ -454,8 +449,7 @@ func (self *LocalCommitsController) handleCommitMoveDown() error { if err := self.git.Rebase.MoveTodoDown(index); err != nil { return self.c.Error(err) } - // TODO: use MoveSelectedLine - _ = self.context.HandleNextLine() + self.context.MoveSelectedLine(1) return self.c.Refresh(types.RefreshOptions{ Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS}, }) @@ -465,8 +459,7 @@ func (self *LocalCommitsController) handleCommitMoveDown() error { self.c.LogAction(self.c.Tr.Actions.MoveCommitDown) err := self.git.Rebase.MoveCommitDown(self.model.Commits, index) if err == nil { - // TODO: use MoveSelectedLine - _ = self.context.HandleNextLine() + self.context.MoveSelectedLine(1) } return self.CheckMergeOrRebase(err) }) @@ -491,7 +484,7 @@ func (self *LocalCommitsController) handleCommitMoveUp() error { if err := self.git.Rebase.MoveTodoDown(index - 1); err != nil { return self.c.Error(err) } - _ = self.context.HandlePrevLine() + self.context.MoveSelectedLine(-1) return self.c.Refresh(types.RefreshOptions{ Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS}, }) @@ -501,7 +494,7 @@ func (self *LocalCommitsController) handleCommitMoveUp() error { self.c.LogAction(self.c.Tr.Actions.MoveCommitUp) err := self.git.Rebase.MoveCommitDown(self.model.Commits, index-1) if err == nil { - _ = self.context.HandlePrevLine() + self.context.MoveSelectedLine(-1) } return self.CheckMergeOrRebase(err) }) @@ -514,7 +507,7 @@ func (self *LocalCommitsController) handleCommitAmendTo() error { HandleConfirm: func() error { return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func() error { self.c.LogAction(self.c.Tr.Actions.AmendCommit) - err := self.git.Rebase.AmendTo(self.getSelectedLocalCommit().Sha) + err := self.git.Rebase.AmendTo(self.context.GetSelected().Sha) return self.CheckMergeOrRebase(err) }) }, @@ -569,7 +562,7 @@ func (self *LocalCommitsController) createRevertMergeCommitMenu(commit *models.C } func (self *LocalCommitsController) afterRevertCommit() error { - _ = self.context.HandleNextLine() + self.context.MoveSelectedLine(1) return self.c.Refresh(types.RefreshOptions{ Mode: types.BLOCK_UI, Scope: []types.RefreshableView{types.COMMITS, types.BRANCHES}, }) @@ -669,7 +662,7 @@ func (self *LocalCommitsController) gotoBottom() error { } } - _ = self.context.HandleGotoBottom() + self.context.SetSelectedLineIdx(self.context.GetItemsLength() - 1) return nil } @@ -791,7 +784,7 @@ func (self *LocalCommitsController) handleOpenCommitInBrowser(commit *models.Com func (self *LocalCommitsController) checkSelected(callback func(*models.Commit) error) func() error { return func() error { - commit := self.getSelectedLocalCommit() + commit := self.context.GetSelected() if commit == nil { return nil } @@ -813,7 +806,7 @@ func (self *LocalCommitsController) copy(commit *models.Commit) error { } func (self *LocalCommitsController) copyRange(*models.Commit) error { - return self.cherryPickHelper.CopyRange(self.context.GetPanelState().GetSelectedLineIdx(), self.model.Commits, self.context) + return self.cherryPickHelper.CopyRange(self.context.GetSelectedLineIdx(), self.model.Commits, self.context) } func (self *LocalCommitsController) paste() error { diff --git a/pkg/gui/controllers/menu_controller.go b/pkg/gui/controllers/menu_controller.go index cbd24e188..392fe3da6 100644 --- a/pkg/gui/controllers/menu_controller.go +++ b/pkg/gui/controllers/menu_controller.go @@ -1,7 +1,7 @@ package controllers import ( - "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -9,24 +9,20 @@ type MenuController struct { baseController c *types.ControllerCommon - context types.IListContext - - getSelectedMenuItem func() *types.MenuItem + context *context.MenuContext } var _ types.IController = &MenuController{} func NewMenuController( c *types.ControllerCommon, - context types.IListContext, - getSelectedMenuItem func() *types.MenuItem, + context *context.MenuContext, ) *MenuController { return &MenuController{ baseController: baseController{}, - c: c, - context: context, - getSelectedMenuItem: getSelectedMenuItem, + c: c, + context: context, } } @@ -44,17 +40,17 @@ func (self *MenuController) GetKeybindings(opts types.KeybindingsOpts) []*types. Key: opts.GetKey(opts.Config.Universal.ConfirmAlt1), Handler: self.press, }, - { - Key: gocui.MouseLeft, - Handler: func() error { return self.context.HandleClick(self.press) }, - }, + // { + // Key: gocui.MouseLeft, + // Handler: func() error { return self.context.HandleClick(self.press) }, + // }, } return bindings } func (self *MenuController) press() error { - selectedItem := self.getSelectedMenuItem() + selectedItem := self.context.GetSelected() if err := self.c.PopContext(); err != nil { return err diff --git a/pkg/gui/controllers/remotes_controller.go b/pkg/gui/controllers/remotes_controller.go index 73b1c57ab..ff3b943fb 100644 --- a/pkg/gui/controllers/remotes_controller.go +++ b/pkg/gui/controllers/remotes_controller.go @@ -1,7 +1,6 @@ package controllers import ( - "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" @@ -13,10 +12,9 @@ type RemotesController struct { baseController c *types.ControllerCommon - context types.IListContext + context *context.RemotesContext git *commands.GitCommand - getSelectedRemote func() *models.Remote setRemoteBranches func([]*models.RemoteBranch) contexts *context.ContextTree } @@ -25,10 +23,9 @@ var _ types.IController = &RemotesController{} func NewRemotesController( c *types.ControllerCommon, - context types.IListContext, + context *context.RemotesContext, git *commands.GitCommand, contexts *context.ContextTree, - getSelectedRemote func() *models.Remote, setRemoteBranches func([]*models.RemoteBranch), ) *RemotesController { return &RemotesController{ @@ -37,7 +34,6 @@ func NewRemotesController( git: git, contexts: contexts, context: context, - getSelectedRemote: getSelectedRemote, setRemoteBranches: setRemoteBranches, } } @@ -48,10 +44,10 @@ func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*typ Key: opts.GetKey(opts.Config.Universal.GoInto), Handler: self.checkSelected(self.enter), }, - { - Key: gocui.MouseLeft, - Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, - }, + // { + // Key: gocui.MouseLeft, + // Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, + // }, { Key: opts.GetKey(opts.Config.Branches.FetchRemote), Handler: self.checkSelected(self.fetch), @@ -183,7 +179,7 @@ func (self *RemotesController) fetch(remote *models.Remote) error { func (self *RemotesController) checkSelected(callback func(*models.Remote) error) func() error { return func() error { - file := self.getSelectedRemote() + file := self.context.GetSelected() if file == nil { return nil } diff --git a/pkg/gui/controllers/submodules_controller.go b/pkg/gui/controllers/submodules_controller.go index 1db27f6e6..2eba02953 100644 --- a/pkg/gui/controllers/submodules_controller.go +++ b/pkg/gui/controllers/submodules_controller.go @@ -5,9 +5,9 @@ import ( "path/filepath" "strings" - "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -16,29 +16,26 @@ type SubmodulesController struct { baseController c *types.ControllerCommon - context types.IListContext + context *context.SubmodulesContext git *commands.GitCommand - enterSubmodule func(submodule *models.SubmoduleConfig) error - getSelectedSubmodule func() *models.SubmoduleConfig + enterSubmodule func(submodule *models.SubmoduleConfig) error } var _ types.IController = &SubmodulesController{} func NewSubmodulesController( c *types.ControllerCommon, - context types.IListContext, + context *context.SubmodulesContext, git *commands.GitCommand, enterSubmodule func(submodule *models.SubmoduleConfig) error, - getSelectedSubmodule func() *models.SubmoduleConfig, ) *SubmodulesController { return &SubmodulesController{ - baseController: baseController{}, - c: c, - context: context, - git: git, - enterSubmodule: enterSubmodule, - getSelectedSubmodule: getSelectedSubmodule, + baseController: baseController{}, + c: c, + context: context, + git: git, + enterSubmodule: enterSubmodule, } } @@ -80,10 +77,10 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []* Description: self.c.Tr.LcViewBulkSubmoduleOptions, OpensMenu: true, }, - { - Key: gocui.MouseLeft, - Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, - }, + // { + // Key: gocui.MouseLeft, + // Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, + // }, } } @@ -230,7 +227,7 @@ func (self *SubmodulesController) remove(submodule *models.SubmoduleConfig) erro func (self *SubmodulesController) checkSelected(callback func(*models.SubmoduleConfig) error) func() error { return func() error { - submodule := self.getSelectedSubmodule() + submodule := self.context.GetSelected() if submodule == nil { return nil } diff --git a/pkg/gui/controllers/tags_controller.go b/pkg/gui/controllers/tags_controller.go index 508820061..18135db02 100644 --- a/pkg/gui/controllers/tags_controller.go +++ b/pkg/gui/controllers/tags_controller.go @@ -158,7 +158,7 @@ func (self *TagsController) create() error { func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func() error { return func() error { - tag := self.context.GetSelectedTag() + tag := self.context.GetSelected() if tag == nil { return nil } diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index 45713968e..8111dd06c 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -44,16 +44,16 @@ func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (s objects := CustomCommandObjects{ SelectedFile: gui.getSelectedFile(), SelectedPath: gui.getSelectedPath(), - SelectedLocalCommit: gui.getSelectedLocalCommit(), - SelectedReflogCommit: gui.getSelectedReflogCommit(), - SelectedLocalBranch: gui.getSelectedBranch(), - SelectedRemoteBranch: gui.getSelectedRemoteBranch(), - SelectedRemote: gui.getSelectedRemote(), - SelectedTag: gui.State.Contexts.Tags.GetSelectedTag(), - SelectedStashEntry: gui.getSelectedStashEntry(), + SelectedLocalCommit: gui.State.Contexts.BranchCommits.GetSelected(), + SelectedReflogCommit: gui.State.Contexts.ReflogCommits.GetSelected(), + SelectedLocalBranch: gui.State.Contexts.Branches.GetSelected(), + SelectedRemoteBranch: gui.State.Contexts.RemoteBranches.GetSelected(), + SelectedRemote: gui.State.Contexts.Remotes.GetSelected(), + SelectedTag: gui.State.Contexts.Tags.GetSelected(), + SelectedStashEntry: gui.State.Contexts.Stash.GetSelected(), SelectedCommitFile: gui.getSelectedCommitFile(), SelectedCommitFilePath: gui.getSelectedCommitFilePath(), - SelectedSubCommit: gui.getSelectedSubCommit(), + SelectedSubCommit: gui.State.Contexts.SubCommits.GetSelected(), CheckedOutBranch: gui.getCheckedOutBranch(), PromptResponses: promptResponses, } diff --git a/pkg/gui/diffing.go b/pkg/gui/diffing.go index 30c7d8789..30af99882 100644 --- a/pkg/gui/diffing.go +++ b/pkg/gui/diffing.go @@ -43,7 +43,7 @@ func (gui *Gui) currentDiffTerminals() []string { return []string{gui.State.Contexts.CommitFiles.GetRefName()} case context.LOCAL_BRANCHES_CONTEXT_KEY: // for our local branches we want to include both the branch and its upstream - branch := gui.getSelectedBranch() + branch := gui.State.Contexts.Branches.GetSelected() if branch != nil { names := []string{branch.ID()} if branch.IsTrackingRemote() { diff --git a/pkg/gui/filtering_menu_panel.go b/pkg/gui/filtering_menu_panel.go index b9b5bc685..fefe6a892 100644 --- a/pkg/gui/filtering_menu_panel.go +++ b/pkg/gui/filtering_menu_panel.go @@ -16,7 +16,7 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error { fileName = node.GetPath() } case gui.State.Contexts.CommitFiles: - node := gui.getSelectedCommitFileNode() + node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() if node != nil { fileName = node.GetPath() } diff --git a/pkg/gui/git_flow.go b/pkg/gui/git_flow.go index eecd5328c..c26b94a70 100644 --- a/pkg/gui/git_flow.go +++ b/pkg/gui/git_flow.go @@ -8,7 +8,7 @@ import ( ) func (gui *Gui) handleCreateGitFlowMenu() error { - branch := gui.getSelectedBranch() + branch := gui.State.Contexts.Branches.GetSelected() if branch == nil { return nil } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index f8479c111..3cc6129e3 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -179,11 +179,11 @@ type GuiRepoState struct { // Suggestions will sometimes appear when typing into a prompt Suggestions []*types.Suggestion - MenuItems []*types.MenuItem Updating bool Panels *panelStates SplitMainPanel bool + LimitCommits bool IsRefreshingFiles bool Searching searchingState @@ -253,68 +253,11 @@ type MergingPanelState struct { UserVerticalScrolling bool } -// TODO: consider splitting this out into the window and the branches view -type branchPanelState struct { - listPanelState -} - -type remotePanelState struct { - listPanelState -} - -type remoteBranchesState struct { - listPanelState -} - -type commitPanelState struct { - listPanelState - - LimitCommits bool -} - -type reflogCommitPanelState struct { - listPanelState -} - -type subCommitPanelState struct { - listPanelState - - // e.g. name of branch whose commits we're looking at - refName string -} - -type stashPanelState struct { - listPanelState -} - -type menuPanelState struct { - listPanelState - OnPress func() error -} - -type submodulePanelState struct { - listPanelState -} - -type suggestionsPanelState struct { - listPanelState -} - // as we move things to the new context approach we're going to eventually // remove this struct altogether and store this state on the contexts. type panelStates struct { - Branches *branchPanelState - Remotes *remotePanelState - RemoteBranches *remoteBranchesState - Commits *commitPanelState - ReflogCommits *reflogCommitPanelState - SubCommits *subCommitPanelState - Stash *stashPanelState - Menu *menuPanelState - LineByLine *LblPanelState - Merging *MergingPanelState - Submodules *submodulePanelState - Suggestions *suggestionsPanelState + LineByLine *LblPanelState + Merging *MergingPanelState } type Views struct { @@ -449,23 +392,13 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { }, Panels: &panelStates{ - // TODO: work out why some of these are -1 and some are 0. Last time I checked there was a good reason but I'm less certain now - Submodules: &submodulePanelState{listPanelState{SelectedLineIdx: -1}}, - Branches: &branchPanelState{listPanelState{SelectedLineIdx: 0}}, - Remotes: &remotePanelState{listPanelState{SelectedLineIdx: 0}}, - RemoteBranches: &remoteBranchesState{listPanelState{SelectedLineIdx: -1}}, - Commits: &commitPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}, LimitCommits: true}, - ReflogCommits: &reflogCommitPanelState{listPanelState{SelectedLineIdx: 0}}, - SubCommits: &subCommitPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}, refName: ""}, - Stash: &stashPanelState{listPanelState{SelectedLineIdx: -1}}, - Menu: &menuPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}, OnPress: nil}, - Suggestions: &suggestionsPanelState{listPanelState: listPanelState{SelectedLineIdx: 0}}, Merging: &MergingPanelState{ State: mergeconflicts.NewState(), UserVerticalScrolling: false, }, }, - Ptmx: nil, + LimitCommits: true, + Ptmx: nil, Modes: Modes{ Filtering: filtering.New(filterPath), CherryPicking: cherrypicking.New(), @@ -584,7 +517,7 @@ func (gui *Gui) resetControllers() { controllerCommon, gui.git, gui.State.Contexts, - func() { gui.State.Panels.Commits.LimitCommits = true }, + func() { gui.State.LimitCommits = true }, ), Bisect: controllers.NewBisectHelper(controllerCommon, gui.git), Suggestions: controllers.NewSuggestionsHelper(controllerCommon, model, gui.refreshSuggestions), @@ -615,7 +548,6 @@ func (gui *Gui) resetControllers() { gui.State.Contexts.Submodules, gui.git, gui.enterSubmodule, - gui.getSelectedSubmodule, ) bisectController := controllers.NewBisectController( @@ -623,7 +555,6 @@ func (gui *Gui) resetControllers() { gui.State.Contexts.BranchCommits, gui.git, gui.helpers.Bisect, - gui.getSelectedLocalCommit, func() []*models.Commit { return gui.State.Model.Commits }, ) @@ -672,15 +603,13 @@ func (gui *Gui) resetControllers() { gui.helpers.Refs, gui.helpers.CherryPick, gui.helpers.Rebase, - gui.getSelectedLocalCommit, model, - func() int { return gui.State.Panels.Commits.SelectedLineIdx }, gui.helpers.Rebase.CheckMergeOrRebase, syncController.HandlePull, gui.getHostingServiceMgr, gui.SwitchToCommitFilesContext, - func() bool { return gui.State.Panels.Commits.LimitCommits }, - func(value bool) { gui.State.Panels.Commits.LimitCommits = value }, + func() bool { return gui.State.LimitCommits }, + func(value bool) { gui.State.LimitCommits = value }, func() bool { return gui.ShowWholeGitGraph }, func(value bool) { gui.ShowWholeGitGraph = value }, ), @@ -689,13 +618,11 @@ func (gui *Gui) resetControllers() { gui.State.Contexts.Remotes, gui.git, gui.State.Contexts, - gui.getSelectedRemote, func(branches []*models.RemoteBranch) { gui.State.Model.RemoteBranches = branches }, ), Menu: controllers.NewMenuController( controllerCommon, gui.State.Contexts.Menu, - gui.getSelectedMenuItem, ), Undo: controllers.NewUndoController( controllerCommon, @@ -714,6 +641,11 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(gui.State.Contexts.Remotes, gui.Controllers.Remotes) controllers.AttachControllers(gui.State.Contexts.Menu, gui.Controllers.Menu) controllers.AttachControllers(gui.State.Contexts.Global, gui.Controllers.Sync, gui.Controllers.Undo, gui.Controllers.Global) + + listControllerFactory := controllers.NewListControllerFactory(gui.c) + for _, context := range gui.getListContexts() { + controllers.AttachControllers(context, listControllerFactory.Create(context)) + } } var RuneReplacements = map[rune]string{ diff --git a/pkg/gui/list_context.go b/pkg/gui/list_context.go deleted file mode 100644 index 7644df6e6..000000000 --- a/pkg/gui/list_context.go +++ /dev/null @@ -1,267 +0,0 @@ -package gui - -import ( - "fmt" - - "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazygit/pkg/gui/context" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - -type ListContext struct { - GetItemsLength func() int - GetDisplayStrings func(startIdx int, length int) [][]string - OnFocus func(...types.OnFocusOpts) error - OnRenderToMain func(...types.OnFocusOpts) error - OnFocusLost func() error - - OnGetSelectedItemId func() string - OnGetPanelState func() types.IListPanelState - // if this is true, we'll call GetDisplayStrings for just the visible part of the - // view and re-render that. This is useful when you need to render different - // content based on the selection (e.g. for showing the selected commit) - RenderSelection bool - - Gui *Gui - - *context.BaseContext -} - -var _ types.IListContext = &ListContext{} - -func (self *ListContext) GetPanelState() types.IListPanelState { - return self.OnGetPanelState() -} - -func (self *ListContext) FocusLine() { - view, err := self.Gui.g.View(self.ViewName) - if err != nil { - // ignoring error for now - return - } - - // we need a way of knowing whether we've rendered to the view yet. - view.FocusPoint(view.OriginX(), self.GetPanelState().GetSelectedLineIdx()) - if self.RenderSelection { - _, originY := view.Origin() - displayStrings := self.GetDisplayStrings(originY, view.InnerHeight()+1) - self.Gui.renderDisplayStringsInViewPort(view, displayStrings) - } - view.Footer = formatListFooter(self.GetPanelState().GetSelectedLineIdx(), self.GetItemsLength()) -} - -func formatListFooter(selectedLineIdx int, length int) string { - return fmt.Sprintf("%d of %d", selectedLineIdx+1, length) -} - -func (self *ListContext) GetSelectedItemId() string { - return self.OnGetSelectedItemId() -} - -// OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view -func (self *ListContext) HandleRender() error { - view, err := self.Gui.g.View(self.ViewName) - if err != nil { - return nil - } - - if self.GetDisplayStrings != nil { - self.Gui.refreshSelectedLine(self.GetPanelState(), self.GetItemsLength()) - self.Gui.renderDisplayStrings(view, self.GetDisplayStrings(0, self.GetItemsLength())) - self.Gui.render() - } - - return nil -} - -func (self *ListContext) HandleFocusLost() error { - if self.OnFocusLost != nil { - return self.OnFocusLost() - } - - view, err := self.Gui.g.View(self.ViewName) - if err != nil { - return nil - } - - _ = view.SetOriginX(0) - - return nil -} - -func (self *ListContext) HandleFocus(opts ...types.OnFocusOpts) error { - self.FocusLine() - - if self.OnFocus != nil { - if err := self.OnFocus(opts...); err != nil { - return err - } - } - - if self.OnRenderToMain != nil { - if err := self.OnRenderToMain(opts...); err != nil { - return err - } - } - - return nil -} - -func (self *ListContext) HandlePrevLine() error { - return self.handleLineChange(-1) -} - -func (self *ListContext) HandleNextLine() error { - return self.handleLineChange(1) -} - -func (self *ListContext) HandleScrollLeft() error { - return self.scroll(self.Gui.scrollLeft) -} - -func (self *ListContext) HandleScrollRight() error { - return self.scroll(self.Gui.scrollRight) -} - -func (self *ListContext) scroll(scrollFunc func(*gocui.View)) error { - if self.ignoreKeybinding() { - return nil - } - - // get the view, move the origin - view, err := self.Gui.g.View(self.ViewName) - if err != nil { - return nil - } - - scrollFunc(view) - - return self.HandleFocus() -} - -func (self *ListContext) ignoreKeybinding() bool { - return !self.Gui.isPopupPanel(self.ViewName) && self.Gui.popupPanelFocused() -} - -func (self *ListContext) handleLineChange(change int) error { - if self.ignoreKeybinding() { - return nil - } - - selectedLineIdx := self.GetPanelState().GetSelectedLineIdx() - if (change < 0 && selectedLineIdx == 0) || (change > 0 && selectedLineIdx == self.GetItemsLength()-1) { - return nil - } - - self.Gui.changeSelectedLine(self.GetPanelState(), self.GetItemsLength(), change) - - return self.HandleFocus() -} - -func (self *ListContext) HandleNextPage() error { - view, err := self.Gui.g.View(self.ViewName) - if err != nil { - return nil - } - delta := self.Gui.pageDelta(view) - - return self.handleLineChange(delta) -} - -func (self *ListContext) HandleGotoTop() error { - return self.handleLineChange(-self.GetItemsLength()) -} - -func (self *ListContext) HandleGotoBottom() error { - return self.handleLineChange(self.GetItemsLength()) -} - -func (self *ListContext) HandlePrevPage() error { - view, err := self.Gui.g.View(self.ViewName) - if err != nil { - return nil - } - - delta := self.Gui.pageDelta(view) - - return self.handleLineChange(-delta) -} - -func (self *ListContext) HandleClick(onClick func() error) error { - if self.ignoreKeybinding() { - return nil - } - - view, err := self.Gui.g.View(self.ViewName) - if err != nil { - return nil - } - - prevSelectedLineIdx := self.GetPanelState().GetSelectedLineIdx() - newSelectedLineIdx := view.SelectedLineIdx() - - // we need to focus the view - if err := self.Gui.c.PushContext(self); err != nil { - return err - } - - if newSelectedLineIdx > self.GetItemsLength()-1 { - return nil - } - - self.GetPanelState().SetSelectedLineIdx(newSelectedLineIdx) - - prevViewName := self.Gui.currentViewName() - if prevSelectedLineIdx == newSelectedLineIdx && prevViewName == self.ViewName && onClick != nil { - return onClick() - } - return self.HandleFocus() -} - -func (self *ListContext) OnSearchSelect(selectedLineIdx int) error { - self.GetPanelState().SetSelectedLineIdx(selectedLineIdx) - return self.HandleFocus() -} - -func (self *ListContext) HandleRenderToMain() error { - if self.OnRenderToMain != nil { - return self.OnRenderToMain() - } - - return nil -} - -func (self *ListContext) attachKeybindings() *ListContext { - self.BaseContext.AddKeybindingsFn(self.keybindings) - - return self -} - -func (self *ListContext) keybindings(opts types.KeybindingsOpts) []*types.Binding { - return []*types.Binding{ - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItem), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevPage), Modifier: gocui.ModNone, Handler: self.HandlePrevPage, Description: self.Gui.c.Tr.LcPrevPage}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextPage), Modifier: gocui.ModNone, Handler: self.HandleNextPage, Description: self.Gui.c.Tr.LcNextPage}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Modifier: gocui.ModNone, Handler: self.HandleGotoTop, Description: self.Gui.c.Tr.LcGotoTop}, - {Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: func() error { return self.HandleClick(nil) }}, - {Tag: "navigation", Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Modifier: gocui.ModNone, Handler: self.HandleScrollLeft}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollRight), Modifier: gocui.ModNone, Handler: self.HandleScrollRight}, - { - Key: opts.GetKey(opts.Config.Universal.StartSearch), - Handler: func() error { return self.Gui.handleOpenSearch(self.GetViewName()) }, - Description: self.Gui.c.Tr.LcStartSearch, - Tag: "navigation", - }, - { - Key: opts.GetKey(opts.Config.Universal.GotoBottom), - Description: self.Gui.c.Tr.LcGotoBottom, - Handler: self.HandleGotoBottom, - Tag: "navigation", - }, - } -} diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index dedcab4cc..b8609e9b7 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -3,7 +3,6 @@ package gui import ( "log" - "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" @@ -12,27 +11,21 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/types" ) -func (gui *Gui) menuListContext() types.IListContext { - return (&ListContext{ - BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ - ViewName: "menu", - Key: "menu", - Kind: types.PERSISTENT_POPUP, - OnGetOptionsMap: gui.getMenuOptions, - Focusable: true, - }), - GetItemsLength: func() int { return gui.Views.Menu.LinesHeight() }, - OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Menu }, - Gui: gui, - - // no GetDisplayStrings field because we do a custom render on menu creation - }).attachKeybindings() +func (gui *Gui) menuListContext() *context.MenuContext { + return context.NewMenuContext( + gui.Views.Menu, + nil, + nil, + nil, + gui.c, + gui.getMenuOptions, + ) } func (gui *Gui) filesListContext() *context.WorkingTreeContext { return context.NewWorkingTreeContext( func() []*models.File { return gui.State.Model.Files }, - func() *gocui.View { return gui.Views.Files }, + gui.Views.Files, func(startIdx int, length int) [][]string { lines := presentation.RenderFileTree(gui.State.Contexts.Files.FileTreeViewModel, gui.State.Modes.Diffing.Ref, gui.State.Model.Submodules) mappedLines := make([][]string, len(lines)) @@ -49,82 +42,46 @@ func (gui *Gui) filesListContext() *context.WorkingTreeContext { ) } -func (gui *Gui) branchesListContext() types.IListContext { - return (&ListContext{ - BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ - ViewName: "branches", - WindowName: "branches", - Key: context.LOCAL_BRANCHES_CONTEXT_KEY, - Kind: types.SIDE_CONTEXT, - Focusable: true, - }), - GetItemsLength: func() int { return len(gui.State.Model.Branches) }, - OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Branches }, - OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.branchesRenderToMain)), - Gui: gui, - GetDisplayStrings: func(startIdx int, length int) [][]string { +func (gui *Gui) branchesListContext() *context.BranchesContext { + return context.NewBranchesContext( + func() []*models.Branch { return gui.State.Model.Branches }, + gui.Views.Branches, + func(startIdx int, length int) [][]string { return presentation.GetBranchListDisplayStrings(gui.State.Model.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref) }, - OnGetSelectedItemId: func() string { - item := gui.getSelectedBranch() - if item == nil { - return "" - } - return item.ID() - }, - }).attachKeybindings() + nil, + OnFocusWrapper(gui.withDiffModeCheck(gui.branchesRenderToMain)), + nil, + gui.c, + ) } -func (gui *Gui) remotesListContext() types.IListContext { - return (&ListContext{ - BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ - ViewName: "branches", - WindowName: "branches", - Key: context.REMOTES_CONTEXT_KEY, - Kind: types.SIDE_CONTEXT, - Focusable: true, - }), - GetItemsLength: func() int { return len(gui.State.Model.Remotes) }, - OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Remotes }, - OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.remotesRenderToMain)), - Gui: gui, - GetDisplayStrings: func(startIdx int, length int) [][]string { +func (gui *Gui) remotesListContext() *context.RemotesContext { + return context.NewRemotesContext( + func() []*models.Remote { return gui.State.Model.Remotes }, + gui.Views.Branches, + func(startIdx int, length int) [][]string { return presentation.GetRemoteListDisplayStrings(gui.State.Model.Remotes, gui.State.Modes.Diffing.Ref) }, - OnGetSelectedItemId: func() string { - item := gui.getSelectedRemote() - if item == nil { - return "" - } - return item.ID() - }, - }).attachKeybindings() + nil, + OnFocusWrapper(gui.withDiffModeCheck(gui.remotesRenderToMain)), + nil, + gui.c, + ) } -func (gui *Gui) remoteBranchesListContext() types.IListContext { - return (&ListContext{ - BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ - ViewName: "branches", - WindowName: "branches", - Key: context.REMOTE_BRANCHES_CONTEXT_KEY, - Kind: types.SIDE_CONTEXT, - Focusable: true, - }), - GetItemsLength: func() int { return len(gui.State.Model.RemoteBranches) }, - OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.RemoteBranches }, - OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.remoteBranchesRenderToMain)), - Gui: gui, - GetDisplayStrings: func(startIdx int, length int) [][]string { +func (gui *Gui) remoteBranchesListContext() *context.RemoteBranchesContext { + return context.NewRemoteBranchesContext( + func() []*models.RemoteBranch { return gui.State.Model.RemoteBranches }, + gui.Views.Branches, + func(startIdx int, length int) [][]string { return presentation.GetRemoteBranchListDisplayStrings(gui.State.Model.RemoteBranches, gui.State.Modes.Diffing.Ref) }, - OnGetSelectedItemId: func() string { - item := gui.getSelectedRemoteBranch() - if item == nil { - return "" - } - return item.ID() - }, - }).attachKeybindings() + nil, + OnFocusWrapper(gui.withDiffModeCheck(gui.remoteBranchesRenderToMain)), + nil, + gui.c, + ) } func (gui *Gui) withDiffModeCheck(f func() error) func() error { @@ -140,7 +97,7 @@ func (gui *Gui) withDiffModeCheck(f func() error) func() error { func (gui *Gui) tagsListContext() *context.TagsContext { return context.NewTagsContext( func() []*models.Tag { return gui.State.Model.Tags }, - func() *gocui.View { return gui.Views.Branches }, + gui.Views.Branches, func(startIdx int, length int) [][]string { return presentation.GetTagListDisplayStrings(gui.State.Model.Tags, gui.State.Modes.Diffing.Ref) }, @@ -151,25 +108,14 @@ func (gui *Gui) tagsListContext() *context.TagsContext { ) } -func (gui *Gui) branchCommitsListContext() types.IListContext { - parseEmoji := gui.c.UserConfig.Git.ParseEmoji - return (&ListContext{ - BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ - ViewName: "commits", - WindowName: "commits", - Key: context.BRANCH_COMMITS_CONTEXT_KEY, - Kind: types.SIDE_CONTEXT, - Focusable: true, - }), - GetItemsLength: func() int { return len(gui.State.Model.Commits) }, - OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Commits }, - OnFocus: OnFocusWrapper(gui.onCommitFocus), - OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.branchCommitsRenderToMain)), - Gui: gui, - GetDisplayStrings: func(startIdx int, length int) [][]string { +func (gui *Gui) branchCommitsListContext() *context.LocalCommitsContext { + return context.NewLocalCommitsContext( + func() []*models.Commit { return gui.State.Model.Commits }, + gui.Views.Commits, + func(startIdx int, length int) [][]string { selectedCommitSha := "" if gui.currentContext().GetKey() == context.BRANCH_COMMITS_CONTEXT_KEY { - selectedCommit := gui.getSelectedLocalCommit() + selectedCommit := gui.State.Contexts.BranchCommits.GetSelected() if selectedCommit != nil { selectedCommitSha = selectedCommit.Sha } @@ -179,7 +125,7 @@ func (gui *Gui) branchCommitsListContext() types.IListContext { gui.State.ScreenMode != SCREEN_NORMAL, gui.helpers.CherryPick.CherryPickedCommitShaMap(), gui.State.Modes.Diffing.Ref, - parseEmoji, + gui.c.UserConfig.Git.ParseEmoji, selectedCommitSha, startIdx, length, @@ -187,35 +133,21 @@ func (gui *Gui) branchCommitsListContext() types.IListContext { gui.State.Model.BisectInfo, ) }, - OnGetSelectedItemId: func() string { - item := gui.getSelectedLocalCommit() - if item == nil { - return "" - } - return item.ID() - }, - RenderSelection: true, - }).attachKeybindings() + OnFocusWrapper(gui.onCommitFocus), + OnFocusWrapper(gui.withDiffModeCheck(gui.branchCommitsRenderToMain)), + nil, + gui.c, + ) } -func (gui *Gui) subCommitsListContext() types.IListContext { - parseEmoji := gui.c.UserConfig.Git.ParseEmoji - return (&ListContext{ - BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ - ViewName: "branches", - WindowName: "branches", - Key: context.SUB_COMMITS_CONTEXT_KEY, - Kind: types.SIDE_CONTEXT, - Focusable: true, - }), - GetItemsLength: func() int { return len(gui.State.Model.SubCommits) }, - OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.SubCommits }, - OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.subCommitsRenderToMain)), - Gui: gui, - GetDisplayStrings: func(startIdx int, length int) [][]string { +func (gui *Gui) subCommitsListContext() *context.SubCommitsContext { + return context.NewSubCommitsContext( + func() []*models.Commit { return gui.State.Model.SubCommits }, + gui.Views.Branches, + func(startIdx int, length int) [][]string { selectedCommitSha := "" if gui.currentContext().GetKey() == context.SUB_COMMITS_CONTEXT_KEY { - selectedCommit := gui.getSelectedSubCommit() + selectedCommit := gui.State.Contexts.SubCommits.GetSelected() if selectedCommit != nil { selectedCommitSha = selectedCommit.Sha } @@ -225,7 +157,7 @@ func (gui *Gui) subCommitsListContext() types.IListContext { gui.State.ScreenMode != SCREEN_NORMAL, gui.helpers.CherryPick.CherryPickedCommitShaMap(), gui.State.Modes.Diffing.Ref, - parseEmoji, + gui.c.UserConfig.Git.ParseEmoji, selectedCommitSha, startIdx, length, @@ -233,15 +165,11 @@ func (gui *Gui) subCommitsListContext() types.IListContext { git_commands.NewNullBisectInfo(), ) }, - OnGetSelectedItemId: func() string { - item := gui.getSelectedSubCommit() - if item == nil { - return "" - } - return item.ID() - }, - RenderSelection: true, - }).attachKeybindings() + nil, + OnFocusWrapper(gui.withDiffModeCheck(gui.subCommitsRenderToMain)), + nil, + gui.c, + ) } func (gui *Gui) shouldShowGraph() bool { @@ -263,69 +191,44 @@ func (gui *Gui) shouldShowGraph() bool { return false } -func (gui *Gui) reflogCommitsListContext() types.IListContext { - parseEmoji := gui.c.UserConfig.Git.ParseEmoji - return (&ListContext{ - BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ - ViewName: "commits", - WindowName: "commits", - Key: context.REFLOG_COMMITS_CONTEXT_KEY, - Kind: types.SIDE_CONTEXT, - Focusable: true, - }), - GetItemsLength: func() int { return len(gui.State.Model.FilteredReflogCommits) }, - OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.ReflogCommits }, - OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.reflogCommitsRenderToMain)), - Gui: gui, - GetDisplayStrings: func(startIdx int, length int) [][]string { +func (gui *Gui) reflogCommitsListContext() *context.ReflogCommitsContext { + return context.NewReflogCommitsContext( + func() []*models.Commit { return gui.State.Model.FilteredReflogCommits }, + gui.Views.Commits, + func(startIdx int, length int) [][]string { return presentation.GetReflogCommitListDisplayStrings( gui.State.Model.FilteredReflogCommits, gui.State.ScreenMode != SCREEN_NORMAL, gui.helpers.CherryPick.CherryPickedCommitShaMap(), gui.State.Modes.Diffing.Ref, - parseEmoji, + gui.c.UserConfig.Git.ParseEmoji, ) }, - OnGetSelectedItemId: func() string { - item := gui.getSelectedReflogCommit() - if item == nil { - return "" - } - return item.ID() - }, - }).attachKeybindings() + nil, + OnFocusWrapper(gui.withDiffModeCheck(gui.reflogCommitsRenderToMain)), + nil, + gui.c, + ) } -func (gui *Gui) stashListContext() types.IListContext { - return (&ListContext{ - BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ - ViewName: "stash", - WindowName: "stash", - Key: context.STASH_CONTEXT_KEY, - Kind: types.SIDE_CONTEXT, - Focusable: true, - }), - GetItemsLength: func() int { return len(gui.State.Model.StashEntries) }, - OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Stash }, - OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.stashRenderToMain)), - Gui: gui, - GetDisplayStrings: func(startIdx int, length int) [][]string { +func (gui *Gui) stashListContext() *context.StashContext { + return context.NewStashContext( + func() []*models.StashEntry { return gui.State.Model.StashEntries }, + gui.Views.Stash, + func(startIdx int, length int) [][]string { return presentation.GetStashEntryListDisplayStrings(gui.State.Model.StashEntries, gui.State.Modes.Diffing.Ref) }, - OnGetSelectedItemId: func() string { - item := gui.getSelectedStashEntry() - if item == nil { - return "" - } - return item.ID() - }, - }).attachKeybindings() + nil, + OnFocusWrapper(gui.withDiffModeCheck(gui.stashRenderToMain)), + nil, + gui.c, + ) } func (gui *Gui) commitFilesListContext() *context.CommitFilesContext { return context.NewCommitFilesContext( func() []*models.CommitFile { return gui.State.Model.CommitFiles }, - func() *gocui.View { return gui.Views.CommitFiles }, + gui.Views.CommitFiles, func(startIdx int, length int) [][]string { if gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.GetItemsLength() == 0 { return [][]string{{style.FgRed.Sprint("(none)")}} @@ -346,48 +249,32 @@ func (gui *Gui) commitFilesListContext() *context.CommitFilesContext { ) } -func (gui *Gui) submodulesListContext() types.IListContext { - return (&ListContext{ - BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ - ViewName: "files", - WindowName: "files", - Key: context.SUBMODULES_CONTEXT_KEY, - Kind: types.SIDE_CONTEXT, - Focusable: true, - }), - GetItemsLength: func() int { return len(gui.State.Model.Submodules) }, - OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Submodules }, - OnRenderToMain: OnFocusWrapper(gui.withDiffModeCheck(gui.submodulesRenderToMain)), - Gui: gui, - GetDisplayStrings: func(startIdx int, length int) [][]string { +func (gui *Gui) submodulesListContext() *context.SubmodulesContext { + return context.NewSubmodulesContext( + func() []*models.SubmoduleConfig { return gui.State.Model.Submodules }, + gui.Views.Files, + func(startIdx int, length int) [][]string { return presentation.GetSubmoduleListDisplayStrings(gui.State.Model.Submodules) }, - OnGetSelectedItemId: func() string { - item := gui.getSelectedSubmodule() - if item == nil { - return "" - } - return item.ID() - }, - }).attachKeybindings() + nil, + OnFocusWrapper(gui.withDiffModeCheck(gui.submodulesRenderToMain)), + nil, + gui.c, + ) } -func (gui *Gui) suggestionsListContext() types.IListContext { - return (&ListContext{ - BaseContext: context.NewBaseContext(context.NewBaseContextOpts{ - ViewName: "suggestions", - WindowName: "suggestions", - Key: context.SUGGESTIONS_CONTEXT_KEY, - Kind: types.PERSISTENT_POPUP, - Focusable: true, - }), - GetItemsLength: func() int { return len(gui.State.Suggestions) }, - OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Suggestions }, - Gui: gui, - GetDisplayStrings: func(startIdx int, length int) [][]string { +func (gui *Gui) suggestionsListContext() *context.SuggestionsContext { + return context.NewSuggestionsContext( + func() []*types.Suggestion { return gui.State.Suggestions }, + gui.Views.Files, + func(startIdx int, length int) [][]string { return presentation.GetSuggestionListDisplayStrings(gui.State.Suggestions) }, - }).attachKeybindings() + nil, + nil, + nil, + gui.c, + ) } func (gui *Gui) getListContexts() []types.IListContext { diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go index 3e20baebb..9388be279 100644 --- a/pkg/gui/menu_panel.go +++ b/pkg/gui/menu_panel.go @@ -6,7 +6,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/theme" - "github.com/jesseduffield/lazygit/pkg/utils" ) func (gui *Gui) getMenuOptions() map[string]string { @@ -35,44 +34,24 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error { }) } - gui.State.MenuItems = opts.Items - - stringArrays := make([][]string, len(opts.Items)) - for i, item := range opts.Items { + for _, item := range opts.Items { if item.OpensMenu && item.DisplayStrings != nil { return errors.New("Message for the developer of this app: you've set opensMenu with displaystrings on the menu panel. Bad developer!. Apologies, user") } - - if item.DisplayStrings == nil { - styledStr := item.DisplayString - if item.OpensMenu { - styledStr = opensMenuStyle(styledStr) - } - stringArrays[i] = []string{styledStr} - } else { - stringArrays[i] = item.DisplayStrings - } } - list := utils.RenderDisplayStrings(stringArrays) - - x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(false, list) + x0, y0, x1, y1 := gui.getConfirmationPanelDimensionsForContentHeight(len(opts.Items)) menuView, _ := gui.g.SetView("menu", x0, y0, x1, y1, 0) menuView.Title = opts.Title menuView.FgColor = theme.GocuiDefaultTextColor menuView.SetOnSelectItem(gui.onSelectItemWrapper(func(selectedLine int) error { return nil })) - menuView.SetContent(list) - gui.State.Panels.Menu.SelectedLineIdx = 0 + gui.State.Contexts.Menu.SetMenuItems(opts.Items) + gui.State.Contexts.Menu.GetPanelState().SetSelectedLineIdx(0) + _ = gui.c.PostRefreshUpdate(gui.State.Contexts.Menu) + + // TODO: ensure that if we're opened a menu from within a menu that it renders correctly return gui.c.PushContext(gui.State.Contexts.Menu) } - -func (gui *Gui) getSelectedMenuItem() *types.MenuItem { - if len(gui.State.MenuItems) == 0 { - return nil - } - - return gui.State.MenuItems[gui.State.Panels.Menu.SelectedLineIdx] -} diff --git a/pkg/gui/options_menu_panel.go b/pkg/gui/options_menu_panel.go index b9df16722..3ca6ea388 100644 --- a/pkg/gui/options_menu_panel.go +++ b/pkg/gui/options_menu_panel.go @@ -3,6 +3,7 @@ package gui import ( "strings" + "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -34,16 +35,12 @@ func (gui *Gui) getBindings(context types.Context) []*types.Binding { func (gui *Gui) displayDescription(binding *types.Binding) string { if binding.OpensMenu { - return opensMenuStyle(binding.Description) + return presentation.OpensMenuStyle(binding.Description) } return style.FgCyan.Sprint(binding.Description) } -func opensMenuStyle(str string) string { - return style.FgMagenta.Sprintf("%s...", str) -} - func (gui *Gui) handleCreateOptionsMenu() error { context := gui.currentContext() bindings := gui.getBindings(context) diff --git a/pkg/gui/patch_building_panel.go b/pkg/gui/patch_building_panel.go index fc41bd603..6b48d2bc2 100644 --- a/pkg/gui/patch_building_panel.go +++ b/pkg/gui/patch_building_panel.go @@ -26,7 +26,7 @@ func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error { gui.Views.Secondary.Title = "Custom Patch" // get diff from commit file that's currently selected - node := gui.getSelectedCommitFileNode() + node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() if node == nil { return nil } @@ -87,7 +87,7 @@ func (gui *Gui) handleToggleSelectionForPatch() error { } // add range of lines to those set for the file - node := gui.getSelectedCommitFileNode() + node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() if node == nil { return nil } diff --git a/pkg/gui/patch_options_panel.go b/pkg/gui/patch_options_panel.go index 4eda367bd..d69dbda27 100644 --- a/pkg/gui/patch_options_panel.go +++ b/pkg/gui/patch_options_panel.go @@ -118,7 +118,7 @@ func (gui *Gui) handleMovePatchToSelectedCommit() error { return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.MovePatchToSelectedCommit) - err := gui.git.Patch.MovePatchToSelectedCommit(gui.State.Model.Commits, commitIndex, gui.State.Panels.Commits.SelectedLineIdx) + err := gui.git.Patch.MovePatchToSelectedCommit(gui.State.Model.Commits, commitIndex, gui.State.Contexts.BranchCommits.GetSelectedLineIdx()) return gui.helpers.Rebase.CheckMergeOrRebase(err) }) } diff --git a/pkg/gui/presentation/menu.go b/pkg/gui/presentation/menu.go new file mode 100644 index 000000000..c43896c22 --- /dev/null +++ b/pkg/gui/presentation/menu.go @@ -0,0 +1,7 @@ +package presentation + +import "github.com/jesseduffield/lazygit/pkg/gui/style" + +func OpensMenuStyle(str string) string { + return style.FgMagenta.Sprintf("%s...", str) +} diff --git a/pkg/gui/reflog_panel.go b/pkg/gui/reflog_panel.go index d3569ee81..57b4e0a35 100644 --- a/pkg/gui/reflog_panel.go +++ b/pkg/gui/reflog_panel.go @@ -9,17 +9,11 @@ import ( // list panel functions func (gui *Gui) getSelectedReflogCommit() *models.Commit { - selectedLine := gui.State.Panels.ReflogCommits.SelectedLineIdx - reflogComits := gui.State.Model.FilteredReflogCommits - if selectedLine == -1 || len(reflogComits) == 0 { - return nil - } - - return reflogComits[selectedLine] + return gui.State.Contexts.ReflogCommits.GetSelected() } func (gui *Gui) reflogCommitsRenderToMain() error { - commit := gui.getSelectedReflogCommit() + commit := gui.State.Contexts.ReflogCommits.GetSelected() var task updateTask if commit == nil { task = NewRenderStringTask("No reflog history") @@ -38,7 +32,7 @@ func (gui *Gui) reflogCommitsRenderToMain() error { } func (gui *Gui) CheckoutReflogCommit() error { - commit := gui.getSelectedReflogCommit() + commit := gui.State.Contexts.ReflogCommits.GetSelected() if commit == nil { return nil } @@ -55,19 +49,17 @@ func (gui *Gui) CheckoutReflogCommit() error { return err } - gui.State.Panels.ReflogCommits.SelectedLineIdx = 0 - return nil } func (gui *Gui) handleCreateReflogResetMenu() error { - commit := gui.getSelectedReflogCommit() + commit := gui.State.Contexts.ReflogCommits.GetSelected() return gui.helpers.Refs.CreateGitResetMenu(commit.Sha) } func (gui *Gui) handleViewReflogCommitFiles() error { - commit := gui.getSelectedReflogCommit() + commit := gui.State.Contexts.ReflogCommits.GetSelected() if commit == nil { return nil } @@ -81,7 +73,7 @@ func (gui *Gui) handleViewReflogCommitFiles() error { } func (gui *Gui) handleCopyReflogCommit() error { - commit := gui.getSelectedReflogCommit() + commit := gui.State.Contexts.ReflogCommits.GetSelected() if commit == nil { return nil } @@ -91,7 +83,7 @@ func (gui *Gui) handleCopyReflogCommit() error { func (gui *Gui) handleCopyReflogCommitRange() error { // just doing this to ensure something is selected - commit := gui.getSelectedReflogCommit() + commit := gui.State.Contexts.ReflogCommits.GetSelected() if commit == nil { return nil } diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go index a19a685dc..d4ed2d2f9 100644 --- a/pkg/gui/refresh.go +++ b/pkg/gui/refresh.go @@ -211,7 +211,7 @@ func (gui *Gui) refreshCommitsWithLimit() error { commits, err := gui.git.Loaders.Commits.GetCommits( loaders.GetCommitsOptions{ - Limit: gui.State.Panels.Commits.LimitCommits, + Limit: gui.State.LimitCommits, FilterPath: gui.State.Modes.Filtering.GetPath(), IncludeRebaseCommits: true, RefName: gui.refForLog(), @@ -484,7 +484,7 @@ func (gui *Gui) refreshReflogCommits() error { } func (gui *Gui) refreshRemotes() error { - prevSelectedRemote := gui.getSelectedRemote() + prevSelectedRemote := gui.State.Contexts.Remotes.GetSelected() remotes, err := gui.git.Loaders.Remotes.GetRemotes() if err != nil { diff --git a/pkg/gui/remote_branches_panel.go b/pkg/gui/remote_branches_panel.go index 0c00f8d80..243a7ca4d 100644 --- a/pkg/gui/remote_branches_panel.go +++ b/pkg/gui/remote_branches_panel.go @@ -4,25 +4,15 @@ import ( "fmt" "strings" - "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) // list panel functions -func (gui *Gui) getSelectedRemoteBranch() *models.RemoteBranch { - selectedLine := gui.State.Panels.RemoteBranches.SelectedLineIdx - if selectedLine == -1 || len(gui.State.Model.RemoteBranches) == 0 { - return nil - } - - return gui.State.Model.RemoteBranches[selectedLine] -} - func (gui *Gui) remoteBranchesRenderToMain() error { var task updateTask - remoteBranch := gui.getSelectedRemoteBranch() + remoteBranch := gui.State.Contexts.RemoteBranches.GetSelected() if remoteBranch == nil { task = NewRenderStringTask("No branches for this remote") } else { @@ -43,12 +33,12 @@ func (gui *Gui) handleRemoteBranchesEscape() error { } func (gui *Gui) handleMergeRemoteBranch() error { - selectedBranchName := gui.getSelectedRemoteBranch().FullName() + selectedBranchName := gui.State.Contexts.RemoteBranches.GetSelected().FullName() return gui.mergeBranchIntoCheckedOutBranch(selectedBranchName) } func (gui *Gui) handleDeleteRemoteBranch() error { - remoteBranch := gui.getSelectedRemoteBranch() + remoteBranch := gui.State.Contexts.RemoteBranches.GetSelected() if remoteBranch == nil { return nil } @@ -72,12 +62,12 @@ func (gui *Gui) handleDeleteRemoteBranch() error { } func (gui *Gui) handleRebaseOntoRemoteBranch() error { - selectedBranchName := gui.getSelectedRemoteBranch().FullName() + selectedBranchName := gui.State.Contexts.RemoteBranches.GetSelected().FullName() return gui.handleRebaseOntoBranch(selectedBranchName) } func (gui *Gui) handleSetBranchUpstream() error { - selectedBranch := gui.getSelectedRemoteBranch() + selectedBranch := gui.State.Contexts.RemoteBranches.GetSelected() checkedOutBranch := gui.getCheckedOutBranch() message := utils.ResolvePlaceholderString( @@ -103,7 +93,7 @@ func (gui *Gui) handleSetBranchUpstream() error { } func (gui *Gui) handleCreateResetToRemoteBranchMenu() error { - selectedBranch := gui.getSelectedRemoteBranch() + selectedBranch := gui.State.Contexts.RemoteBranches.GetSelected() if selectedBranch == nil { return nil } @@ -112,7 +102,7 @@ func (gui *Gui) handleCreateResetToRemoteBranchMenu() error { } func (gui *Gui) handleEnterRemoteBranch() error { - selectedBranch := gui.getSelectedRemoteBranch() + selectedBranch := gui.State.Contexts.RemoteBranches.GetSelected() if selectedBranch == nil { return nil } @@ -121,7 +111,7 @@ func (gui *Gui) handleEnterRemoteBranch() error { } func (gui *Gui) handleNewBranchOffRemoteBranch() error { - selectedBranch := gui.getSelectedRemoteBranch() + selectedBranch := gui.State.Contexts.RemoteBranches.GetSelected() if selectedBranch == nil { return nil } diff --git a/pkg/gui/remotes_panel.go b/pkg/gui/remotes_panel.go index 1273ee6ad..f47bd1a01 100644 --- a/pkg/gui/remotes_panel.go +++ b/pkg/gui/remotes_panel.go @@ -4,24 +4,14 @@ import ( "fmt" "strings" - "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/style" ) // list panel functions -func (gui *Gui) getSelectedRemote() *models.Remote { - selectedLine := gui.State.Panels.Remotes.SelectedLineIdx - if selectedLine == -1 || len(gui.State.Model.Remotes) == 0 { - return nil - } - - return gui.State.Model.Remotes[selectedLine] -} - func (gui *Gui) remotesRenderToMain() error { var task updateTask - remote := gui.getSelectedRemote() + remote := gui.State.Contexts.Remotes.GetSelected() if remote == nil { task = NewRenderStringTask("No remotes") } else { diff --git a/pkg/gui/stash_panel.go b/pkg/gui/stash_panel.go index ed68d3cd4..e51fcc054 100644 --- a/pkg/gui/stash_panel.go +++ b/pkg/gui/stash_panel.go @@ -9,12 +9,7 @@ import ( // list panel functions func (gui *Gui) getSelectedStashEntry() *models.StashEntry { - selectedLine := gui.State.Panels.Stash.SelectedLineIdx - if selectedLine == -1 { - return nil - } - - return gui.State.Model.StashEntries[selectedLine] + return gui.State.Contexts.Stash.GetSelected() } func (gui *Gui) stashRenderToMain() error { diff --git a/pkg/gui/sub_commits_panel.go b/pkg/gui/sub_commits_panel.go index a5756649f..04c131625 100644 --- a/pkg/gui/sub_commits_panel.go +++ b/pkg/gui/sub_commits_panel.go @@ -2,25 +2,14 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/loaders" - "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/types" ) // list panel functions -func (gui *Gui) getSelectedSubCommit() *models.Commit { - selectedLine := gui.State.Panels.SubCommits.SelectedLineIdx - commits := gui.State.Model.SubCommits - if selectedLine == -1 || len(commits) == 0 { - return nil - } - - return commits[selectedLine] -} - func (gui *Gui) subCommitsRenderToMain() error { - commit := gui.getSelectedSubCommit() + commit := gui.State.Contexts.SubCommits.GetSelected() var task updateTask if commit == nil { task = NewRenderStringTask("No commits") @@ -39,7 +28,7 @@ func (gui *Gui) subCommitsRenderToMain() error { } func (gui *Gui) handleCheckoutSubCommit() error { - commit := gui.getSelectedSubCommit() + commit := gui.State.Contexts.SubCommits.GetSelected() if commit == nil { return nil } @@ -62,13 +51,13 @@ func (gui *Gui) handleCheckoutSubCommit() error { } func (gui *Gui) handleCreateSubCommitResetMenu() error { - commit := gui.getSelectedSubCommit() + commit := gui.State.Contexts.SubCommits.GetSelected() return gui.helpers.Refs.CreateGitResetMenu(commit.Sha) } func (gui *Gui) handleViewSubCommitFiles() error { - commit := gui.getSelectedSubCommit() + commit := gui.State.Contexts.SubCommits.GetSelected() if commit == nil { return nil } @@ -85,7 +74,7 @@ func (gui *Gui) switchToSubCommitsContext(refName string) error { // need to populate my sub commits commits, err := gui.git.Loaders.Commits.GetCommits( loaders.GetCommitsOptions{ - Limit: gui.State.Panels.Commits.LimitCommits, + Limit: gui.State.LimitCommits, FilterPath: gui.State.Modes.Filtering.GetPath(), IncludeRebaseCommits: false, RefName: refName, @@ -96,7 +85,6 @@ func (gui *Gui) switchToSubCommitsContext(refName string) error { } gui.State.Model.SubCommits = commits - gui.State.Panels.SubCommits.refName = refName gui.State.Contexts.SubCommits.GetPanelState().SetSelectedLineIdx(0) gui.State.Contexts.SubCommits.SetParentContext(gui.currentSideListContext()) @@ -104,7 +92,7 @@ func (gui *Gui) switchToSubCommitsContext(refName string) error { } func (gui *Gui) handleNewBranchOffSubCommit() error { - commit := gui.getSelectedSubCommit() + commit := gui.State.Contexts.SubCommits.GetSelected() if commit == nil { return nil } @@ -113,7 +101,7 @@ func (gui *Gui) handleNewBranchOffSubCommit() error { } func (gui *Gui) handleCopySubCommit() error { - commit := gui.getSelectedSubCommit() + commit := gui.State.Contexts.SubCommits.GetSelected() if commit == nil { return nil } @@ -123,7 +111,7 @@ func (gui *Gui) handleCopySubCommit() error { func (gui *Gui) handleCopySubCommitRange() error { // just doing this to ensure something is selected - commit := gui.getSelectedSubCommit() + commit := gui.State.Contexts.SubCommits.GetSelected() if commit == nil { return nil } diff --git a/pkg/gui/submodules_panel.go b/pkg/gui/submodules_panel.go index 490347c5d..3f25e077d 100644 --- a/pkg/gui/submodules_panel.go +++ b/pkg/gui/submodules_panel.go @@ -8,18 +8,9 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/style" ) -func (gui *Gui) getSelectedSubmodule() *models.SubmoduleConfig { - selectedLine := gui.State.Panels.Submodules.SelectedLineIdx - if selectedLine == -1 || len(gui.State.Model.Submodules) == 0 { - return nil - } - - return gui.State.Model.Submodules[selectedLine] -} - func (gui *Gui) submodulesRenderToMain() error { var task updateTask - submodule := gui.getSelectedSubmodule() + submodule := gui.State.Contexts.Submodules.GetSelected() if submodule == nil { task = NewRenderStringTask("No submodules") } else { diff --git a/pkg/gui/suggestions_panel.go b/pkg/gui/suggestions_panel.go index c11145ded..d7b8b0d2b 100644 --- a/pkg/gui/suggestions_panel.go +++ b/pkg/gui/suggestions_panel.go @@ -15,17 +15,12 @@ func (gui *Gui) getSelectedSuggestionValue() string { } func (gui *Gui) getSelectedSuggestion() *types.Suggestion { - selectedLine := gui.State.Panels.Suggestions.SelectedLineIdx - if selectedLine == -1 { - return nil - } - - return gui.State.Suggestions[selectedLine] + return gui.State.Contexts.Suggestions.GetSelected() } func (gui *Gui) setSuggestions(suggestions []*types.Suggestion) { gui.State.Suggestions = suggestions - gui.State.Panels.Suggestions.SelectedLineIdx = 0 + gui.State.Contexts.Suggestions.SetSelectedLineIdx(0) _ = gui.resetOrigin(gui.Views.Suggestions) _ = gui.State.Contexts.Suggestions.HandleRender() } diff --git a/pkg/gui/tags_panel.go b/pkg/gui/tags_panel.go index f452974d7..9757fdc77 100644 --- a/pkg/gui/tags_panel.go +++ b/pkg/gui/tags_panel.go @@ -2,7 +2,7 @@ package gui func (self *Gui) tagsRenderToMain() error { var task updateTask - tag := self.State.Contexts.Tags.GetSelectedTag() + tag := self.State.Contexts.Tags.GetSelected() if tag == nil { task = NewRenderStringTask("No tags") } else { diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index 7b9f47001..2f59b15f5 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -24,6 +24,7 @@ type ParentContexter interface { } type IBaseContext interface { + HasKeybindings ParentContexter GetKind() ContextKind @@ -35,9 +36,7 @@ type IBaseContext interface { GetOptionsMap() map[string]string - GetKeybindings(opts KeybindingsOpts) []*Binding AddKeybindingsFn(KeybindingsFn) - GetMouseKeybindings(opts KeybindingsOpts) []*gocui.ViewMouseBinding AddMouseKeybindingsFn(MouseKeybindingsFn) } @@ -50,6 +49,33 @@ type Context interface { HandleRenderToMain() error } +type IListContext interface { + Context + + GetSelectedItemId() string + + GetList() IList + + OnSearchSelect(selectedLineIdx int) error + FocusLine() + + GetPanelState() IListPanelState + GetViewTrait() IViewTrait +} + +type IViewTrait interface { + FocusPoint(yIdx int) + SetViewPortContent(content string) + SetContent(content string) + SetFooter(value string) + SetOriginX(value int) + ViewPortYBounds() (int, int) + ScrollLeft() + ScrollRight() + PageDelta() int + SelectedLineIdx() int +} + type OnFocusOpts struct { ClickedViewName string ClickedViewLineIdx int @@ -76,28 +102,6 @@ type IController interface { Context() Context } -type IListContext interface { - HasKeybindings - - GetSelectedItemId() string - HandlePrevLine() error - HandleNextLine() error - HandleScrollLeft() error - HandleScrollRight() error - HandlePrevPage() error - HandleNextPage() error - HandleGotoTop() error - HandleGotoBottom() error - HandleClick(onClick func() error) error - - OnSearchSelect(selectedLineIdx int) error - FocusLine() - - GetPanelState() IListPanelState - - Context -} - type IList interface { IListCursor GetItemsLength() int From cd31a762b97c071fbd33ea9b82f679890e68eaa7 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 6 Feb 2022 13:42:17 +1100 Subject: [PATCH 054/385] rename OSCommand field to os --- pkg/commands/oscommands/os.go | 5 +++++ pkg/gui/branches_panel.go | 2 +- pkg/gui/controllers/files_helper.go | 7 ++++++- pkg/gui/custom_commands.go | 4 ++-- pkg/gui/diffing.go | 2 +- pkg/gui/global_handlers.go | 2 +- pkg/gui/gpg.go | 4 ++-- pkg/gui/gui.go | 14 +++++++------- pkg/gui/information_panel.go | 4 ++-- pkg/gui/line_by_line_panel.go | 4 ++-- pkg/gui/pull_request_menu_panel.go | 2 +- pkg/gui/quitting.go | 2 +- pkg/gui/recent_repos_panel.go | 2 +- 13 files changed, 32 insertions(+), 22 deletions(-) diff --git a/pkg/commands/oscommands/os.go b/pkg/commands/oscommands/os.go index 53f5bd6f6..1c4f5bf28 100644 --- a/pkg/commands/oscommands/os.go +++ b/pkg/commands/oscommands/os.go @@ -72,9 +72,14 @@ func FileType(path string) string { } func (c *OSCommand) OpenFile(filename string) error { + return c.OpenFileAtLine(filename, 1) +} + +func (c *OSCommand) OpenFileAtLine(filename string, lineNumber int) error { commandTemplate := c.UserConfig.OS.OpenCommand templateValues := map[string]string{ "filename": c.Quote(filename), + "line": fmt.Sprintf("%d", lineNumber), } command := utils.ResolvePlaceholderString(commandTemplate, templateValues) return c.Cmd.NewShell(command).Run() diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index 072ee257b..7fcf050b3 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -79,7 +79,7 @@ func (gui *Gui) handleCopyPullRequestURLPress() error { return gui.c.Error(err) } gui.c.LogAction(gui.c.Tr.Actions.CopyPullRequestURL) - if err := gui.OSCommand.CopyToClipboard(url); err != nil { + if err := gui.os.CopyToClipboard(url); err != nil { return gui.c.Error(err) } diff --git a/pkg/gui/controllers/files_helper.go b/pkg/gui/controllers/files_helper.go index c3706cc72..35f388183 100644 --- a/pkg/gui/controllers/files_helper.go +++ b/pkg/gui/controllers/files_helper.go @@ -10,6 +10,7 @@ type IFilesHelper interface { EditFile(filename string) error EditFileAtLine(filename string, lineNumber int) error OpenFile(filename string) error + OpenFileAtLine(filename string, lineNumber int) error } type FilesHelper struct { @@ -49,8 +50,12 @@ func (self *FilesHelper) EditFileAtLine(filename string, lineNumber int) error { } func (self *FilesHelper) OpenFile(filename string) error { + return self.OpenFileAtLine(filename, 1) +} + +func (self *FilesHelper) OpenFileAtLine(filename string, lineNumber int) error { self.c.LogAction(self.c.Tr.Actions.OpenFile) - if err := self.os.OpenFile(filename); err != nil { + if err := self.os.OpenFileAtLine(filename, lineNumber); err != nil { return self.c.Error(err) } return nil diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index 8111dd06c..e32e5bb11 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -247,7 +247,7 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand } if customCommand.Subprocess { - return gui.runSubprocessWithSuspenseAndRefresh(gui.OSCommand.Cmd.NewShell(cmdStr)) + return gui.runSubprocessWithSuspenseAndRefresh(gui.os.Cmd.NewShell(cmdStr)) } loadingText := customCommand.LoadingText @@ -256,7 +256,7 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand } return gui.c.WithWaitingStatus(loadingText, func() error { gui.c.LogAction(gui.c.Tr.Actions.CustomCommand) - cmdObj := gui.OSCommand.Cmd.NewShell(cmdStr) + cmdObj := gui.os.Cmd.NewShell(cmdStr) if customCommand.Stream { cmdObj.StreamOutput() } diff --git a/pkg/gui/diffing.go b/pkg/gui/diffing.go index 30af99882..a23772ab3 100644 --- a/pkg/gui/diffing.go +++ b/pkg/gui/diffing.go @@ -15,7 +15,7 @@ func (gui *Gui) exitDiffMode() error { } func (gui *Gui) renderDiff() error { - cmdObj := gui.OSCommand.Cmd.New( + cmdObj := gui.os.Cmd.New( fmt.Sprintf("git diff --submodule --no-ext-diff --color %s", gui.diffStr()), ) task := NewRunPtyTask(cmdObj.GetCmd()) diff --git a/pkg/gui/global_handlers.go b/pkg/gui/global_handlers.go index ba8a0a237..d14c5193d 100644 --- a/pkg/gui/global_handlers.go +++ b/pkg/gui/global_handlers.go @@ -219,7 +219,7 @@ func (gui *Gui) handleCopySelectedSideContextItemToClipboard() error { } gui.c.LogAction(gui.c.Tr.Actions.CopyToClipboard) - if err := gui.OSCommand.CopyToClipboard(itemId); err != nil { + if err := gui.os.CopyToClipboard(itemId); err != nil { return gui.c.Error(err) } diff --git a/pkg/gui/gpg.go b/pkg/gui/gpg.go index a469b2a61..60d728c42 100644 --- a/pkg/gui/gpg.go +++ b/pkg/gui/gpg.go @@ -18,7 +18,7 @@ func (gui *Gui) withGpgHandling(cmdObj oscommands.ICmdObj, waitingStatus string, useSubprocess := gui.git.Config.UsingGpg() if useSubprocess { - success, err := gui.runSubprocessWithSuspense(gui.OSCommand.Cmd.NewShell(cmdObj.ToString())) + success, err := gui.runSubprocessWithSuspense(gui.os.Cmd.NewShell(cmdObj.ToString())) if success && onSuccess != nil { if err := onSuccess(); err != nil { return err @@ -36,7 +36,7 @@ func (gui *Gui) withGpgHandling(cmdObj oscommands.ICmdObj, waitingStatus string, func (gui *Gui) RunAndStream(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error { return gui.c.WithWaitingStatus(waitingStatus, func() error { - cmdObj := gui.OSCommand.Cmd.NewShell(cmdObj.ToString()) + cmdObj := gui.os.Cmd.NewShell(cmdObj.ToString()) cmdObj.AddEnvVars("TERM=dumb") cmdWriter := gui.getCmdWriter() cmd := cmdObj.GetCmd() diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 3cc6129e3..9038fe647 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -83,9 +83,9 @@ type Repo string // Gui wraps the gocui Gui object which handles rendering and events type Gui struct { *common.Common - g *gocui.Gui - git *commands.GitCommand - OSCommand *oscommands.OSCommand + g *gocui.Gui + git *commands.GitCommand + os *oscommands.OSCommand // this is the state of the GUI for the current repo State *GuiRepoState @@ -318,7 +318,7 @@ func (gui *Gui) onNewRepo(filterPath string, reuseState bool) error { var err error gui.git, err = commands.NewGitCommand( gui.Common, - gui.OSCommand, + gui.os, git_config.NewStdCachedGitConfig(gui.Log), gui.Mutexes.SyncMutex, ) @@ -479,7 +479,7 @@ func NewGui( osCommand := oscommands.NewOSCommand(cmn, oscommands.GetPlatform(), guiIO) - gui.OSCommand = osCommand + gui.os = osCommand gui.watchFilesForChanges() @@ -509,7 +509,7 @@ func NewGui( func (gui *Gui) resetControllers() { controllerCommon := gui.c - osCommand := gui.OSCommand + osCommand := gui.os rebaseHelper := controllers.NewRebaseHelper(controllerCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling) model := gui.State.Model gui.helpers = &Helpers{ @@ -977,7 +977,7 @@ func (gui *Gui) loadNewRepo() error { return err } - if err := gui.OSCommand.UpdateWindowTitle(); err != nil { + if err := gui.os.UpdateWindowTitle(); err != nil { return err } diff --git a/pkg/gui/information_panel.go b/pkg/gui/information_panel.go index 07e64fb42..3e317a349 100644 --- a/pkg/gui/information_panel.go +++ b/pkg/gui/information_panel.go @@ -44,9 +44,9 @@ func (gui *Gui) handleInfoClick() error { // if we're not in an active mode we show the donate button if cx <= len(gui.c.Tr.Donate) { - return gui.OSCommand.OpenLink(constants.Links.Donate) + return gui.os.OpenLink(constants.Links.Donate) } else if cx <= len(gui.c.Tr.Donate)+1+len(gui.c.Tr.AskQuestion) { - return gui.OSCommand.OpenLink(constants.Links.Discussions) + return gui.os.OpenLink(constants.Links.Discussions) } return nil } diff --git a/pkg/gui/line_by_line_panel.go b/pkg/gui/line_by_line_panel.go index e9cace6d8..7f423f115 100644 --- a/pkg/gui/line_by_line_panel.go +++ b/pkg/gui/line_by_line_panel.go @@ -88,7 +88,7 @@ func (gui *Gui) copySelectedToClipboard() error { selected := state.PlainRenderSelected() gui.c.LogAction(gui.c.Tr.Actions.CopySelectedTextToClipboard) - if err := gui.OSCommand.CopyToClipboard(selected); err != nil { + if err := gui.os.CopyToClipboard(selected); err != nil { return gui.c.Error(err) } @@ -210,7 +210,7 @@ func (gui *Gui) handleOpenFileAtLine() error { // need to look at current index, then work out what my hunk's header information is, and see how far my line is away from the hunk header lineNumber := state.CurrentLineNumber() - if err := gui.editFileAtLine(filename, lineNumber); err != nil { + if err := gui.os.OpenFileAtLine(filename, lineNumber); err != nil { return err } diff --git a/pkg/gui/pull_request_menu_panel.go b/pkg/gui/pull_request_menu_panel.go index 10f7bcdf5..1f63c6306 100644 --- a/pkg/gui/pull_request_menu_panel.go +++ b/pkg/gui/pull_request_menu_panel.go @@ -64,7 +64,7 @@ func (gui *Gui) createPullRequest(from string, to string) error { gui.c.LogAction(gui.c.Tr.Actions.OpenPullRequest) - if err := gui.OSCommand.OpenLink(url); err != nil { + if err := gui.os.OpenLink(url); err != nil { return gui.c.Error(err) } diff --git a/pkg/gui/quitting.go b/pkg/gui/quitting.go index 4db28dcb1..99ebdfb1a 100644 --- a/pkg/gui/quitting.go +++ b/pkg/gui/quitting.go @@ -25,7 +25,7 @@ func (gui *Gui) recordDirectory(dirName string) error { if newDirFilePath == "" { return nil } - return gui.OSCommand.CreateFileWithContent(newDirFilePath, dirName) + return gui.os.CreateFileWithContent(newDirFilePath, dirName) } func (gui *Gui) handleQuitWithoutChangingDirectory() error { diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index 16b6b1df9..73ee784c3 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -62,7 +62,7 @@ func (gui *Gui) dispatchSwitchToRepo(path string, reuse bool) error { return err } - if err := commands.VerifyInGitRepo(gui.OSCommand); err != nil { + if err := commands.VerifyInGitRepo(gui.os); err != nil { if err := os.Chdir(originalPath); err != nil { return err } From b93b8cc00a2f2ea339b1ecdbc380320556490d3b Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 6 Feb 2022 14:37:16 +1100 Subject: [PATCH 055/385] controller for viewing sub commits --- pkg/gui/commits_panel.go | 5 +- pkg/gui/context/branches_context.go | 9 ++ pkg/gui/context/list_context_trait.go | 5 - pkg/gui/context/local_commits_context.go | 14 ++- pkg/gui/context/remote_branches_context.go | 9 ++ pkg/gui/context/tags_context.go | 9 ++ .../controllers/local_commits_controller.go | 18 +-- pkg/gui/controllers/refs_helper.go | 33 +++--- pkg/gui/controllers/remotes_controller.go | 2 +- .../sub_commits_switch_controller.go | 105 ++++++++++++++++++ pkg/gui/controllers/tags_controller.go | 11 +- pkg/gui/filtering.go | 2 +- pkg/gui/gui.go | 32 +++--- pkg/gui/keybindings.go | 14 --- pkg/gui/menu_panel.go | 2 +- pkg/gui/reflog_panel.go | 2 +- pkg/gui/refresh.go | 2 +- pkg/gui/sub_commits_panel.go | 8 +- pkg/gui/types/context.go | 1 - pkg/gui/types/modes.go | 13 +++ 20 files changed, 210 insertions(+), 86 deletions(-) create mode 100644 pkg/gui/controllers/sub_commits_switch_controller.go create mode 100644 pkg/gui/types/modes.go diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index 37e234e82..bed39a05a 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -15,8 +15,9 @@ func (gui *Gui) getSelectedLocalCommit() *models.Commit { } func (gui *Gui) onCommitFocus() error { - if gui.State.Contexts.BranchCommits.GetSelectedLineIdx() > COMMIT_THRESHOLD && gui.State.LimitCommits { - gui.State.LimitCommits = false + context := gui.State.Contexts.BranchCommits + if context.GetSelectedLineIdx() > COMMIT_THRESHOLD && context.GetLimitCommits() { + context.SetLimitCommits(false) go utils.Safe(func() { if err := gui.refreshCommitsWithLimit(); err != nil { _ = gui.c.Error(err) diff --git a/pkg/gui/context/branches_context.go b/pkg/gui/context/branches_context.go index 0be6e1dce..4b82844f4 100644 --- a/pkg/gui/context/branches_context.go +++ b/pkg/gui/context/branches_context.go @@ -84,3 +84,12 @@ func (self *BranchesViewModel) GetSelected() *models.Branch { return self.getModel()[self.GetSelectedLineIdx()] } + +func (self *BranchesViewModel) GetSelectedRefName() string { + item := self.GetSelected() + if item == nil { + return "" + } + + return item.RefName() +} diff --git a/pkg/gui/context/list_context_trait.go b/pkg/gui/context/list_context_trait.go index e4fab30bf..b716bb25e 100644 --- a/pkg/gui/context/list_context_trait.go +++ b/pkg/gui/context/list_context_trait.go @@ -20,11 +20,6 @@ func (self *ListContextTrait) GetList() types.IList { return self.list } -// TODO: remove -func (self *ListContextTrait) GetPanelState() types.IListPanelState { - return self.list -} - func (self *ListContextTrait) GetViewTrait() types.IViewTrait { return self.viewTrait } diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index 0345ecb81..533d97cb2 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -61,12 +61,14 @@ func (self *LocalCommitsContext) GetSelectedItemId() string { type LocalCommitsViewModel struct { *traits.ListCursor - getModel func() []*models.Commit + limitCommits bool + getModel func() []*models.Commit } func NewLocalCommitsViewModel(getModel func() []*models.Commit) *LocalCommitsViewModel { self := &LocalCommitsViewModel{ - getModel: getModel, + getModel: getModel, + limitCommits: true, } self.ListCursor = traits.NewListCursor(self) @@ -85,3 +87,11 @@ func (self *LocalCommitsViewModel) GetSelected() *models.Commit { return self.getModel()[self.GetSelectedLineIdx()] } + +func (self *LocalCommitsViewModel) SetLimitCommits(value bool) { + self.limitCommits = value +} + +func (self *LocalCommitsViewModel) GetLimitCommits() bool { + return self.limitCommits +} diff --git a/pkg/gui/context/remote_branches_context.go b/pkg/gui/context/remote_branches_context.go index e15e80261..6ec5f887b 100644 --- a/pkg/gui/context/remote_branches_context.go +++ b/pkg/gui/context/remote_branches_context.go @@ -84,3 +84,12 @@ func (self *RemoteBranchesViewModel) GetSelected() *models.RemoteBranch { return self.getModel()[self.GetSelectedLineIdx()] } + +func (self *RemoteBranchesViewModel) GetSelectedRefName() string { + item := self.GetSelected() + if item == nil { + return "" + } + + return item.RefName() +} diff --git a/pkg/gui/context/tags_context.go b/pkg/gui/context/tags_context.go index e0409cfba..169a4989d 100644 --- a/pkg/gui/context/tags_context.go +++ b/pkg/gui/context/tags_context.go @@ -84,3 +84,12 @@ func (self *TagsViewModel) GetSelected() *models.Tag { return self.getModel()[self.GetSelectedLineIdx()] } + +func (self *TagsViewModel) GetSelectedRefName() string { + item := self.GetSelected() + if item == nil { + return "" + } + + return item.RefName() +} diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index 4ce7b88da..bb06a2314 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -38,8 +38,6 @@ type LocalCommitsController struct { pullFiles PullFilesFn getHostingServiceMgr GetHostingServiceMgrFn switchToCommitFilesContext SwitchToCommitFilesContextFn - getLimitCommits func() bool - setLimitCommits func(bool) getShowWholeGitGraph func() bool setShowWholeGitGraph func(bool) } @@ -60,8 +58,6 @@ func NewLocalCommitsController( pullFiles PullFilesFn, getHostingServiceMgr GetHostingServiceMgrFn, switchToCommitFilesContext SwitchToCommitFilesContextFn, - getLimitCommits func() bool, - setLimitCommits func(bool), getShowWholeGitGraph func() bool, setShowWholeGitGraph func(bool), ) *LocalCommitsController { @@ -80,8 +76,6 @@ func NewLocalCommitsController( pullFiles: pullFiles, getHostingServiceMgr: getHostingServiceMgr, switchToCommitFilesContext: switchToCommitFilesContext, - getLimitCommits: getLimitCommits, - setLimitCommits: setLimitCommits, getShowWholeGitGraph: getShowWholeGitGraph, setShowWholeGitGraph: setShowWholeGitGraph, } @@ -466,7 +460,7 @@ func (self *LocalCommitsController) handleCommitMoveDown() error { } func (self *LocalCommitsController) handleCommitMoveUp() error { - index := self.context.GetPanelState().GetSelectedLineIdx() + index := self.context.GetSelectedLineIdx() if index == 0 { return nil } @@ -641,8 +635,8 @@ func (self *LocalCommitsController) handleCreateCommitResetMenu(commit *models.C func (self *LocalCommitsController) openSearch() error { // we usually lazyload these commits but now that we're searching we need to load them now - if self.getLimitCommits() { - self.setLimitCommits(false) + if self.context.GetLimitCommits() { + self.context.SetLimitCommits(false) if err := self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS}}); err != nil { return err } @@ -655,8 +649,8 @@ func (self *LocalCommitsController) openSearch() error { func (self *LocalCommitsController) gotoBottom() error { // we usually lazyload these commits but now that we're jumping to the bottom we need to load them now - if self.getLimitCommits() { - self.setLimitCommits(false) + if self.context.GetLimitCommits() { + self.context.SetLimitCommits(false) if err := self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}); err != nil { return err } @@ -693,7 +687,7 @@ func (self *LocalCommitsController) handleOpenLogMenu() error { self.setShowWholeGitGraph(!self.getShowWholeGitGraph()) if self.getShowWholeGitGraph() { - self.setLimitCommits(false) + self.context.SetLimitCommits(false) } return self.c.WithWaitingStatus(self.c.Tr.LcLoadingCommits, func() error { diff --git a/pkg/gui/controllers/refs_helper.go b/pkg/gui/controllers/refs_helper.go index 8d56ec0d7..e6d9babfb 100644 --- a/pkg/gui/controllers/refs_helper.go +++ b/pkg/gui/controllers/refs_helper.go @@ -20,23 +20,20 @@ type IRefsHelper interface { } type RefsHelper struct { - c *types.ControllerCommon - git *commands.GitCommand - contexts *context.ContextTree - limitCommits func() + c *types.ControllerCommon + git *commands.GitCommand + contexts *context.ContextTree } func NewRefsHelper( c *types.ControllerCommon, git *commands.GitCommand, contexts *context.ContextTree, - limitCommits func(), ) *RefsHelper { return &RefsHelper{ - c: c, - git: git, - contexts: contexts, - limitCommits: limitCommits, + c: c, + git: git, + contexts: contexts, } } @@ -51,11 +48,11 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions cmdOptions := git_commands.CheckoutOptions{Force: false, EnvVars: options.EnvVars} onSuccess := func() { - self.contexts.Branches.GetPanelState().SetSelectedLineIdx(0) - self.contexts.BranchCommits.GetPanelState().SetSelectedLineIdx(0) - self.contexts.ReflogCommits.GetPanelState().SetSelectedLineIdx(0) + self.contexts.Branches.SetSelectedLineIdx(0) + self.contexts.ReflogCommits.SetSelectedLineIdx(0) + self.contexts.BranchCommits.SetSelectedLineIdx(0) // loading a heap of commits is slow so we limit them whenever doing a reset - self.limitCommits() + self.contexts.BranchCommits.SetLimitCommits(true) } return self.c.WithWaitingStatus(waitingStatus, func() error { @@ -107,10 +104,10 @@ func (self *RefsHelper) ResetToRef(ref string, strength string, envVars []string return self.c.Error(err) } - self.contexts.BranchCommits.GetPanelState().SetSelectedLineIdx(0) - self.contexts.ReflogCommits.GetPanelState().SetSelectedLineIdx(0) + self.contexts.BranchCommits.SetSelectedLineIdx(0) + self.contexts.ReflogCommits.SetSelectedLineIdx(0) // loading a heap of commits is slow so we limit them whenever doing a reset - self.limitCommits() + self.contexts.BranchCommits.SetLimitCommits(true) if err := self.c.PushContext(self.contexts.BranchCommits); err != nil { return err @@ -169,8 +166,8 @@ func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggest } } - self.contexts.BranchCommits.GetPanelState().SetSelectedLineIdx(0) - self.contexts.Branches.GetPanelState().SetSelectedLineIdx(0) + self.contexts.BranchCommits.SetSelectedLineIdx(0) + self.contexts.Branches.SetSelectedLineIdx(0) return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) }, diff --git a/pkg/gui/controllers/remotes_controller.go b/pkg/gui/controllers/remotes_controller.go index ff3b943fb..12d2e7459 100644 --- a/pkg/gui/controllers/remotes_controller.go +++ b/pkg/gui/controllers/remotes_controller.go @@ -81,7 +81,7 @@ func (self *RemotesController) enter(remote *models.Remote) error { if len(remote.Branches) == 0 { newSelectedLine = -1 } - self.contexts.RemoteBranches.GetPanelState().SetSelectedLineIdx(newSelectedLine) + self.contexts.RemoteBranches.SetSelectedLineIdx(newSelectedLine) return self.c.PushContext(self.contexts.RemoteBranches) } diff --git a/pkg/gui/controllers/sub_commits_switch_controller.go b/pkg/gui/controllers/sub_commits_switch_controller.go new file mode 100644 index 000000000..dbd6ab135 --- /dev/null +++ b/pkg/gui/controllers/sub_commits_switch_controller.go @@ -0,0 +1,105 @@ +package controllers + +import ( + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/loaders" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type SubCommitsSwitchControllerFactory struct { + c *types.ControllerCommon + subCommitsContext *context.SubCommitsContext + git *commands.GitCommand + modes *types.Modes + setSubCommits func([]*models.Commit) +} + +var _ types.IController = &SubCommitsSwitchController{} + +type ContextWithRefName interface { + types.Context + GetSelectedRefName() string +} + +type SubCommitsSwitchController struct { + baseController + + c *types.ControllerCommon + context ContextWithRefName + subCommitsContext *context.SubCommitsContext + git *commands.GitCommand + modes *types.Modes + setSubCommits func([]*models.Commit) +} + +func NewSubCommitsSwitchControllerFactory( + c *types.ControllerCommon, + subCommitsContext *context.SubCommitsContext, + git *commands.GitCommand, + modes *types.Modes, + setSubCommits func([]*models.Commit), +) *SubCommitsSwitchControllerFactory { + return &SubCommitsSwitchControllerFactory{ + c: c, + subCommitsContext: subCommitsContext, + git: git, + modes: modes, + setSubCommits: setSubCommits, + } +} + +func (self *SubCommitsSwitchControllerFactory) Create(context ContextWithRefName) *SubCommitsSwitchController { + return &SubCommitsSwitchController{ + baseController: baseController{}, + c: self.c, + context: context, + subCommitsContext: self.subCommitsContext, + git: self.git, + modes: self.modes, + setSubCommits: self.setSubCommits, + } +} + +func (self *SubCommitsSwitchController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + bindings := []*types.Binding{ + { + Handler: self.viewCommits, + Key: opts.GetKey(opts.Config.Universal.GoInto), + Description: self.c.Tr.LcViewCommits, + }, + } + + return bindings +} + +func (self *SubCommitsSwitchController) viewCommits() error { + refName := self.context.GetSelectedRefName() + if refName == "" { + return nil + } + + // need to populate my sub commits + commits, err := self.git.Loaders.Commits.GetCommits( + loaders.GetCommitsOptions{ + Limit: true, + FilterPath: self.modes.Filtering.GetPath(), + IncludeRebaseCommits: false, + RefName: refName, + }, + ) + if err != nil { + return err + } + + self.setSubCommits(commits) + self.subCommitsContext.SetSelectedLineIdx(0) + self.subCommitsContext.SetParentContext(self.context) + + return self.c.PushContext(self.subCommitsContext) +} + +func (self *SubCommitsSwitchController) Context() types.Context { + return self.context +} diff --git a/pkg/gui/controllers/tags_controller.go b/pkg/gui/controllers/tags_controller.go index 18135db02..e819c1973 100644 --- a/pkg/gui/controllers/tags_controller.go +++ b/pkg/gui/controllers/tags_controller.go @@ -78,11 +78,6 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types. Description: self.c.Tr.LcViewResetOptions, OpensMenu: true, }, - { - Key: opts.GetKey(opts.Config.Universal.GoInto), - Handler: self.withSelectedTag(self.enter), - Description: self.c.Tr.LcViewCommits, - }, } return bindings @@ -96,10 +91,6 @@ func (self *TagsController) checkout(tag *models.Tag) error { return self.c.PushContext(self.contexts.Branches) } -func (self *TagsController) enter(tag *models.Tag) error { - return self.switchToSubCommitsContext(tag.Name) -} - func (self *TagsController) delete(tag *models.Tag) error { prompt := utils.ResolvePlaceholderString( self.c.Tr.DeleteTagPrompt, @@ -153,7 +144,7 @@ func (self *TagsController) createResetMenu(tag *models.Tag) error { func (self *TagsController) create() error { // leaving commit SHA blank so that we're just creating the tag for the current commit - return self.tagsHelper.CreateTagMenu("", func() { self.context.GetPanelState().SetSelectedLineIdx(0) }) + return self.tagsHelper.CreateTagMenu("", func() { self.context.SetSelectedLineIdx(0) }) } func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func() error { diff --git a/pkg/gui/filtering.go b/pkg/gui/filtering.go index 6d75b2e77..4780387c9 100644 --- a/pkg/gui/filtering.go +++ b/pkg/gui/filtering.go @@ -51,6 +51,6 @@ func (gui *Gui) setFiltering(path string) error { } return gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}, Then: func() { - gui.State.Contexts.BranchCommits.GetPanelState().SetSelectedLineIdx(0) + gui.State.Contexts.BranchCommits.SetSelectedLineIdx(0) }}) } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 9038fe647..93e5c5ff3 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -175,7 +175,7 @@ type PrevLayout struct { type GuiRepoState struct { Model *types.Model - Modes Modes + Modes *types.Modes // Suggestions will sometimes appear when typing into a prompt Suggestions []*types.Suggestion @@ -297,12 +297,6 @@ const ( COMPLETE ) -type Modes struct { - Filtering filtering.Filtering - CherryPicking *cherrypicking.CherryPicking - Diffing diffing.Diffing -} - // if you add a new mutex here be sure to instantiate it. We're using pointers to // mutexes so that we can pass the mutexes to controllers. type guiMutexes struct { @@ -397,9 +391,8 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { UserVerticalScrolling: false, }, }, - LimitCommits: true, - Ptmx: nil, - Modes: Modes{ + Ptmx: nil, + Modes: &types.Modes{ Filtering: filtering.New(filterPath), CherryPicking: cherrypicking.New(), Diffing: diffing.New(), @@ -517,7 +510,6 @@ func (gui *Gui) resetControllers() { controllerCommon, gui.git, gui.State.Contexts, - func() { gui.State.LimitCommits = true }, ), Bisect: controllers.NewBisectHelper(controllerCommon, gui.git), Suggestions: controllers.NewSuggestionsHelper(controllerCommon, model, gui.refreshSuggestions), @@ -608,8 +600,6 @@ func (gui *Gui) resetControllers() { syncController.HandlePull, gui.getHostingServiceMgr, gui.SwitchToCommitFilesContext, - func() bool { return gui.State.LimitCommits }, - func(value bool) { gui.State.LimitCommits = value }, func() bool { return gui.ShowWholeGitGraph }, func(value bool) { gui.ShowWholeGitGraph = value }, ), @@ -634,6 +624,22 @@ func (gui *Gui) resetControllers() { Sync: syncController, } + switchToSubCommitsControllerFactory := controllers.NewSubCommitsSwitchControllerFactory( + controllerCommon, + gui.State.Contexts.SubCommits, + gui.git, + gui.State.Modes, + func(commits []*models.Commit) { gui.State.Model.SubCommits = commits }, + ) + + for _, context := range []controllers.ContextWithRefName{ + gui.State.Contexts.Branches, + gui.State.Contexts.RemoteBranches, + gui.State.Contexts.Tags, + } { + controllers.AttachControllers(context, switchToSubCommitsControllerFactory.Create(context)) + } + controllers.AttachControllers(gui.State.Contexts.Files, gui.Controllers.Files) controllers.AttachControllers(gui.State.Contexts.Tags, gui.Controllers.Tags) controllers.AttachControllers(gui.State.Contexts.Submodules, gui.Controllers.Submodules) diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 0083cd940..4b66281fc 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -477,13 +477,6 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin Handler: gui.handleCopySelectedSideContextItemToClipboard, Description: gui.c.Tr.LcCopyBranchNameToClipboard, }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.GoInto), - Handler: gui.handleEnterBranch, - Description: gui.c.Tr.LcViewCommits, - }, { ViewName: "branches", Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, @@ -499,13 +492,6 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin Description: gui.c.Tr.LcViewResetOptions, OpensMenu: true, }, - { - ViewName: "branches", - Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.GoInto), - Handler: gui.handleEnterRemoteBranch, - Description: gui.c.Tr.LcViewCommits, - }, { ViewName: "commits", Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)}, diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go index 9388be279..4afe931d1 100644 --- a/pkg/gui/menu_panel.go +++ b/pkg/gui/menu_panel.go @@ -49,7 +49,7 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error { })) gui.State.Contexts.Menu.SetMenuItems(opts.Items) - gui.State.Contexts.Menu.GetPanelState().SetSelectedLineIdx(0) + gui.State.Contexts.Menu.SetSelectedLineIdx(0) _ = gui.c.PostRefreshUpdate(gui.State.Contexts.Menu) // TODO: ensure that if we're opened a menu from within a menu that it renders correctly diff --git a/pkg/gui/reflog_panel.go b/pkg/gui/reflog_panel.go index 57b4e0a35..472c073cd 100644 --- a/pkg/gui/reflog_panel.go +++ b/pkg/gui/reflog_panel.go @@ -88,5 +88,5 @@ func (gui *Gui) handleCopyReflogCommitRange() error { return nil } - return gui.helpers.CherryPick.CopyRange(gui.State.Contexts.ReflogCommits.GetPanelState().GetSelectedLineIdx(), gui.State.Model.FilteredReflogCommits, gui.State.Contexts.ReflogCommits) + return gui.helpers.CherryPick.CopyRange(gui.State.Contexts.ReflogCommits.GetSelectedLineIdx(), gui.State.Model.FilteredReflogCommits, gui.State.Contexts.ReflogCommits) } diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go index d4ed2d2f9..84d58d815 100644 --- a/pkg/gui/refresh.go +++ b/pkg/gui/refresh.go @@ -211,7 +211,7 @@ func (gui *Gui) refreshCommitsWithLimit() error { commits, err := gui.git.Loaders.Commits.GetCommits( loaders.GetCommitsOptions{ - Limit: gui.State.LimitCommits, + Limit: gui.State.Contexts.BranchCommits.GetLimitCommits(), FilterPath: gui.State.Modes.Filtering.GetPath(), IncludeRebaseCommits: true, RefName: gui.refForLog(), diff --git a/pkg/gui/sub_commits_panel.go b/pkg/gui/sub_commits_panel.go index 04c131625..ddcb8f096 100644 --- a/pkg/gui/sub_commits_panel.go +++ b/pkg/gui/sub_commits_panel.go @@ -45,7 +45,7 @@ func (gui *Gui) handleCheckoutSubCommit() error { return err } - gui.State.Contexts.SubCommits.GetPanelState().SetSelectedLineIdx(0) + gui.State.Contexts.SubCommits.SetSelectedLineIdx(0) return nil } @@ -74,7 +74,7 @@ func (gui *Gui) switchToSubCommitsContext(refName string) error { // need to populate my sub commits commits, err := gui.git.Loaders.Commits.GetCommits( loaders.GetCommitsOptions{ - Limit: gui.State.LimitCommits, + Limit: true, FilterPath: gui.State.Modes.Filtering.GetPath(), IncludeRebaseCommits: false, RefName: refName, @@ -85,7 +85,7 @@ func (gui *Gui) switchToSubCommitsContext(refName string) error { } gui.State.Model.SubCommits = commits - gui.State.Contexts.SubCommits.GetPanelState().SetSelectedLineIdx(0) + gui.State.Contexts.SubCommits.SetSelectedLineIdx(0) gui.State.Contexts.SubCommits.SetParentContext(gui.currentSideListContext()) return gui.c.PushContext(gui.State.Contexts.SubCommits) @@ -116,5 +116,5 @@ func (gui *Gui) handleCopySubCommitRange() error { return nil } - return gui.helpers.CherryPick.CopyRange(gui.State.Contexts.SubCommits.GetPanelState().GetSelectedLineIdx(), gui.State.Model.SubCommits, gui.State.Contexts.SubCommits) + return gui.helpers.CherryPick.CopyRange(gui.State.Contexts.SubCommits.GetSelectedLineIdx(), gui.State.Model.SubCommits, gui.State.Contexts.SubCommits) } diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index 2f59b15f5..ed971d348 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -59,7 +59,6 @@ type IListContext interface { OnSearchSelect(selectedLineIdx int) error FocusLine() - GetPanelState() IListPanelState GetViewTrait() IViewTrait } diff --git a/pkg/gui/types/modes.go b/pkg/gui/types/modes.go new file mode 100644 index 000000000..ba135de63 --- /dev/null +++ b/pkg/gui/types/modes.go @@ -0,0 +1,13 @@ +package types + +import ( + "github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking" + "github.com/jesseduffield/lazygit/pkg/gui/modes/diffing" + "github.com/jesseduffield/lazygit/pkg/gui/modes/filtering" +) + +type Modes struct { + Filtering filtering.Filtering + CherryPicking *cherrypicking.CherryPicking + Diffing diffing.Diffing +} From 722410aded4e3d14356c7ab94bfa15abe10359fa Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 6 Feb 2022 15:54:26 +1100 Subject: [PATCH 056/385] refactor controllers --- pkg/gui/branches_panel.go | 378 ------- pkg/gui/commit_files_panel.go | 4 +- pkg/gui/context/branches_context.go | 2 +- pkg/gui/context/commit_files_context.go | 2 +- pkg/gui/context/list_context_trait.go | 2 +- pkg/gui/context/local_commits_context.go | 18 +- pkg/gui/context/menu_context.go | 2 +- pkg/gui/context/reflog_commits_context.go | 2 +- pkg/gui/context/remote_branches_context.go | 2 +- pkg/gui/context/remotes_context.go | 2 +- pkg/gui/context/stash_context.go | 2 +- pkg/gui/context/sub_commits_context.go | 2 +- pkg/gui/context/submodules_context.go | 2 +- pkg/gui/context/suggestions_context.go | 2 +- pkg/gui/context/tags_context.go | 2 +- pkg/gui/context/working_tree_context.go | 2 +- pkg/gui/controllers/bisect_controller.go | 49 +- pkg/gui/controllers/branches_controller.go | 475 +++++++++ pkg/gui/controllers/common.go | 39 + pkg/gui/controllers/files_controller.go | 129 ++- .../controllers/files_controller_remove.go | 2 +- pkg/gui/controllers/global_controller.go | 16 +- .../{ => helpers}/bisect_helper.go | 6 +- .../{ => helpers}/cherry_pick_helper.go | 10 +- .../controllers/{ => helpers}/files_helper.go | 6 +- pkg/gui/controllers/helpers/helpers.go | 13 + pkg/gui/controllers/helpers/host_helper.go | 46 + .../merge_and_rebase_helper.go} | 82 +- .../controllers/{ => helpers}/refs_helper.go | 19 +- .../{ => helpers}/suggestions_helper.go | 6 +- .../controllers/{ => helpers}/tags_helper.go | 6 +- .../{ => helpers}/working_tree_helper.go | 2 +- pkg/gui/controllers/list_controller.go | 6 +- .../controllers/local_commits_controller.go | 136 +-- pkg/gui/controllers/menu_controller.go | 21 +- pkg/gui/controllers/remotes_controller.go | 17 +- .../sub_commits_switch_controller.go | 47 +- pkg/gui/controllers/submodules_controller.go | 28 +- pkg/gui/controllers/sync_controller.go | 32 +- pkg/gui/controllers/tags_controller.go | 51 +- pkg/gui/controllers/types.go | 7 +- pkg/gui/controllers/undo_controller.go | 37 +- pkg/gui/custom_commands.go | 2 +- pkg/gui/global_handlers.go | 13 - pkg/gui/gui.go | 149 +-- pkg/gui/keybindings.go | 931 ++++++++---------- pkg/gui/modes.go | 2 +- pkg/gui/patch_options_panel.go | 8 +- pkg/gui/pull_request_menu_panel.go | 78 -- pkg/gui/reflog_panel.go | 7 +- pkg/gui/refresh.go | 6 +- pkg/gui/remote_branches_panel.go | 15 +- pkg/gui/stash_panel.go | 15 +- pkg/gui/status_panel.go | 10 +- pkg/gui/sub_commits_panel.go | 7 +- pkg/gui/types/common.go | 2 +- 56 files changed, 1406 insertions(+), 1553 deletions(-) create mode 100644 pkg/gui/controllers/branches_controller.go create mode 100644 pkg/gui/controllers/common.go rename pkg/gui/controllers/{ => helpers}/bisect_helper.go (91%) rename pkg/gui/controllers/{ => helpers}/cherry_pick_helper.go (96%) rename pkg/gui/controllers/{ => helpers}/files_helper.go (94%) create mode 100644 pkg/gui/controllers/helpers/helpers.go create mode 100644 pkg/gui/controllers/helpers/host_helper.go rename pkg/gui/controllers/{rebase_helper.go => helpers/merge_and_rebase_helper.go} (67%) rename pkg/gui/controllers/{ => helpers}/refs_helper.go (93%) rename pkg/gui/controllers/{ => helpers}/suggestions_helper.go (98%) rename pkg/gui/controllers/{ => helpers}/tags_helper.go (94%) rename pkg/gui/controllers/{ => helpers}/working_tree_helper.go (98%) delete mode 100644 pkg/gui/pull_request_menu_panel.go diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go index 7fcf050b3..959085645 100644 --- a/pkg/gui/branches_panel.go +++ b/pkg/gui/branches_panel.go @@ -1,18 +1,5 @@ package gui -import ( - "errors" - "fmt" - "strings" - - "github.com/jesseduffield/lazygit/pkg/commands/git_commands" - "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/jesseduffield/lazygit/pkg/utils" -) - -// list panel functions - func (gui *Gui) branchesRenderToMain() error { var task updateTask branch := gui.State.Contexts.Branches.GetSelected() @@ -31,368 +18,3 @@ func (gui *Gui) branchesRenderToMain() error { }, }) } - -// specific functions - -func (gui *Gui) handleBranchPress() error { - branch := gui.State.Contexts.Branches.GetSelected() - if branch == nil { - return nil - } - - if branch == gui.getCheckedOutBranch() { - return gui.c.ErrorMsg(gui.c.Tr.AlreadyCheckedOutBranch) - } - - gui.c.LogAction(gui.c.Tr.Actions.CheckoutBranch) - return gui.helpers.Refs.CheckoutRef(branch.Name, types.CheckoutRefOptions{}) -} - -func (gui *Gui) handleCreatePullRequestPress() error { - branch := gui.State.Contexts.Branches.GetSelected() - return gui.createPullRequest(branch.Name, "") -} - -func (gui *Gui) handleCreatePullRequestMenu() error { - selectedBranch := gui.State.Contexts.Branches.GetSelected() - if selectedBranch == nil { - return nil - } - checkedOutBranch := gui.getCheckedOutBranch() - - return gui.createPullRequestMenu(selectedBranch, checkedOutBranch) -} - -func (gui *Gui) handleCopyPullRequestURLPress() error { - hostingServiceMgr := gui.getHostingServiceMgr() - - branch := gui.State.Contexts.Branches.GetSelected() - - branchExistsOnRemote := gui.git.Remote.CheckRemoteBranchExists(branch.Name) - - if !branchExistsOnRemote { - return gui.c.Error(errors.New(gui.c.Tr.NoBranchOnRemote)) - } - - url, err := hostingServiceMgr.GetPullRequestURL(branch.Name, "") - if err != nil { - return gui.c.Error(err) - } - gui.c.LogAction(gui.c.Tr.Actions.CopyPullRequestURL) - if err := gui.os.CopyToClipboard(url); err != nil { - return gui.c.Error(err) - } - - gui.c.Toast(gui.c.Tr.PullRequestURLCopiedToClipboard) - - return nil -} - -func (gui *Gui) handleGitFetch() error { - return gui.c.WithLoaderPanel(gui.c.Tr.FetchWait, func() error { - if err := gui.fetch(); err != nil { - _ = gui.c.Error(err) - } - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) - }) -} - -func (gui *Gui) handleForceCheckout() error { - branch := gui.State.Contexts.Branches.GetSelected() - message := gui.c.Tr.SureForceCheckout - title := gui.c.Tr.ForceCheckoutBranch - - return gui.c.Ask(types.AskOpts{ - Title: title, - Prompt: message, - HandleConfirm: func() error { - gui.c.LogAction(gui.c.Tr.Actions.ForceCheckoutBranch) - if err := gui.git.Branch.Checkout(branch.Name, git_commands.CheckoutOptions{Force: true}); err != nil { - _ = gui.c.Error(err) - } - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) - }, - }) -} - -func (gui *Gui) handleCheckoutByName() error { - return gui.c.Prompt(types.PromptOpts{ - Title: gui.c.Tr.BranchName + ":", - FindSuggestionsFunc: gui.helpers.Suggestions.GetRefsSuggestionsFunc(), - HandleConfirm: func(response string) error { - gui.c.LogAction("Checkout branch") - return gui.helpers.Refs.CheckoutRef(response, types.CheckoutRefOptions{ - OnRefNotFound: func(ref string) error { - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.BranchNotFoundTitle, - Prompt: fmt.Sprintf("%s %s%s", gui.c.Tr.BranchNotFoundPrompt, ref, "?"), - HandleConfirm: func() error { - return gui.createNewBranchWithName(ref) - }, - }) - }, - }) - }}, - ) -} - -func (gui *Gui) getCheckedOutBranch() *models.Branch { - if len(gui.State.Model.Branches) == 0 { - return nil - } - - return gui.State.Model.Branches[0] -} - -func (gui *Gui) createNewBranchWithName(newBranchName string) error { - branch := gui.State.Contexts.Branches.GetSelected() - if branch == nil { - return nil - } - - if err := gui.git.Branch.New(newBranchName, branch.Name); err != nil { - return gui.c.Error(err) - } - - gui.State.Contexts.Branches.SetSelectedLineIdx(0) - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) -} - -func (gui *Gui) handleDeleteBranch() error { - return gui.deleteBranch(false) -} - -func (gui *Gui) deleteBranch(force bool) error { - selectedBranch := gui.State.Contexts.Branches.GetSelected() - if selectedBranch == nil { - return nil - } - checkedOutBranch := gui.getCheckedOutBranch() - if checkedOutBranch.Name == selectedBranch.Name { - return gui.c.ErrorMsg(gui.c.Tr.CantDeleteCheckOutBranch) - } - return gui.deleteNamedBranch(selectedBranch, force) -} - -func (gui *Gui) deleteNamedBranch(selectedBranch *models.Branch, force bool) error { - title := gui.c.Tr.DeleteBranch - var templateStr string - if force { - templateStr = gui.c.Tr.ForceDeleteBranchMessage - } else { - templateStr = gui.c.Tr.DeleteBranchMessage - } - message := utils.ResolvePlaceholderString( - templateStr, - map[string]string{ - "selectedBranchName": selectedBranch.Name, - }, - ) - - return gui.c.Ask(types.AskOpts{ - Title: title, - Prompt: message, - HandleConfirm: func() error { - gui.c.LogAction(gui.c.Tr.Actions.DeleteBranch) - if err := gui.git.Branch.Delete(selectedBranch.Name, force); err != nil { - errMessage := err.Error() - if !force && strings.Contains(errMessage, "git branch -D ") { - return gui.deleteNamedBranch(selectedBranch, true) - } - return gui.c.ErrorMsg(errMessage) - } - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) - }, - }) -} - -func (gui *Gui) mergeBranchIntoCheckedOutBranch(branchName string) error { - if gui.git.Branch.IsHeadDetached() { - return gui.c.ErrorMsg("Cannot merge branch in detached head state. You might have checked out a commit directly or a remote branch, in which case you should checkout the local branch you want to be on") - } - checkedOutBranchName := gui.getCheckedOutBranch().Name - if checkedOutBranchName == branchName { - return gui.c.ErrorMsg(gui.c.Tr.CantMergeBranchIntoItself) - } - prompt := utils.ResolvePlaceholderString( - gui.c.Tr.ConfirmMerge, - map[string]string{ - "checkedOutBranch": checkedOutBranchName, - "selectedBranch": branchName, - }, - ) - - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.MergingTitle, - Prompt: prompt, - HandleConfirm: func() error { - gui.c.LogAction(gui.c.Tr.Actions.Merge) - err := gui.git.Branch.Merge(branchName, git_commands.MergeOpts{}) - return gui.helpers.Rebase.CheckMergeOrRebase(err) - }, - }) -} - -func (gui *Gui) handleMerge() error { - selectedBranchName := gui.State.Contexts.Branches.GetSelected().Name - return gui.mergeBranchIntoCheckedOutBranch(selectedBranchName) -} - -func (gui *Gui) handleRebaseOntoLocalBranch() error { - selectedBranchName := gui.State.Contexts.Branches.GetSelected().Name - return gui.handleRebaseOntoBranch(selectedBranchName) -} - -func (gui *Gui) handleRebaseOntoBranch(selectedBranchName string) error { - checkedOutBranch := gui.getCheckedOutBranch().Name - if selectedBranchName == checkedOutBranch { - return gui.c.ErrorMsg(gui.c.Tr.CantRebaseOntoSelf) - } - prompt := utils.ResolvePlaceholderString( - gui.c.Tr.ConfirmRebase, - map[string]string{ - "checkedOutBranch": checkedOutBranch, - "selectedBranch": selectedBranchName, - }, - ) - - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.RebasingTitle, - Prompt: prompt, - HandleConfirm: func() error { - gui.c.LogAction(gui.c.Tr.Actions.RebaseBranch) - err := gui.git.Rebase.RebaseBranch(selectedBranchName) - return gui.helpers.Rebase.CheckMergeOrRebase(err) - }, - }) -} - -func (gui *Gui) handleFastForward() error { - branch := gui.State.Contexts.Branches.GetSelected() - if branch == nil || !branch.IsRealBranch() { - return nil - } - - if !branch.IsTrackingRemote() { - return gui.c.ErrorMsg(gui.c.Tr.FwdNoUpstream) - } - if !branch.RemoteBranchStoredLocally() { - return gui.c.ErrorMsg(gui.c.Tr.FwdNoLocalUpstream) - } - if branch.HasCommitsToPush() { - return gui.c.ErrorMsg(gui.c.Tr.FwdCommitsToPush) - } - - action := gui.c.Tr.Actions.FastForwardBranch - - message := utils.ResolvePlaceholderString( - gui.c.Tr.Fetching, - map[string]string{ - "from": fmt.Sprintf("%s/%s", branch.UpstreamRemote, branch.UpstreamBranch), - "to": branch.Name, - }, - ) - - return gui.c.WithLoaderPanel(message, func() error { - if branch == gui.getCheckedOutBranch() { - gui.c.LogAction(action) - - err := gui.git.Sync.Pull( - git_commands.PullOptions{ - RemoteName: branch.UpstreamRemote, - BranchName: branch.Name, - FastForwardOnly: true, - }, - ) - if err != nil { - _ = gui.c.Error(err) - } - - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) - } else { - gui.c.LogAction(action) - err := gui.git.Sync.FastForward(branch.Name, branch.UpstreamRemote, branch.UpstreamBranch) - if err != nil { - _ = gui.c.Error(err) - } - _ = gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) - } - - return nil - }) -} - -func (gui *Gui) handleCreateResetToBranchMenu() error { - branch := gui.State.Contexts.Branches.GetSelected() - if branch == nil { - return nil - } - - return gui.helpers.Refs.CreateGitResetMenu(branch.Name) -} - -func (gui *Gui) handleRenameBranch() error { - branch := gui.State.Contexts.Branches.GetSelected() - if branch == nil || !branch.IsRealBranch() { - return nil - } - - promptForNewName := func() error { - return gui.c.Prompt(types.PromptOpts{ - Title: gui.c.Tr.NewBranchNamePrompt + " " + branch.Name + ":", - InitialContent: branch.Name, - HandleConfirm: func(newBranchName string) error { - gui.c.LogAction(gui.c.Tr.Actions.RenameBranch) - if err := gui.git.Branch.Rename(branch.Name, newBranchName); err != nil { - return gui.c.Error(err) - } - - // need to find where the branch is now so that we can re-select it. That means we need to refetch the branches synchronously and then find our branch - gui.refreshBranches() - - // now that we've got our stuff again we need to find that branch and reselect it. - for i, newBranch := range gui.State.Model.Branches { - if newBranch.Name == newBranchName { - gui.State.Contexts.Branches.SetSelectedLineIdx(i) - if err := gui.State.Contexts.Branches.HandleRender(); err != nil { - return err - } - } - } - - return nil - }, - }) - } - - // I could do an explicit check here for whether the branch is tracking a remote branch - // but if we've selected it we'll already know that via Pullables and Pullables. - // Bit of a hack but I'm lazy. - if !branch.IsTrackingRemote() { - return promptForNewName() - } - - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.LcRenameBranch, - Prompt: gui.c.Tr.RenameBranchWarning, - HandleConfirm: promptForNewName, - }) -} - -func (gui *Gui) handleEnterBranch() error { - branch := gui.State.Contexts.Branches.GetSelected() - if branch == nil { - return nil - } - - return gui.switchToSubCommitsContext(branch.RefName()) -} - -func (gui *Gui) handleNewBranchOffBranch() error { - selectedBranch := gui.State.Contexts.Branches.GetSelected() - if selectedBranch == nil { - return nil - } - - return gui.helpers.Refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), "") -} diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index fbbedcb6f..8f1201ccb 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -85,7 +85,7 @@ func (gui *Gui) handleDiscardOldFileChange() error { return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { gui.c.LogAction(gui.c.Tr.Actions.DiscardOldFileChange) if err := gui.git.Rebase.DiscardOldFileChanges(gui.State.Model.Commits, gui.State.Contexts.BranchCommits.GetSelectedLineIdx(), fileName); err != nil { - if err := gui.helpers.Rebase.CheckMergeOrRebase(err); err != nil { + if err := gui.helpers.MergeAndRebase.CheckMergeOrRebase(err); err != nil { return err } } @@ -265,7 +265,7 @@ func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesC gui.State.Contexts.CommitFiles.SetRefName(opts.RefName) gui.State.Contexts.CommitFiles.SetCanRebase(opts.CanRebase) gui.State.Contexts.CommitFiles.SetParentContext(opts.Context) - gui.State.Contexts.CommitFiles.SetWindowName(opts.WindowName) + gui.State.Contexts.CommitFiles.SetWindowName(opts.Context.GetWindowName()) if err := gui.refreshCommitFilesView(); err != nil { return err diff --git a/pkg/gui/context/branches_context.go b/pkg/gui/context/branches_context.go index 4b82844f4..146810a86 100644 --- a/pkg/gui/context/branches_context.go +++ b/pkg/gui/context/branches_context.go @@ -23,7 +23,7 @@ func NewBranchesContext( onRenderToMain func(...types.OnFocusOpts) error, onFocusLost func() error, - c *types.ControllerCommon, + c *types.HelperCommon, ) *BranchesContext { viewModel := NewBranchesViewModel(getModel) diff --git a/pkg/gui/context/commit_files_context.go b/pkg/gui/context/commit_files_context.go index 1c555387b..8f9bd91f7 100644 --- a/pkg/gui/context/commit_files_context.go +++ b/pkg/gui/context/commit_files_context.go @@ -23,7 +23,7 @@ func NewCommitFilesContext( onRenderToMain func(...types.OnFocusOpts) error, onFocusLost func() error, - c *types.ControllerCommon, + c *types.HelperCommon, ) *CommitFilesContext { viewModel := filetree.NewCommitFileTreeViewModel(getModel, c.Log, c.UserConfig.Gui.ShowFileTree) diff --git a/pkg/gui/context/list_context_trait.go b/pkg/gui/context/list_context_trait.go index b716bb25e..6deb5dfc1 100644 --- a/pkg/gui/context/list_context_trait.go +++ b/pkg/gui/context/list_context_trait.go @@ -10,7 +10,7 @@ import ( type ListContextTrait struct { types.Context - c *types.ControllerCommon + c *types.HelperCommon list types.IList viewTrait *ViewTrait getDisplayStrings func(startIdx int, length int) [][]string diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index 533d97cb2..9da4721e3 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -23,7 +23,7 @@ func NewLocalCommitsContext( onRenderToMain func(...types.OnFocusOpts) error, onFocusLost func() error, - c *types.ControllerCommon, + c *types.HelperCommon, ) *LocalCommitsContext { viewModel := NewLocalCommitsViewModel(getModel) @@ -61,8 +61,14 @@ func (self *LocalCommitsContext) GetSelectedItemId() string { type LocalCommitsViewModel struct { *traits.ListCursor + getModel func() []*models.Commit + + // If this is true we limit the amount of commits we load, for the sake of keeping things fast. + // If the user attempts to scroll past the end of the list, we will load more commits. limitCommits bool - getModel func() []*models.Commit + + // If this is true we'll use git log --all when fetching the commits. + showWholeGitGraph bool } func NewLocalCommitsViewModel(getModel func() []*models.Commit) *LocalCommitsViewModel { @@ -95,3 +101,11 @@ func (self *LocalCommitsViewModel) SetLimitCommits(value bool) { func (self *LocalCommitsViewModel) GetLimitCommits() bool { return self.limitCommits } + +func (self *LocalCommitsViewModel) SetShowWholeGitGraph(value bool) { + self.showWholeGitGraph = value +} + +func (self *LocalCommitsViewModel) GetShowWholeGitGraph() bool { + return self.showWholeGitGraph +} diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go index 47c6b885f..2e75ba25a 100644 --- a/pkg/gui/context/menu_context.go +++ b/pkg/gui/context/menu_context.go @@ -21,7 +21,7 @@ func NewMenuContext( onRenderToMain func(...types.OnFocusOpts) error, onFocusLost func() error, - c *types.ControllerCommon, + c *types.HelperCommon, getOptionsMap func() map[string]string, ) *MenuContext { viewModel := NewMenuViewModel() diff --git a/pkg/gui/context/reflog_commits_context.go b/pkg/gui/context/reflog_commits_context.go index e3130c251..4a53fe393 100644 --- a/pkg/gui/context/reflog_commits_context.go +++ b/pkg/gui/context/reflog_commits_context.go @@ -23,7 +23,7 @@ func NewReflogCommitsContext( onRenderToMain func(...types.OnFocusOpts) error, onFocusLost func() error, - c *types.ControllerCommon, + c *types.HelperCommon, ) *ReflogCommitsContext { viewModel := NewReflogCommitsViewModel(getModel) diff --git a/pkg/gui/context/remote_branches_context.go b/pkg/gui/context/remote_branches_context.go index 6ec5f887b..c851c96ac 100644 --- a/pkg/gui/context/remote_branches_context.go +++ b/pkg/gui/context/remote_branches_context.go @@ -23,7 +23,7 @@ func NewRemoteBranchesContext( onRenderToMain func(...types.OnFocusOpts) error, onFocusLost func() error, - c *types.ControllerCommon, + c *types.HelperCommon, ) *RemoteBranchesContext { viewModel := NewRemoteBranchesViewModel(getModel) diff --git a/pkg/gui/context/remotes_context.go b/pkg/gui/context/remotes_context.go index 28d0db20a..2b6afdeb5 100644 --- a/pkg/gui/context/remotes_context.go +++ b/pkg/gui/context/remotes_context.go @@ -23,7 +23,7 @@ func NewRemotesContext( onRenderToMain func(...types.OnFocusOpts) error, onFocusLost func() error, - c *types.ControllerCommon, + c *types.HelperCommon, ) *RemotesContext { viewModel := NewRemotesViewModel(getModel) diff --git a/pkg/gui/context/stash_context.go b/pkg/gui/context/stash_context.go index 9c22e7b06..95efeaef1 100644 --- a/pkg/gui/context/stash_context.go +++ b/pkg/gui/context/stash_context.go @@ -23,7 +23,7 @@ func NewStashContext( onRenderToMain func(...types.OnFocusOpts) error, onFocusLost func() error, - c *types.ControllerCommon, + c *types.HelperCommon, ) *StashContext { viewModel := NewStashViewModel(getModel) diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go index aed0e01a2..10c2cf41a 100644 --- a/pkg/gui/context/sub_commits_context.go +++ b/pkg/gui/context/sub_commits_context.go @@ -23,7 +23,7 @@ func NewSubCommitsContext( onRenderToMain func(...types.OnFocusOpts) error, onFocusLost func() error, - c *types.ControllerCommon, + c *types.HelperCommon, ) *SubCommitsContext { viewModel := NewSubCommitsViewModel(getModel) diff --git a/pkg/gui/context/submodules_context.go b/pkg/gui/context/submodules_context.go index c58755985..2bf5fe274 100644 --- a/pkg/gui/context/submodules_context.go +++ b/pkg/gui/context/submodules_context.go @@ -23,7 +23,7 @@ func NewSubmodulesContext( onRenderToMain func(...types.OnFocusOpts) error, onFocusLost func() error, - c *types.ControllerCommon, + c *types.HelperCommon, ) *SubmodulesContext { viewModel := NewSubmodulesViewModel(getModel) diff --git a/pkg/gui/context/suggestions_context.go b/pkg/gui/context/suggestions_context.go index 5320e40c6..6c565eedf 100644 --- a/pkg/gui/context/suggestions_context.go +++ b/pkg/gui/context/suggestions_context.go @@ -22,7 +22,7 @@ func NewSuggestionsContext( onRenderToMain func(...types.OnFocusOpts) error, onFocusLost func() error, - c *types.ControllerCommon, + c *types.HelperCommon, ) *SuggestionsContext { viewModel := NewSuggestionsViewModel(getModel) diff --git a/pkg/gui/context/tags_context.go b/pkg/gui/context/tags_context.go index 169a4989d..aa6211f40 100644 --- a/pkg/gui/context/tags_context.go +++ b/pkg/gui/context/tags_context.go @@ -23,7 +23,7 @@ func NewTagsContext( onRenderToMain func(...types.OnFocusOpts) error, onFocusLost func() error, - c *types.ControllerCommon, + c *types.HelperCommon, ) *TagsContext { viewModel := NewTagsViewModel(getModel) diff --git a/pkg/gui/context/working_tree_context.go b/pkg/gui/context/working_tree_context.go index c1021ba23..ae647afb3 100644 --- a/pkg/gui/context/working_tree_context.go +++ b/pkg/gui/context/working_tree_context.go @@ -23,7 +23,7 @@ func NewWorkingTreeContext( onRenderToMain func(...types.OnFocusOpts) error, onFocusLost func() error, - c *types.ControllerCommon, + c *types.HelperCommon, ) *WorkingTreeContext { viewModel := filetree.NewFileTreeViewModel(getModel, c.Log, c.UserConfig.Gui.ShowFileTree) diff --git a/pkg/gui/controllers/bisect_controller.go b/pkg/gui/controllers/bisect_controller.go index 99ae9c2df..addcd8d80 100644 --- a/pkg/gui/controllers/bisect_controller.go +++ b/pkg/gui/controllers/bisect_controller.go @@ -4,7 +4,6 @@ import ( "fmt" "strings" - "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" @@ -13,33 +12,17 @@ import ( type BisectController struct { baseController - - c *types.ControllerCommon - context *context.LocalCommitsContext - git *commands.GitCommand - bisectHelper *BisectHelper - - getCommits func() []*models.Commit + *controllerCommon } var _ types.IController = &BisectController{} func NewBisectController( - c *types.ControllerCommon, - context *context.LocalCommitsContext, - git *commands.GitCommand, - bisectHelper *BisectHelper, - - getCommits func() []*models.Commit, + common *controllerCommon, ) *BisectController { return &BisectController{ - baseController: baseController{}, - c: c, - context: context, - git: git, - bisectHelper: bisectHelper, - - getCommits: getCommits, + baseController: baseController{}, + controllerCommon: common, } } @@ -119,7 +102,7 @@ func (self *BisectController) openMidBisectMenu(info *git_commands.BisectInfo, c { DisplayString: self.c.Tr.Bisect.ResetOption, OnPress: func() error { - return self.bisectHelper.Reset() + return self.helpers.Bisect.Reset() }, }, } @@ -146,7 +129,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo, return self.c.Error(err) } - return self.bisectHelper.PostBisectCommandRefresh() + return self.helpers.Bisect.PostBisectCommandRefresh() }, }, { @@ -161,7 +144,7 @@ func (self *BisectController) openStartBisectMenu(info *git_commands.BisectInfo, return self.c.Error(err) } - return self.bisectHelper.PostBisectCommandRefresh() + return self.helpers.Bisect.PostBisectCommandRefresh() }, }, }, @@ -188,7 +171,7 @@ func (self *BisectController) showBisectCompleteMessage(candidateShas []string) return self.c.Error(err) } - return self.bisectHelper.PostBisectCommandRefresh() + return self.helpers.Bisect.PostBisectCommandRefresh() }, }) } @@ -222,7 +205,7 @@ func (self *BisectController) afterBisectMarkRefresh(selectCurrent bool, waitToR } else { selectFn() - return self.bisectHelper.PostBisectCommandRefresh() + return self.helpers.Bisect.PostBisectCommandRefresh() } } @@ -230,10 +213,10 @@ func (self *BisectController) selectCurrentBisectCommit() { info := self.git.Bisect.GetInfo() if info.GetCurrentSha() != "" { // find index of commit with that sha, move cursor to that. - for i, commit := range self.getCommits() { + for i, commit := range self.model.Commits { if commit.Sha == info.GetCurrentSha() { - self.context.SetSelectedLineIdx(i) - _ = self.context.HandleFocus() + self.context().SetSelectedLineIdx(i) + _ = self.context().HandleFocus() break } } @@ -242,7 +225,7 @@ func (self *BisectController) selectCurrentBisectCommit() { func (self *BisectController) checkSelected(callback func(*models.Commit) error) func() error { return func() error { - commit := self.context.GetSelected() + commit := self.context().GetSelected() if commit == nil { return nil } @@ -252,5 +235,9 @@ func (self *BisectController) checkSelected(callback func(*models.Commit) error) } func (self *BisectController) Context() types.Context { - return self.context + return self.context() +} + +func (self *BisectController) context() *context.LocalCommitsContext { + return self.contexts.BranchCommits } diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go new file mode 100644 index 000000000..ff5989656 --- /dev/null +++ b/pkg/gui/controllers/branches_controller.go @@ -0,0 +1,475 @@ +package controllers + +import ( + "errors" + "fmt" + "strings" + + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +type BranchesController struct { + baseController + *controllerCommon +} + +var _ types.IController = &BranchesController{} + +func NewBranchesController( + common *controllerCommon, +) *BranchesController { + return &BranchesController{ + baseController: baseController{}, + controllerCommon: common, + } +} + +func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + return []*types.Binding{ + { + ViewName: "branches", + Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, + Key: opts.GetKey(opts.Config.Universal.Select), + Handler: self.handleBranchPress, + Description: self.c.Tr.LcCheckout, + }, + { + ViewName: "branches", + Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, + Key: opts.GetKey(opts.Config.Branches.CreatePullRequest), + Handler: self.handleCreatePullRequestPress, + Description: self.c.Tr.LcCreatePullRequest, + }, + { + ViewName: "branches", + Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, + Key: opts.GetKey(opts.Config.Branches.ViewPullRequestOptions), + Handler: self.checkSelected(self.handleCreatePullRequestMenu), + Description: self.c.Tr.LcCreatePullRequestOptions, + OpensMenu: true, + }, + { + ViewName: "branches", + Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, + Key: opts.GetKey(opts.Config.Branches.CopyPullRequestURL), + Handler: self.handleCopyPullRequestURLPress, + Description: self.c.Tr.LcCopyPullRequestURL, + }, + { + ViewName: "branches", + Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, + Key: opts.GetKey(opts.Config.Branches.CheckoutBranchByName), + Handler: self.handleCheckoutByName, + Description: self.c.Tr.LcCheckoutByName, + }, + { + ViewName: "branches", + Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, + Key: opts.GetKey(opts.Config.Branches.ForceCheckoutBranch), + Handler: self.handleForceCheckout, + Description: self.c.Tr.LcForceCheckout, + }, + { + ViewName: "branches", + Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, + Key: opts.GetKey(opts.Config.Universal.New), + Handler: self.checkSelected(self.handleNewBranchOffBranch), + Description: self.c.Tr.LcNewBranch, + }, + { + ViewName: "branches", + Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, + Key: opts.GetKey(opts.Config.Universal.Remove), + Handler: self.checkSelectedAndReal(self.handleDeleteBranch), + Description: self.c.Tr.LcDeleteBranch, + }, + { + ViewName: "branches", + Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, + Key: opts.GetKey(opts.Config.Branches.RebaseBranch), + Handler: opts.Guards.OutsideFilterMode(self.handleRebaseOntoLocalBranch), + Description: self.c.Tr.LcRebaseBranch, + }, + { + ViewName: "branches", + Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, + Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch), + Handler: opts.Guards.OutsideFilterMode(self.handleMerge), + Description: self.c.Tr.LcMergeIntoCurrentBranch, + }, + { + ViewName: "branches", + Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, + Key: opts.GetKey(opts.Config.Branches.FastForward), + Handler: self.checkSelectedAndReal(self.handleFastForward), + Description: self.c.Tr.FastForward, + }, + { + ViewName: "branches", + Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, + Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), + Handler: self.checkSelected(self.handleCreateResetToBranchMenu), + Description: self.c.Tr.LcViewResetOptions, + OpensMenu: true, + }, + { + ViewName: "branches", + Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, + Key: opts.GetKey(opts.Config.Branches.RenameBranch), + Handler: self.checkSelectedAndReal(self.handleRenameBranch), + Description: self.c.Tr.LcRenameBranch, + }, + } +} + +func (self *BranchesController) Context() types.Context { + return self.context() +} + +func (self *BranchesController) context() *context.BranchesContext { + return self.contexts.Branches +} + +func (self *BranchesController) handleBranchPress() error { + branch := self.context().GetSelected() + if branch == nil { + return nil + } + + if branch == self.helpers.Refs.GetCheckedOutRef() { + return self.c.ErrorMsg(self.c.Tr.AlreadyCheckedOutBranch) + } + + self.c.LogAction(self.c.Tr.Actions.CheckoutBranch) + return self.helpers.Refs.CheckoutRef(branch.Name, types.CheckoutRefOptions{}) +} + +func (self *BranchesController) handleCreatePullRequestPress() error { + branch := self.context().GetSelected() + return self.createPullRequest(branch.Name, "") +} + +func (self *BranchesController) handleCreatePullRequestMenu(selectedBranch *models.Branch) error { + checkedOutBranch := self.helpers.Refs.GetCheckedOutRef() + + return self.createPullRequestMenu(selectedBranch, checkedOutBranch) +} + +func (self *BranchesController) handleCopyPullRequestURLPress() error { + branch := self.context().GetSelected() + + branchExistsOnRemote := self.git.Remote.CheckRemoteBranchExists(branch.Name) + + if !branchExistsOnRemote { + return self.c.Error(errors.New(self.c.Tr.NoBranchOnRemote)) + } + + url, err := self.helpers.Host.GetPullRequestURL(branch.Name, "") + if err != nil { + return self.c.Error(err) + } + self.c.LogAction(self.c.Tr.Actions.CopyPullRequestURL) + if err := self.os.CopyToClipboard(url); err != nil { + return self.c.Error(err) + } + + self.c.Toast(self.c.Tr.PullRequestURLCopiedToClipboard) + + return nil +} + +func (self *BranchesController) handleForceCheckout() error { + branch := self.context().GetSelected() + message := self.c.Tr.SureForceCheckout + title := self.c.Tr.ForceCheckoutBranch + + return self.c.Ask(types.AskOpts{ + Title: title, + Prompt: message, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.ForceCheckoutBranch) + if err := self.git.Branch.Checkout(branch.Name, git_commands.CheckoutOptions{Force: true}); err != nil { + _ = self.c.Error(err) + } + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + }, + }) +} + +func (self *BranchesController) handleCheckoutByName() error { + return self.c.Prompt(types.PromptOpts{ + Title: self.c.Tr.BranchName + ":", + FindSuggestionsFunc: self.helpers.Suggestions.GetRefsSuggestionsFunc(), + HandleConfirm: func(response string) error { + self.c.LogAction("Checkout branch") + return self.helpers.Refs.CheckoutRef(response, types.CheckoutRefOptions{ + OnRefNotFound: func(ref string) error { + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.BranchNotFoundTitle, + Prompt: fmt.Sprintf("%s %s%s", self.c.Tr.BranchNotFoundPrompt, ref, "?"), + HandleConfirm: func() error { + return self.createNewBranchWithName(ref) + }, + }) + }, + }) + }}, + ) +} + +func (self *BranchesController) createNewBranchWithName(newBranchName string) error { + branch := self.context().GetSelected() + if branch == nil { + return nil + } + + if err := self.git.Branch.New(newBranchName, branch.Name); err != nil { + return self.c.Error(err) + } + + self.context().SetSelectedLineIdx(0) + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) +} + +func (self *BranchesController) handleDeleteBranch(branch *models.Branch) error { + return self.deleteBranch(branch, false) +} + +func (self *BranchesController) deleteBranch(branch *models.Branch, force bool) error { + checkedOutBranch := self.helpers.Refs.GetCheckedOutRef() + if checkedOutBranch.Name == branch.Name { + return self.c.ErrorMsg(self.c.Tr.CantDeleteCheckOutBranch) + } + return self.deleteNamedBranch(branch, force) +} + +func (self *BranchesController) deleteNamedBranch(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 + } + message := utils.ResolvePlaceholderString( + templateStr, + map[string]string{ + "selectedBranchName": selectedBranch.Name, + }, + ) + + return self.c.Ask(types.AskOpts{ + Title: title, + Prompt: message, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.DeleteBranch) + if err := self.git.Branch.Delete(selectedBranch.Name, force); err != nil { + errMessage := err.Error() + if !force && strings.Contains(errMessage, "git branch -D ") { + return self.deleteNamedBranch(selectedBranch, true) + } + return self.c.ErrorMsg(errMessage) + } + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) + }, + }) +} + +func (self *BranchesController) handleMerge() error { + selectedBranchName := self.context().GetSelected().Name + return self.helpers.MergeAndRebase.MergeRefIntoCheckedOutBranch(selectedBranchName) +} + +func (self *BranchesController) handleRebaseOntoLocalBranch() error { + selectedBranchName := self.context().GetSelected().Name + return self.helpers.MergeAndRebase.RebaseOntoRef(selectedBranchName) +} + +func (self *BranchesController) handleFastForward(branch *models.Branch) error { + if !branch.IsTrackingRemote() { + return self.c.ErrorMsg(self.c.Tr.FwdNoUpstream) + } + if !branch.RemoteBranchStoredLocally() { + return self.c.ErrorMsg(self.c.Tr.FwdNoLocalUpstream) + } + if branch.HasCommitsToPush() { + return self.c.ErrorMsg(self.c.Tr.FwdCommitsToPush) + } + + action := self.c.Tr.Actions.FastForwardBranch + + message := utils.ResolvePlaceholderString( + self.c.Tr.Fetching, + map[string]string{ + "from": fmt.Sprintf("%s/%s", branch.UpstreamRemote, branch.UpstreamBranch), + "to": branch.Name, + }, + ) + + return self.c.WithLoaderPanel(message, func() error { + if branch == self.helpers.Refs.GetCheckedOutRef() { + self.c.LogAction(action) + + err := self.git.Sync.Pull( + git_commands.PullOptions{ + RemoteName: branch.UpstreamRemote, + BranchName: branch.Name, + FastForwardOnly: true, + }, + ) + if err != nil { + _ = self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + } else { + self.c.LogAction(action) + err := self.git.Sync.FastForward(branch.Name, branch.UpstreamRemote, branch.UpstreamBranch) + if err != nil { + _ = self.c.Error(err) + } + _ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) + } + + return nil + }) +} + +func (self *BranchesController) handleCreateResetToBranchMenu(selectedBranch *models.Branch) error { + return self.helpers.Refs.CreateGitResetMenu(selectedBranch.Name) +} + +func (self *BranchesController) handleRenameBranch(branch *models.Branch) error { + promptForNewName := func() error { + return self.c.Prompt(types.PromptOpts{ + Title: self.c.Tr.NewBranchNamePrompt + " " + branch.Name + ":", + InitialContent: branch.Name, + HandleConfirm: func(newBranchName string) error { + self.c.LogAction(self.c.Tr.Actions.RenameBranch) + if err := self.git.Branch.Rename(branch.Name, newBranchName); err != nil { + return self.c.Error(err) + } + + // need to find where the branch is now so that we can re-select it. That means we need to refetch the branches synchronously and then find our branch + _ = self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.BRANCHES}}) + + // now that we've got our stuff again we need to find that branch and reselect it. + for i, newBranch := range self.model.Branches { + if newBranch.Name == newBranchName { + self.context().SetSelectedLineIdx(i) + if err := self.context().HandleRender(); err != nil { + return err + } + } + } + + return nil + }, + }) + } + + // I could do an explicit check here for whether the branch is tracking a remote branch + // but if we've selected it we'll already know that via Pullables and Pullables. + // Bit of a hack but I'm lazy. + if !branch.IsTrackingRemote() { + return promptForNewName() + } + + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.LcRenameBranch, + Prompt: self.c.Tr.RenameBranchWarning, + HandleConfirm: promptForNewName, + }) +} + +func (self *BranchesController) handleNewBranchOffBranch(selectedBranch *models.Branch) error { + return self.helpers.Refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), "") +} + +func (self *BranchesController) createPullRequestMenu(selectedBranch *models.Branch, checkedOutBranch *models.Branch) error { + menuItems := make([]*types.MenuItem, 0, 4) + + fromToDisplayStrings := func(from string, to string) []string { + return []string{fmt.Sprintf("%s 鈫 %s", from, to)} + } + + menuItemsForBranch := func(branch *models.Branch) []*types.MenuItem { + return []*types.MenuItem{ + { + DisplayStrings: fromToDisplayStrings(branch.Name, self.c.Tr.LcDefaultBranch), + OnPress: func() error { + return self.createPullRequest(branch.Name, "") + }, + }, + { + DisplayStrings: fromToDisplayStrings(branch.Name, self.c.Tr.LcSelectBranch), + OnPress: func() error { + return self.c.Prompt(types.PromptOpts{ + Title: branch.Name + " 鈫", + FindSuggestionsFunc: self.helpers.Suggestions.GetBranchNameSuggestionsFunc(), + HandleConfirm: func(targetBranchName string) error { + return self.createPullRequest(branch.Name, targetBranchName) + }}, + ) + }, + }, + } + } + + if selectedBranch != checkedOutBranch { + menuItems = append(menuItems, + &types.MenuItem{ + DisplayStrings: fromToDisplayStrings(checkedOutBranch.Name, selectedBranch.Name), + OnPress: func() error { + return self.createPullRequest(checkedOutBranch.Name, selectedBranch.Name) + }, + }, + ) + menuItems = append(menuItems, menuItemsForBranch(checkedOutBranch)...) + } + + menuItems = append(menuItems, menuItemsForBranch(selectedBranch)...) + + return self.c.Menu(types.CreateMenuOptions{Title: fmt.Sprintf(self.c.Tr.CreatePullRequestOptions), Items: menuItems}) +} + +func (self *BranchesController) createPullRequest(from string, to string) error { + url, err := self.helpers.Host.GetPullRequestURL(from, to) + if err != nil { + return self.c.Error(err) + } + + self.c.LogAction(self.c.Tr.Actions.OpenPullRequest) + + if err := self.os.OpenLink(url); err != nil { + return self.c.Error(err) + } + + return nil +} + +func (self *BranchesController) checkSelected(callback func(*models.Branch) error) func() error { + return func() error { + selectedItem := self.context().GetSelected() + if selectedItem == nil { + return nil + } + + return callback(selectedItem) + } +} + +func (self *BranchesController) checkSelectedAndReal(callback func(*models.Branch) error) func() error { + return func() error { + selectedItem := self.context().GetSelected() + if selectedItem == nil || !selectedItem.IsRealBranch() { + return nil + } + + return callback(selectedItem) + } +} diff --git a/pkg/gui/controllers/common.go b/pkg/gui/controllers/common.go new file mode 100644 index 000000000..55ba4b176 --- /dev/null +++ b/pkg/gui/controllers/common.go @@ -0,0 +1,39 @@ +package controllers + +import ( + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type controllerCommon struct { + c *types.HelperCommon + os *oscommands.OSCommand + git *commands.GitCommand + helpers *helpers.Helpers + model *types.Model + contexts *context.ContextTree + modes *types.Modes +} + +func NewControllerCommon( + c *types.HelperCommon, + os *oscommands.OSCommand, + git *commands.GitCommand, + helpers *helpers.Helpers, + model *types.Model, + contexts *context.ContextTree, + modes *types.Modes, +) *controllerCommon { + return &controllerCommon{ + c: c, + os: os, + git: git, + helpers: helpers, + model: model, + contexts: contexts, + modes: modes, + } +} diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index de085607d..6868586e6 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/config" @@ -17,73 +17,33 @@ import ( ) type FilesController struct { - // I've said publicly that I'm against single-letter variable names but in this - // case I would actually prefer a _zero_ letter variable name in the form of - // struct embedding, but Go does not allow hiding public fields in an embedded struct - // to the client - c *types.ControllerCommon - context *context.WorkingTreeContext - model *types.Model - git *commands.GitCommand - os *oscommands.OSCommand + baseController + *controllerCommon - getSelectedFileNode func() *filetree.FileNode - contexts *context.ContextTree enterSubmodule func(submodule *models.SubmoduleConfig) error - getSubmodules func() []*models.SubmoduleConfig setCommitMessage func(message string) - getCheckedOutBranch func() *models.Branch withGpgHandling func(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error getFailedCommitMessage func() string - getSelectedPath func() string switchToMergeFn func(path string) error - suggestionsHelper ISuggestionsHelper - refsHelper IRefsHelper - filesHelper IFilesHelper - workingTreeHelper IWorkingTreeHelper } var _ types.IController = &FilesController{} func NewFilesController( - c *types.ControllerCommon, - context *context.WorkingTreeContext, - model *types.Model, - git *commands.GitCommand, - os *oscommands.OSCommand, - getSelectedFileNode func() *filetree.FileNode, - allContexts *context.ContextTree, + common *controllerCommon, enterSubmodule func(submodule *models.SubmoduleConfig) error, - getSubmodules func() []*models.SubmoduleConfig, setCommitMessage func(message string), withGpgHandling func(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error, getFailedCommitMessage func() string, - getSelectedPath func() string, switchToMergeFn func(path string) error, - suggestionsHelper ISuggestionsHelper, - refsHelper IRefsHelper, - filesHelper IFilesHelper, - workingTreeHelper IWorkingTreeHelper, ) *FilesController { return &FilesController{ - c: c, - context: context, - model: model, - git: git, - os: os, - getSelectedFileNode: getSelectedFileNode, - contexts: allContexts, + controllerCommon: common, enterSubmodule: enterSubmodule, - getSubmodules: getSubmodules, setCommitMessage: setCommitMessage, withGpgHandling: withGpgHandling, getFailedCommitMessage: getFailedCommitMessage, - getSelectedPath: getSelectedPath, switchToMergeFn: switchToMergeFn, - suggestionsHelper: suggestionsHelper, - refsHelper: refsHelper, - filesHelper: filesHelper, - workingTreeHelper: workingTreeHelper, } } @@ -96,7 +56,7 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types }, // { // Key: gocui.MouseLeft, - // Handler: func() error { return self.context.HandleClick(self.checkSelectedFileNode(self.press)) }, + // Handler: func() error { return self.context().HandleClick(self.checkSelectedFileNode(self.press)) }, // }, { Key: opts.GetKey(" "), // TODO: softcode @@ -187,6 +147,11 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types Handler: self.OpenMergeTool, Description: self.c.Tr.LcOpenMergeTool, }, + { + Key: opts.GetKey(opts.Config.Files.Fetch), + Handler: self.fetch, + Description: self.c.Tr.LcFetch, + }, } } @@ -249,12 +214,12 @@ func (self *FilesController) press(node *filetree.FileNode) error { return err } - return self.context.HandleFocus() + return self.context().HandleFocus() } func (self *FilesController) checkSelectedFileNode(callback func(*filetree.FileNode) error) func() error { return func() error { - node := self.getSelectedFileNode() + node := self.context().GetSelectedFileNode() if node == nil { return nil } @@ -264,11 +229,15 @@ func (self *FilesController) checkSelectedFileNode(callback func(*filetree.FileN } func (self *FilesController) Context() types.Context { - return self.context + return self.context() +} + +func (self *FilesController) context() *context.WorkingTreeContext { + return self.contexts.Files } func (self *FilesController) getSelectedFile() *models.File { - node := self.getSelectedFileNode() + node := self.context().GetSelectedFileNode() if node == nil { return nil } @@ -280,7 +249,7 @@ func (self *FilesController) enter() error { } func (self *FilesController) EnterFile(opts types.OnFocusOpts) error { - node := self.getSelectedFileNode() + node := self.context().GetSelectedFileNode() if node == nil { return nil } @@ -291,7 +260,7 @@ func (self *FilesController) EnterFile(opts types.OnFocusOpts) error { file := node.File - submoduleConfigs := self.getSubmodules() + submoduleConfigs := self.model.Submodules if file.IsSubmodule(submoduleConfigs) { submoduleConfig := file.SubmoduleConfig(submoduleConfigs) return self.enterSubmodule(submoduleConfig) @@ -410,7 +379,7 @@ func (self *FilesController) commitPrefixConfigForRepo() *config.CommitPrefixCon } func (self *FilesController) prepareFilesForCommit() error { - noStagedFiles := !self.workingTreeHelper.AnyStagedFiles() + noStagedFiles := !self.helpers.WorkingTree.AnyStagedFiles() if noStagedFiles && self.c.UserConfig.Gui.SkipNoStagedFilesWarning { self.c.LogAction(self.c.Tr.Actions.StageAllFiles) err := self.git.WorkingTree.StageAll() @@ -442,7 +411,7 @@ func (self *FilesController) HandleCommitPress() error { return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle) } - if !self.workingTreeHelper.AnyStagedFiles() { + if !self.helpers.WorkingTree.AnyStagedFiles() { return self.promptToStageAllAndRetry(self.HandleCommitPress) } @@ -458,7 +427,7 @@ func (self *FilesController) HandleCommitPress() error { if err != nil { return self.c.ErrorMsg(fmt.Sprintf("%s: %s", self.c.Tr.LcCommitPrefixPatternError, err.Error())) } - prefix := rgx.ReplaceAllString(self.getCheckedOutBranch().Name, prefixReplace) + prefix := rgx.ReplaceAllString(self.helpers.Refs.GetCheckedOutRef().Name, prefixReplace) self.setCommitMessage(prefix) } } @@ -493,7 +462,7 @@ func (self *FilesController) handleAmendCommitPress() error { return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle) } - if !self.workingTreeHelper.AnyStagedFiles() { + if !self.helpers.WorkingTree.AnyStagedFiles() { return self.promptToStageAllAndRetry(self.handleAmendCommitPress) } @@ -519,7 +488,7 @@ func (self *FilesController) HandleCommitEditorPress() error { return self.c.ErrorMsg(self.c.Tr.NoFilesStagedTitle) } - if !self.workingTreeHelper.AnyStagedFiles() { + if !self.helpers.WorkingTree.AnyStagedFiles() { return self.promptToStageAllAndRetry(self.HandleCommitEditorPress) } @@ -556,8 +525,8 @@ func (self *FilesController) handleStatusFilterPressed() error { } func (self *FilesController) setStatusFiltering(filter filetree.FileTreeDisplayFilter) error { - self.context.FileTreeViewModel.SetFilter(filter) - return self.c.PostRefreshUpdate(self.context) + self.context().FileTreeViewModel.SetFilter(filter) + return self.c.PostRefreshUpdate(self.context()) } func (self *FilesController) edit(node *filetree.FileNode) error { @@ -565,16 +534,16 @@ func (self *FilesController) edit(node *filetree.FileNode) error { return self.c.ErrorMsg(self.c.Tr.ErrCannotEditDirectory) } - return self.filesHelper.EditFile(node.GetPath()) + return self.helpers.Files.EditFile(node.GetPath()) } func (self *FilesController) Open() error { - node := self.getSelectedFileNode() + node := self.context().GetSelectedFileNode() if node == nil { return nil } - return self.filesHelper.OpenFile(node.GetPath()) + return self.helpers.Files.OpenFile(node.GetPath()) } func (self *FilesController) switchToMerge() error { @@ -613,16 +582,16 @@ func (self *FilesController) stash() error { } func (self *FilesController) createResetMenu() error { - return self.refsHelper.CreateGitResetMenu("@{upstream}") + return self.helpers.Refs.CreateGitResetMenu("@{upstream}") } func (self *FilesController) handleToggleDirCollapsed() error { - node := self.getSelectedFileNode() + node := self.context().GetSelectedFileNode() if node == nil { return nil } - self.context.FileTreeViewModel.ToggleCollapsed(node.GetPath()) + self.context().FileTreeViewModel.ToggleCollapsed(node.GetPath()) if err := self.c.PostRefreshUpdate(self.contexts.Files); err != nil { self.c.Log.Error(err) @@ -632,9 +601,9 @@ func (self *FilesController) handleToggleDirCollapsed() error { } func (self *FilesController) toggleTreeView() error { - self.context.FileTreeViewModel.ToggleShowTree() + self.context().FileTreeViewModel.ToggleShowTree() - return self.c.PostRefreshUpdate(self.context) + return self.c.PostRefreshUpdate(self.context()) } func (self *FilesController) OpenMergeTool() error { @@ -654,7 +623,7 @@ func (self *FilesController) ResetSubmodule(submodule *models.SubmoduleConfig) e return self.c.WithWaitingStatus(self.c.Tr.LcResettingSubmoduleStatus, func() error { self.c.LogAction(self.c.Tr.Actions.ResetSubmodule) - file := self.workingTreeHelper.FileForSubmodule(submodule) + file := self.helpers.WorkingTree.FileForSubmodule(submodule) if file != nil { if err := self.git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil { return self.c.Error(err) @@ -673,7 +642,7 @@ func (self *FilesController) ResetSubmodule(submodule *models.SubmoduleConfig) e } func (self *FilesController) handleStashSave(stashFunc func(message string) error) error { - if !self.workingTreeHelper.IsWorkingTreeDirty() { + if !self.helpers.WorkingTree.IsWorkingTreeDirty() { return self.c.ErrorMsg(self.c.Tr.NoTrackedStagedFilesStash) } @@ -697,3 +666,25 @@ func (self *FilesController) onClickSecondary(opts gocui.ViewMouseBindingOpts) e clickedViewLineIdx := opts.Cy + opts.Oy return self.EnterFile(types.OnFocusOpts{ClickedViewName: "secondary", ClickedViewLineIdx: clickedViewLineIdx}) } + +func (self *FilesController) fetch() error { + return self.c.WithLoaderPanel(self.c.Tr.FetchWait, func() error { + if err := self.fetchAux(); err != nil { + _ = self.c.Error(err) + } + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + }) +} + +func (self *FilesController) fetchAux() (err error) { + self.c.LogAction("Fetch") + err = self.git.Sync.Fetch(git_commands.FetchOptions{}) + + if err != nil && strings.Contains(err.Error(), "exit status 128") { + _ = self.c.ErrorMsg(self.c.Tr.PassUnameWrong) + } + + _ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.ASYNC}) + + return err +} diff --git a/pkg/gui/controllers/files_controller_remove.go b/pkg/gui/controllers/files_controller_remove.go index 42d1df8b0..cdebf8914 100644 --- a/pkg/gui/controllers/files_controller_remove.go +++ b/pkg/gui/controllers/files_controller_remove.go @@ -39,7 +39,7 @@ func (self *FilesController) remove(node *filetree.FileNode) error { } else { file := node.File - submodules := self.getSubmodules() + submodules := self.model.Submodules if file.IsSubmodule(submodules) { submodule := file.SubmoduleConfig(submodules) diff --git a/pkg/gui/controllers/global_controller.go b/pkg/gui/controllers/global_controller.go index dd0c8ea3b..487c1e10b 100644 --- a/pkg/gui/controllers/global_controller.go +++ b/pkg/gui/controllers/global_controller.go @@ -1,26 +1,22 @@ package controllers import ( - "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) type GlobalController struct { baseController - - c *types.ControllerCommon - os *oscommands.OSCommand + *controllerCommon } func NewGlobalController( - c *types.ControllerCommon, - os *oscommands.OSCommand, + common *controllerCommon, ) *GlobalController { return &GlobalController{ - baseController: baseController{}, - c: c, - os: os, + baseController: baseController{}, + controllerCommon: common, } } @@ -63,7 +59,7 @@ func (self *GlobalController) GetCustomCommandsHistorySuggestionsFunc() func(str // reversing so that we display the latest command first history := utils.Reverse(self.c.GetAppState().CustomCommandsHistory) - return FuzzySearchFunc(history) + return helpers.FuzzySearchFunc(history) } func (self *GlobalController) Context() types.Context { diff --git a/pkg/gui/controllers/bisect_helper.go b/pkg/gui/controllers/helpers/bisect_helper.go similarity index 91% rename from pkg/gui/controllers/bisect_helper.go rename to pkg/gui/controllers/helpers/bisect_helper.go index 357407fb6..401d01b0c 100644 --- a/pkg/gui/controllers/bisect_helper.go +++ b/pkg/gui/controllers/helpers/bisect_helper.go @@ -1,4 +1,4 @@ -package controllers +package helpers import ( "github.com/jesseduffield/lazygit/pkg/commands" @@ -6,12 +6,12 @@ import ( ) type BisectHelper struct { - c *types.ControllerCommon + c *types.HelperCommon git *commands.GitCommand } func NewBisectHelper( - c *types.ControllerCommon, + c *types.HelperCommon, git *commands.GitCommand, ) *BisectHelper { return &BisectHelper{ diff --git a/pkg/gui/controllers/cherry_pick_helper.go b/pkg/gui/controllers/helpers/cherry_pick_helper.go similarity index 96% rename from pkg/gui/controllers/cherry_pick_helper.go rename to pkg/gui/controllers/helpers/cherry_pick_helper.go index 1f6665224..a0fd4ebca 100644 --- a/pkg/gui/controllers/cherry_pick_helper.go +++ b/pkg/gui/controllers/helpers/cherry_pick_helper.go @@ -1,4 +1,4 @@ -package controllers +package helpers import ( "github.com/jesseduffield/lazygit/pkg/commands" @@ -9,25 +9,25 @@ import ( ) type CherryPickHelper struct { - c *types.ControllerCommon + c *types.HelperCommon git *commands.GitCommand contexts *context.ContextTree getData func() *cherrypicking.CherryPicking - rebaseHelper *RebaseHelper + rebaseHelper *MergeAndRebaseHelper } // I'm using the analogy of copy+paste in the terminology here because it's intuitively what's going on, // even if in truth we're running git cherry-pick func NewCherryPickHelper( - c *types.ControllerCommon, + c *types.HelperCommon, git *commands.GitCommand, contexts *context.ContextTree, getData func() *cherrypicking.CherryPicking, - rebaseHelper *RebaseHelper, + rebaseHelper *MergeAndRebaseHelper, ) *CherryPickHelper { return &CherryPickHelper{ c: c, diff --git a/pkg/gui/controllers/files_helper.go b/pkg/gui/controllers/helpers/files_helper.go similarity index 94% rename from pkg/gui/controllers/files_helper.go rename to pkg/gui/controllers/helpers/files_helper.go index 35f388183..72be6e4e5 100644 --- a/pkg/gui/controllers/files_helper.go +++ b/pkg/gui/controllers/helpers/files_helper.go @@ -1,4 +1,4 @@ -package controllers +package helpers import ( "github.com/jesseduffield/lazygit/pkg/commands" @@ -14,13 +14,13 @@ type IFilesHelper interface { } type FilesHelper struct { - c *types.ControllerCommon + c *types.HelperCommon git *commands.GitCommand os *oscommands.OSCommand } func NewFilesHelper( - c *types.ControllerCommon, + c *types.HelperCommon, git *commands.GitCommand, os *oscommands.OSCommand, ) *FilesHelper { diff --git a/pkg/gui/controllers/helpers/helpers.go b/pkg/gui/controllers/helpers/helpers.go new file mode 100644 index 000000000..65f686ade --- /dev/null +++ b/pkg/gui/controllers/helpers/helpers.go @@ -0,0 +1,13 @@ +package helpers + +type Helpers struct { + Refs *RefsHelper + Bisect *BisectHelper + Suggestions *SuggestionsHelper + Files *FilesHelper + WorkingTree *WorkingTreeHelper + Tags *TagsHelper + MergeAndRebase *MergeAndRebaseHelper + CherryPick *CherryPickHelper + Host *HostHelper +} diff --git a/pkg/gui/controllers/helpers/host_helper.go b/pkg/gui/controllers/helpers/host_helper.go new file mode 100644 index 000000000..edc0bc7ba --- /dev/null +++ b/pkg/gui/controllers/helpers/host_helper.go @@ -0,0 +1,46 @@ +package helpers + +import ( + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/hosting_service" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +// this helper just wraps our hosting_service package + +type IHostHelper interface { + GetPullRequestURL(from string, to string) (string, error) + GetCommitURL(commitSha string) (string, error) +} + +type HostHelper struct { + c *types.HelperCommon + git *commands.GitCommand +} + +func NewHostHelper( + c *types.HelperCommon, + git *commands.GitCommand, +) *HostHelper { + return &HostHelper{ + c: c, + git: git, + } +} + +func (self *HostHelper) GetPullRequestURL(from string, to string) (string, error) { + return self.getHostingServiceMgr().GetPullRequestURL(from, to) +} + +func (self *HostHelper) GetCommitURL(commitSha string) (string, error) { + return self.getHostingServiceMgr().GetCommitURL(commitSha) +} + +// getting this on every request rather than storing it in state in case our remoteURL changes +// from one invocation to the next. Note however that we're currently caching config +// results so we might want to invalidate the cache here if it becomes a problem. +func (self *HostHelper) getHostingServiceMgr() *hosting_service.HostingServiceMgr { + remoteUrl := self.git.Config.GetRemoteURL() + configServices := self.c.UserConfig.Services + return hosting_service.NewHostingServiceMgr(self.c.Log, self.c.Tr, remoteUrl, configServices) +} diff --git a/pkg/gui/controllers/rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go similarity index 67% rename from pkg/gui/controllers/rebase_helper.go rename to pkg/gui/controllers/helpers/merge_and_rebase_helper.go index 036af31e0..477c5c64f 100644 --- a/pkg/gui/controllers/rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -1,33 +1,38 @@ -package controllers +package helpers import ( "fmt" "strings" "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" ) -type RebaseHelper struct { - c *types.ControllerCommon +type MergeAndRebaseHelper struct { + c *types.HelperCommon contexts *context.ContextTree git *commands.GitCommand takeOverMergeConflictScrolling func() + refsHelper *RefsHelper } -func NewRebaseHelper( - c *types.ControllerCommon, +func NewMergeAndRebaseHelper( + c *types.HelperCommon, contexts *context.ContextTree, git *commands.GitCommand, takeOverMergeConflictScrolling func(), -) *RebaseHelper { - return &RebaseHelper{ + refsHelper *RefsHelper, +) *MergeAndRebaseHelper { + return &MergeAndRebaseHelper{ c: c, contexts: contexts, git: git, takeOverMergeConflictScrolling: takeOverMergeConflictScrolling, + refsHelper: refsHelper, } } @@ -39,7 +44,7 @@ const ( REBASE_OPTION_SKIP string = "skip" ) -func (self *RebaseHelper) CreateRebaseOptionsMenu() error { +func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error { options := []string{REBASE_OPTION_CONTINUE, REBASE_OPTION_ABORT} if self.git.Status.WorkingTreeState() == enums.REBASE_MODE_REBASING { @@ -68,7 +73,7 @@ func (self *RebaseHelper) CreateRebaseOptionsMenu() error { return self.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems}) } -func (self *RebaseHelper) genericMergeCommand(command string) error { +func (self *MergeAndRebaseHelper) genericMergeCommand(command string) error { status := self.git.Status.WorkingTreeState() if status != enums.REBASE_MODE_MERGING && status != enums.REBASE_MODE_REBASING { @@ -120,7 +125,7 @@ func isMergeConflictErr(errStr string) bool { return false } -func (self *RebaseHelper) CheckMergeOrRebase(result error) error { +func (self *MergeAndRebaseHelper) CheckMergeOrRebase(result error) error { if err := self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil { return err } @@ -154,7 +159,7 @@ func (self *RebaseHelper) CheckMergeOrRebase(result error) error { } } -func (self *RebaseHelper) AbortMergeOrRebaseWithConfirm() error { +func (self *MergeAndRebaseHelper) AbortMergeOrRebaseWithConfirm() error { // prompt user to confirm that they want to abort, then do it mode := self.workingTreeStateNoun() return self.c.Ask(types.AskOpts{ @@ -166,7 +171,7 @@ func (self *RebaseHelper) AbortMergeOrRebaseWithConfirm() error { }) } -func (self *RebaseHelper) workingTreeStateNoun() string { +func (self *MergeAndRebaseHelper) workingTreeStateNoun() string { workingTreeState := self.git.Status.WorkingTreeState() switch workingTreeState { case enums.REBASE_MODE_NONE: @@ -179,7 +184,7 @@ func (self *RebaseHelper) workingTreeStateNoun() string { } // PromptToContinueRebase asks the user if they want to continue the rebase/merge that's in progress -func (self *RebaseHelper) PromptToContinueRebase() error { +func (self *MergeAndRebaseHelper) PromptToContinueRebase() error { self.takeOverMergeConflictScrolling() return self.c.Ask(types.AskOpts{ @@ -190,3 +195,54 @@ func (self *RebaseHelper) PromptToContinueRebase() error { }, }) } + +func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error { + checkedOutBranch := self.refsHelper.GetCheckedOutRef().Name + if ref == checkedOutBranch { + return self.c.ErrorMsg(self.c.Tr.CantRebaseOntoSelf) + } + prompt := utils.ResolvePlaceholderString( + self.c.Tr.ConfirmRebase, + map[string]string{ + "checkedOutBranch": checkedOutBranch, + "selectedBranch": ref, + }, + ) + + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.RebasingTitle, + Prompt: prompt, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.RebaseBranch) + err := self.git.Rebase.RebaseBranch(ref) + return self.CheckMergeOrRebase(err) + }, + }) +} + +func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) error { + if self.git.Branch.IsHeadDetached() { + return self.c.ErrorMsg("Cannot merge branch in detached head state. You might have checked out a commit directly or a remote branch, in which case you should checkout the local branch you want to be on") + } + checkedOutBranchName := self.refsHelper.GetCheckedOutRef().Name + if checkedOutBranchName == refName { + return self.c.ErrorMsg(self.c.Tr.CantMergeBranchIntoItself) + } + prompt := utils.ResolvePlaceholderString( + self.c.Tr.ConfirmMerge, + map[string]string{ + "checkedOutBranch": checkedOutBranchName, + "selectedBranch": refName, + }, + ) + + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.MergingTitle, + Prompt: prompt, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.Merge) + err := self.git.Branch.Merge(refName, git_commands.MergeOpts{}) + return self.CheckMergeOrRebase(err) + }, + }) +} diff --git a/pkg/gui/controllers/refs_helper.go b/pkg/gui/controllers/helpers/refs_helper.go similarity index 93% rename from pkg/gui/controllers/refs_helper.go rename to pkg/gui/controllers/helpers/refs_helper.go index e6d9babfb..3b132a32f 100644 --- a/pkg/gui/controllers/refs_helper.go +++ b/pkg/gui/controllers/helpers/refs_helper.go @@ -1,4 +1,4 @@ -package controllers +package helpers import ( "fmt" @@ -6,6 +6,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" + "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -14,26 +15,30 @@ import ( type IRefsHelper interface { CheckoutRef(ref string, options types.CheckoutRefOptions) error + GetCheckedOutRef() *models.Branch CreateGitResetMenu(ref string) error ResetToRef(ref string, strength string, envVars []string) error NewBranch(from string, fromDescription string, suggestedBranchname string) error } type RefsHelper struct { - c *types.ControllerCommon + c *types.HelperCommon git *commands.GitCommand contexts *context.ContextTree + model *types.Model } func NewRefsHelper( - c *types.ControllerCommon, + c *types.HelperCommon, git *commands.GitCommand, contexts *context.ContextTree, + model *types.Model, ) *RefsHelper { return &RefsHelper{ c: c, git: git, contexts: contexts, + model: model, } } @@ -99,6 +104,14 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions }) } +func (self *RefsHelper) GetCheckedOutRef() *models.Branch { + if len(self.model.Branches) == 0 { + return nil + } + + return self.model.Branches[0] +} + func (self *RefsHelper) ResetToRef(ref string, strength string, envVars []string) error { if err := self.git.Commit.ResetToCommit(ref, strength, envVars); err != nil { return self.c.Error(err) diff --git a/pkg/gui/controllers/suggestions_helper.go b/pkg/gui/controllers/helpers/suggestions_helper.go similarity index 98% rename from pkg/gui/controllers/suggestions_helper.go rename to pkg/gui/controllers/helpers/suggestions_helper.go index e696fdd8e..a48e325b1 100644 --- a/pkg/gui/controllers/suggestions_helper.go +++ b/pkg/gui/controllers/helpers/suggestions_helper.go @@ -1,4 +1,4 @@ -package controllers +package helpers import ( "fmt" @@ -30,7 +30,7 @@ type ISuggestionsHelper interface { } type SuggestionsHelper struct { - c *types.ControllerCommon + c *types.HelperCommon model *types.Model refreshSuggestionsFn func() @@ -39,7 +39,7 @@ type SuggestionsHelper struct { var _ ISuggestionsHelper = &SuggestionsHelper{} func NewSuggestionsHelper( - c *types.ControllerCommon, + c *types.HelperCommon, model *types.Model, refreshSuggestionsFn func(), ) *SuggestionsHelper { diff --git a/pkg/gui/controllers/tags_helper.go b/pkg/gui/controllers/helpers/tags_helper.go similarity index 94% rename from pkg/gui/controllers/tags_helper.go rename to pkg/gui/controllers/helpers/tags_helper.go index 6cec4fe4d..d2e92cd24 100644 --- a/pkg/gui/controllers/tags_helper.go +++ b/pkg/gui/controllers/helpers/tags_helper.go @@ -1,4 +1,4 @@ -package controllers +package helpers import ( "github.com/jesseduffield/lazygit/pkg/commands" @@ -10,11 +10,11 @@ import ( // and the commits context. type TagsHelper struct { - c *types.ControllerCommon + c *types.HelperCommon git *commands.GitCommand } -func NewTagsHelper(c *types.ControllerCommon, git *commands.GitCommand) *TagsHelper { +func NewTagsHelper(c *types.HelperCommon, git *commands.GitCommand) *TagsHelper { return &TagsHelper{ c: c, git: git, diff --git a/pkg/gui/controllers/working_tree_helper.go b/pkg/gui/controllers/helpers/working_tree_helper.go similarity index 98% rename from pkg/gui/controllers/working_tree_helper.go rename to pkg/gui/controllers/helpers/working_tree_helper.go index 894d278be..273748d6b 100644 --- a/pkg/gui/controllers/working_tree_helper.go +++ b/pkg/gui/controllers/helpers/working_tree_helper.go @@ -1,4 +1,4 @@ -package controllers +package helpers import ( "github.com/jesseduffield/lazygit/pkg/commands/models" diff --git a/pkg/gui/controllers/list_controller.go b/pkg/gui/controllers/list_controller.go index 8473fad83..5b1d2e04a 100644 --- a/pkg/gui/controllers/list_controller.go +++ b/pkg/gui/controllers/list_controller.go @@ -6,10 +6,10 @@ import ( ) type ListControllerFactory struct { - c *types.ControllerCommon + c *types.HelperCommon } -func NewListControllerFactory(c *types.ControllerCommon) *ListControllerFactory { +func NewListControllerFactory(c *types.HelperCommon) *ListControllerFactory { return &ListControllerFactory{ c: c, } @@ -25,7 +25,7 @@ func (self *ListControllerFactory) Create(context types.IListContext) *ListContr type ListController struct { baseController - c *types.ControllerCommon + c *types.HelperCommon context types.IListContext } diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index bb06a2314..0a7d51ae6 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -4,80 +4,37 @@ import ( "fmt" "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazygit/pkg/commands" - "github.com/jesseduffield/lazygit/pkg/commands/hosting_service" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" ) type ( - CheckoutRefFn func(refName string, opts types.CheckoutRefOptions) error - CreateGitResetMenuFn func(refName string) error SwitchToCommitFilesContextFn func(SwitchToCommitFilesContextOpts) error - GetHostingServiceMgrFn func() *hosting_service.HostingServiceMgr PullFilesFn func() error - CheckMergeOrRebase func(error) error ) type LocalCommitsController struct { baseController - c *types.ControllerCommon - context *context.LocalCommitsContext - os *oscommands.OSCommand - git *commands.GitCommand - tagsHelper *TagsHelper - refsHelper IRefsHelper - cherryPickHelper *CherryPickHelper - rebaseHelper *RebaseHelper + *controllerCommon - model *types.Model - CheckMergeOrRebase CheckMergeOrRebase pullFiles PullFilesFn - getHostingServiceMgr GetHostingServiceMgrFn switchToCommitFilesContext SwitchToCommitFilesContextFn - getShowWholeGitGraph func() bool - setShowWholeGitGraph func(bool) } var _ types.IController = &LocalCommitsController{} func NewLocalCommitsController( - c *types.ControllerCommon, - context *context.LocalCommitsContext, - os *oscommands.OSCommand, - git *commands.GitCommand, - tagsHelper *TagsHelper, - refsHelper IRefsHelper, - cherryPickHelper *CherryPickHelper, - rebaseHelper *RebaseHelper, - model *types.Model, - CheckMergeOrRebase CheckMergeOrRebase, + common *controllerCommon, pullFiles PullFilesFn, - getHostingServiceMgr GetHostingServiceMgrFn, switchToCommitFilesContext SwitchToCommitFilesContextFn, - getShowWholeGitGraph func() bool, - setShowWholeGitGraph func(bool), ) *LocalCommitsController { return &LocalCommitsController{ baseController: baseController{}, - c: c, - context: context, - os: os, - git: git, - tagsHelper: tagsHelper, - refsHelper: refsHelper, - cherryPickHelper: cherryPickHelper, - rebaseHelper: rebaseHelper, - model: model, - CheckMergeOrRebase: CheckMergeOrRebase, + controllerCommon: common, pullFiles: pullFiles, - getHostingServiceMgr: getHostingServiceMgr, switchToCommitFilesContext: switchToCommitFilesContext, - getShowWholeGitGraph: getShowWholeGitGraph, - setShowWholeGitGraph: setShowWholeGitGraph, } } @@ -185,7 +142,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ }, // { // Key: gocui.MouseLeft, - // Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, + // Handler: func() error { return self.context().HandleClick(self.checkSelected(self.enter)) }, // }, } @@ -305,7 +262,7 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error { InitialContent: message, HandleConfirm: func(response string) error { self.c.LogAction(self.c.Tr.Actions.RewordCommit) - if err := self.git.Rebase.RewordCommit(self.model.Commits, self.context.GetSelectedLineIdx(), response); err != nil { + if err := self.git.Rebase.RewordCommit(self.model.Commits, self.context().GetSelectedLineIdx(), response); err != nil { return self.c.Error(err) } @@ -325,7 +282,7 @@ func (self *LocalCommitsController) rewordEditor() error { self.c.LogAction(self.c.Tr.Actions.RewordCommit) subProcess, err := self.git.Rebase.RewordCommitInEditor( - self.model.Commits, self.context.GetSelectedLineIdx(), + self.model.Commits, self.context().GetSelectedLineIdx(), ) if err != nil { return self.c.Error(err) @@ -388,15 +345,15 @@ func (self *LocalCommitsController) pick() error { } func (self *LocalCommitsController) interactiveRebase(action string) error { - err := self.git.Rebase.InteractiveRebase(self.model.Commits, self.context.GetSelectedLineIdx(), action) - return self.CheckMergeOrRebase(err) + err := self.git.Rebase.InteractiveRebase(self.model.Commits, self.context().GetSelectedLineIdx(), action) + return self.helpers.MergeAndRebase.CheckMergeOrRebase(err) } // handleMidRebaseCommand sees if the selected commit is in fact a rebasing // commit meaning you are trying to edit the todo file rather than actually // begin a rebase. It then updates the todo file with that action func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool, error) { - selectedCommit := self.context.GetSelected() + selectedCommit := self.context().GetSelected() if selectedCommit.Status != "rebasing" { return false, nil } @@ -416,7 +373,7 @@ func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool, ) if err := self.git.Rebase.EditRebaseTodo( - self.context.GetSelectedLineIdx(), action, + self.context().GetSelectedLineIdx(), action, ); err != nil { return false, self.c.Error(err) } @@ -427,7 +384,7 @@ func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool, } func (self *LocalCommitsController) handleCommitMoveDown() error { - index := self.context.GetSelectedLineIdx() + index := self.context().GetSelectedLineIdx() commits := self.model.Commits selectedCommit := self.model.Commits[index] if selectedCommit.Status == "rebasing" { @@ -443,7 +400,7 @@ func (self *LocalCommitsController) handleCommitMoveDown() error { if err := self.git.Rebase.MoveTodoDown(index); err != nil { return self.c.Error(err) } - self.context.MoveSelectedLine(1) + self.context().MoveSelectedLine(1) return self.c.Refresh(types.RefreshOptions{ Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS}, }) @@ -453,14 +410,14 @@ func (self *LocalCommitsController) handleCommitMoveDown() error { self.c.LogAction(self.c.Tr.Actions.MoveCommitDown) err := self.git.Rebase.MoveCommitDown(self.model.Commits, index) if err == nil { - self.context.MoveSelectedLine(1) + self.context().MoveSelectedLine(1) } - return self.CheckMergeOrRebase(err) + return self.helpers.MergeAndRebase.CheckMergeOrRebase(err) }) } func (self *LocalCommitsController) handleCommitMoveUp() error { - index := self.context.GetSelectedLineIdx() + index := self.context().GetSelectedLineIdx() if index == 0 { return nil } @@ -478,7 +435,7 @@ func (self *LocalCommitsController) handleCommitMoveUp() error { if err := self.git.Rebase.MoveTodoDown(index - 1); err != nil { return self.c.Error(err) } - self.context.MoveSelectedLine(-1) + self.context().MoveSelectedLine(-1) return self.c.Refresh(types.RefreshOptions{ Mode: types.SYNC, Scope: []types.RefreshableView{types.REBASE_COMMITS}, }) @@ -488,9 +445,9 @@ func (self *LocalCommitsController) handleCommitMoveUp() error { self.c.LogAction(self.c.Tr.Actions.MoveCommitUp) err := self.git.Rebase.MoveCommitDown(self.model.Commits, index-1) if err == nil { - self.context.MoveSelectedLine(-1) + self.context().MoveSelectedLine(-1) } - return self.CheckMergeOrRebase(err) + return self.helpers.MergeAndRebase.CheckMergeOrRebase(err) }) } @@ -501,8 +458,8 @@ func (self *LocalCommitsController) handleCommitAmendTo() error { HandleConfirm: func() error { return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func() error { self.c.LogAction(self.c.Tr.Actions.AmendCommit) - err := self.git.Rebase.AmendTo(self.context.GetSelected().Sha) - return self.CheckMergeOrRebase(err) + err := self.git.Rebase.AmendTo(self.context().GetSelected().Sha) + return self.helpers.MergeAndRebase.CheckMergeOrRebase(err) }) }, }) @@ -556,7 +513,7 @@ func (self *LocalCommitsController) createRevertMergeCommitMenu(commit *models.C } func (self *LocalCommitsController) afterRevertCommit() error { - self.context.MoveSelectedLine(1) + self.context().MoveSelectedLine(1) return self.c.Refresh(types.RefreshOptions{ Mode: types.BLOCK_UI, Scope: []types.RefreshableView{types.COMMITS, types.BRANCHES}, }) @@ -564,10 +521,9 @@ func (self *LocalCommitsController) afterRevertCommit() error { func (self *LocalCommitsController) enter(commit *models.Commit) error { return self.switchToCommitFilesContext(SwitchToCommitFilesContextOpts{ - RefName: commit.Sha, - CanRebase: true, - Context: self.context, - WindowName: "commits", + RefName: commit.Sha, + CanRebase: true, + Context: self.context(), }) } @@ -608,14 +564,14 @@ func (self *LocalCommitsController) handleSquashAllAboveFixupCommits(commit *mod return self.c.WithWaitingStatus(self.c.Tr.SquashingStatus, func() error { self.c.LogAction(self.c.Tr.Actions.SquashAllAboveFixupCommits) err := self.git.Rebase.SquashAllAboveFixupCommits(commit.Sha) - return self.CheckMergeOrRebase(err) + return self.helpers.MergeAndRebase.CheckMergeOrRebase(err) }) }, }) } func (self *LocalCommitsController) handleTagCommit(commit *models.Commit) error { - return self.tagsHelper.CreateTagMenu(commit.Sha, func() {}) + return self.helpers.Tags.CreateTagMenu(commit.Sha, func() {}) } func (self *LocalCommitsController) handleCheckoutCommit(commit *models.Commit) error { @@ -624,19 +580,19 @@ func (self *LocalCommitsController) handleCheckoutCommit(commit *models.Commit) Prompt: self.c.Tr.SureCheckoutThisCommit, HandleConfirm: func() error { self.c.LogAction(self.c.Tr.Actions.CheckoutCommit) - return self.refsHelper.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) + return self.helpers.Refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) }, }) } func (self *LocalCommitsController) handleCreateCommitResetMenu(commit *models.Commit) error { - return self.refsHelper.CreateGitResetMenu(commit.Sha) + return self.helpers.Refs.CreateGitResetMenu(commit.Sha) } func (self *LocalCommitsController) openSearch() error { // we usually lazyload these commits but now that we're searching we need to load them now - if self.context.GetLimitCommits() { - self.context.SetLimitCommits(false) + if self.context().GetLimitCommits() { + self.context().SetLimitCommits(false) if err := self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS}}); err != nil { return err } @@ -649,14 +605,14 @@ func (self *LocalCommitsController) openSearch() error { func (self *LocalCommitsController) gotoBottom() error { // we usually lazyload these commits but now that we're jumping to the bottom we need to load them now - if self.context.GetLimitCommits() { - self.context.SetLimitCommits(false) + if self.context().GetLimitCommits() { + self.context().SetLimitCommits(false) if err := self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}); err != nil { return err } } - self.context.SetSelectedLineIdx(self.context.GetItemsLength() - 1) + self.context().SetSelectedLineIdx(self.context().GetItemsLength() - 1) return nil } @@ -684,10 +640,10 @@ func (self *LocalCommitsController) handleOpenLogMenu() error { { DisplayString: self.c.Tr.ToggleShowGitGraphAll, OnPress: func() error { - self.setShowWholeGitGraph(!self.getShowWholeGitGraph()) + self.context().SetShowWholeGitGraph(!self.context().GetShowWholeGitGraph()) - if self.getShowWholeGitGraph() { - self.context.SetLimitCommits(false) + if self.context().GetShowWholeGitGraph() { + self.context().SetLimitCommits(false) } return self.c.WithWaitingStatus(self.c.Tr.LcLoadingCommits, func() error { @@ -761,9 +717,7 @@ func (self *LocalCommitsController) handleOpenLogMenu() error { } func (self *LocalCommitsController) handleOpenCommitInBrowser(commit *models.Commit) error { - hostingServiceMgr := self.getHostingServiceMgr() - - url, err := hostingServiceMgr.GetCommitURL(commit.Sha) + url, err := self.helpers.Host.GetCommitURL(commit.Sha) if err != nil { return self.c.Error(err) } @@ -778,7 +732,7 @@ func (self *LocalCommitsController) handleOpenCommitInBrowser(commit *models.Com func (self *LocalCommitsController) checkSelected(callback func(*models.Commit) error) func() error { return func() error { - commit := self.context.GetSelected() + commit := self.context().GetSelected() if commit == nil { return nil } @@ -788,21 +742,25 @@ func (self *LocalCommitsController) checkSelected(callback func(*models.Commit) } func (self *LocalCommitsController) Context() types.Context { - return self.context + return self.context() +} + +func (self *LocalCommitsController) context() *context.LocalCommitsContext { + return self.contexts.BranchCommits } func (self *LocalCommitsController) newBranch(commit *models.Commit) error { - return self.refsHelper.NewBranch(commit.RefName(), commit.Description(), "") + return self.helpers.Refs.NewBranch(commit.RefName(), commit.Description(), "") } func (self *LocalCommitsController) copy(commit *models.Commit) error { - return self.cherryPickHelper.Copy(commit, self.model.Commits, self.context) + return self.helpers.CherryPick.Copy(commit, self.model.Commits, self.context()) } func (self *LocalCommitsController) copyRange(*models.Commit) error { - return self.cherryPickHelper.CopyRange(self.context.GetSelectedLineIdx(), self.model.Commits, self.context) + return self.helpers.CherryPick.CopyRange(self.context().GetSelectedLineIdx(), self.model.Commits, self.context()) } func (self *LocalCommitsController) paste() error { - return self.cherryPickHelper.Paste() + return self.helpers.CherryPick.Paste() } diff --git a/pkg/gui/controllers/menu_controller.go b/pkg/gui/controllers/menu_controller.go index 392fe3da6..91e85dec5 100644 --- a/pkg/gui/controllers/menu_controller.go +++ b/pkg/gui/controllers/menu_controller.go @@ -7,22 +7,17 @@ import ( type MenuController struct { baseController - - c *types.ControllerCommon - context *context.MenuContext + *controllerCommon } var _ types.IController = &MenuController{} func NewMenuController( - c *types.ControllerCommon, - context *context.MenuContext, + common *controllerCommon, ) *MenuController { return &MenuController{ - baseController: baseController{}, - - c: c, - context: context, + baseController: baseController{}, + controllerCommon: common, } } @@ -50,7 +45,7 @@ func (self *MenuController) GetKeybindings(opts types.KeybindingsOpts) []*types. } func (self *MenuController) press() error { - selectedItem := self.context.GetSelected() + selectedItem := self.context().GetSelected() if err := self.c.PopContext(); err != nil { return err @@ -64,5 +59,9 @@ func (self *MenuController) press() error { } func (self *MenuController) Context() types.Context { - return self.context + return self.context() +} + +func (self *MenuController) context() *context.MenuContext { + return self.contexts.Menu } diff --git a/pkg/gui/controllers/remotes_controller.go b/pkg/gui/controllers/remotes_controller.go index 12d2e7459..489454f89 100644 --- a/pkg/gui/controllers/remotes_controller.go +++ b/pkg/gui/controllers/remotes_controller.go @@ -1,7 +1,6 @@ package controllers import ( - "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -10,30 +9,22 @@ import ( type RemotesController struct { baseController - - c *types.ControllerCommon + *controllerCommon context *context.RemotesContext - git *commands.GitCommand setRemoteBranches func([]*models.RemoteBranch) - contexts *context.ContextTree } var _ types.IController = &RemotesController{} func NewRemotesController( - c *types.ControllerCommon, - context *context.RemotesContext, - git *commands.GitCommand, - contexts *context.ContextTree, + common *controllerCommon, setRemoteBranches func([]*models.RemoteBranch), ) *RemotesController { return &RemotesController{ baseController: baseController{}, - c: c, - git: git, - contexts: contexts, - context: context, + controllerCommon: common, + context: common.contexts.Remotes, setRemoteBranches: setRemoteBranches, } } diff --git a/pkg/gui/controllers/sub_commits_switch_controller.go b/pkg/gui/controllers/sub_commits_switch_controller.go index dbd6ab135..cbc9ce137 100644 --- a/pkg/gui/controllers/sub_commits_switch_controller.go +++ b/pkg/gui/controllers/sub_commits_switch_controller.go @@ -1,19 +1,14 @@ package controllers import ( - "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/loaders" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" ) type SubCommitsSwitchControllerFactory struct { - c *types.ControllerCommon - subCommitsContext *context.SubCommitsContext - git *commands.GitCommand - modes *types.Modes - setSubCommits func([]*models.Commit) + controllerCommon *controllerCommon + setSubCommits func([]*models.Commit) } var _ types.IController = &SubCommitsSwitchController{} @@ -25,40 +20,28 @@ type ContextWithRefName interface { type SubCommitsSwitchController struct { baseController + *controllerCommon + context ContextWithRefName - c *types.ControllerCommon - context ContextWithRefName - subCommitsContext *context.SubCommitsContext - git *commands.GitCommand - modes *types.Modes - setSubCommits func([]*models.Commit) + setSubCommits func([]*models.Commit) } func NewSubCommitsSwitchControllerFactory( - c *types.ControllerCommon, - subCommitsContext *context.SubCommitsContext, - git *commands.GitCommand, - modes *types.Modes, + common *controllerCommon, setSubCommits func([]*models.Commit), ) *SubCommitsSwitchControllerFactory { return &SubCommitsSwitchControllerFactory{ - c: c, - subCommitsContext: subCommitsContext, - git: git, - modes: modes, - setSubCommits: setSubCommits, + controllerCommon: common, + setSubCommits: setSubCommits, } } func (self *SubCommitsSwitchControllerFactory) Create(context ContextWithRefName) *SubCommitsSwitchController { return &SubCommitsSwitchController{ - baseController: baseController{}, - c: self.c, - context: context, - subCommitsContext: self.subCommitsContext, - git: self.git, - modes: self.modes, - setSubCommits: self.setSubCommits, + baseController: baseController{}, + controllerCommon: self.controllerCommon, + context: context, + setSubCommits: self.setSubCommits, } } @@ -94,10 +77,10 @@ func (self *SubCommitsSwitchController) viewCommits() error { } self.setSubCommits(commits) - self.subCommitsContext.SetSelectedLineIdx(0) - self.subCommitsContext.SetParentContext(self.context) + self.contexts.SubCommits.SetSelectedLineIdx(0) + self.contexts.SubCommits.SetParentContext(self.context) - return self.c.PushContext(self.subCommitsContext) + return self.c.PushContext(self.contexts.SubCommits) } func (self *SubCommitsSwitchController) Context() types.Context { diff --git a/pkg/gui/controllers/submodules_controller.go b/pkg/gui/controllers/submodules_controller.go index 2eba02953..408536960 100644 --- a/pkg/gui/controllers/submodules_controller.go +++ b/pkg/gui/controllers/submodules_controller.go @@ -5,7 +5,6 @@ import ( "path/filepath" "strings" - "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/style" @@ -14,10 +13,7 @@ import ( type SubmodulesController struct { baseController - - c *types.ControllerCommon - context *context.SubmodulesContext - git *commands.GitCommand + *controllerCommon enterSubmodule func(submodule *models.SubmoduleConfig) error } @@ -25,17 +21,13 @@ type SubmodulesController struct { var _ types.IController = &SubmodulesController{} func NewSubmodulesController( - c *types.ControllerCommon, - context *context.SubmodulesContext, - git *commands.GitCommand, + controllerCommon *controllerCommon, enterSubmodule func(submodule *models.SubmoduleConfig) error, ) *SubmodulesController { return &SubmodulesController{ - baseController: baseController{}, - c: c, - context: context, - git: git, - enterSubmodule: enterSubmodule, + baseController: baseController{}, + controllerCommon: controllerCommon, + enterSubmodule: enterSubmodule, } } @@ -79,7 +71,7 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []* }, // { // Key: gocui.MouseLeft, - // Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, + // Handler: func() error { return self.context().HandleClick(self.checkSelected(self.enter)) }, // }, } } @@ -227,7 +219,7 @@ func (self *SubmodulesController) remove(submodule *models.SubmoduleConfig) erro func (self *SubmodulesController) checkSelected(callback func(*models.SubmoduleConfig) error) func() error { return func() error { - submodule := self.context.GetSelected() + submodule := self.context().GetSelected() if submodule == nil { return nil } @@ -237,5 +229,9 @@ func (self *SubmodulesController) checkSelected(callback func(*models.SubmoduleC } func (self *SubmodulesController) Context() types.Context { - return self.context + return self.context() +} + +func (self *SubmodulesController) context() *context.SubmodulesContext { + return self.contexts.Submodules } diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go index f3f2894b0..74db3d527 100644 --- a/pkg/gui/controllers/sync_controller.go +++ b/pkg/gui/controllers/sync_controller.go @@ -4,7 +4,6 @@ import ( "fmt" "strings" - "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -12,35 +11,22 @@ import ( type SyncController struct { baseController + *controllerCommon - c *types.ControllerCommon - git *commands.GitCommand - - getCheckedOutBranch func() *models.Branch - suggestionsHelper ISuggestionsHelper - getSuggestedRemote func() string - CheckMergeOrRebase func(error) error + getSuggestedRemote func() string } var _ types.IController = &SyncController{} func NewSyncController( - c *types.ControllerCommon, - git *commands.GitCommand, - getCheckedOutBranch func() *models.Branch, - suggestionsHelper ISuggestionsHelper, + common *controllerCommon, getSuggestedRemote func() string, - CheckMergeOrRebase func(error) error, ) *SyncController { return &SyncController{ - baseController: baseController{}, - c: c, - git: git, + baseController: baseController{}, + controllerCommon: common, - getCheckedOutBranch: getCheckedOutBranch, - suggestionsHelper: suggestionsHelper, - getSuggestedRemote: getSuggestedRemote, - CheckMergeOrRebase: CheckMergeOrRebase, + getSuggestedRemote: getSuggestedRemote, } } @@ -75,7 +61,7 @@ func (self *SyncController) HandlePull() error { func (self *SyncController) branchCheckedOut(f func(*models.Branch) error) func() error { return func() error { - currentBranch := self.getCheckedOutBranch() + currentBranch := self.helpers.Refs.GetCheckedOutRef() if currentBranch == nil { // need to wait for branches to refresh return nil @@ -160,7 +146,7 @@ func (self *SyncController) promptForUpstream(currentBranch *models.Branch, onCo return self.c.Prompt(types.PromptOpts{ Title: self.c.Tr.EnterUpstream, InitialContent: suggestedRemote + " " + currentBranch.Name, - FindSuggestionsFunc: self.suggestionsHelper.GetRemoteBranchesSuggestionsFunc(" "), + FindSuggestionsFunc: self.helpers.Suggestions.GetRemoteBranchesSuggestionsFunc(" "), HandleConfirm: onConfirm, }) } @@ -189,7 +175,7 @@ func (self *SyncController) pullWithLock(opts PullFilesOptions) error { }, ) - return self.CheckMergeOrRebase(err) + return self.helpers.MergeAndRebase.CheckMergeOrRebase(err) } type pushOpts struct { diff --git a/pkg/gui/controllers/tags_controller.go b/pkg/gui/controllers/tags_controller.go index e819c1973..0ec153025 100644 --- a/pkg/gui/controllers/tags_controller.go +++ b/pkg/gui/controllers/tags_controller.go @@ -1,7 +1,6 @@ package controllers import ( - "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -10,43 +9,17 @@ import ( type TagsController struct { baseController - - c *types.ControllerCommon - context *context.TagsContext - git *commands.GitCommand - contexts *context.ContextTree - tagsHelper *TagsHelper - - refsHelper IRefsHelper - suggestionsHelper ISuggestionsHelper - - switchToSubCommitsContext func(string) error + *controllerCommon } var _ types.IController = &TagsController{} func NewTagsController( - c *types.ControllerCommon, - context *context.TagsContext, - git *commands.GitCommand, - contexts *context.ContextTree, - tagsHelper *TagsHelper, - refsHelper IRefsHelper, - suggestionsHelper ISuggestionsHelper, - - switchToSubCommitsContext func(string) error, + common *controllerCommon, ) *TagsController { return &TagsController{ - baseController: baseController{}, - c: c, - context: context, - git: git, - contexts: contexts, - tagsHelper: tagsHelper, - refsHelper: refsHelper, - suggestionsHelper: suggestionsHelper, - - switchToSubCommitsContext: switchToSubCommitsContext, + baseController: baseController{}, + controllerCommon: common, } } @@ -85,7 +58,7 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types. func (self *TagsController) checkout(tag *models.Tag) error { self.c.LogAction(self.c.Tr.Actions.CheckoutTag) - if err := self.refsHelper.CheckoutRef(tag.Name, types.CheckoutRefOptions{}); err != nil { + if err := self.helpers.Refs.CheckoutRef(tag.Name, types.CheckoutRefOptions{}); err != nil { return err } return self.c.PushContext(self.contexts.Branches) @@ -123,7 +96,7 @@ func (self *TagsController) push(tag *models.Tag) error { return self.c.Prompt(types.PromptOpts{ Title: title, InitialContent: "origin", - FindSuggestionsFunc: self.suggestionsHelper.GetRemoteSuggestionsFunc(), + FindSuggestionsFunc: self.helpers.Suggestions.GetRemoteSuggestionsFunc(), HandleConfirm: func(response string) error { return self.c.WithWaitingStatus(self.c.Tr.PushingTagStatus, func() error { self.c.LogAction(self.c.Tr.Actions.PushTag) @@ -139,17 +112,17 @@ func (self *TagsController) push(tag *models.Tag) error { } func (self *TagsController) createResetMenu(tag *models.Tag) error { - return self.refsHelper.CreateGitResetMenu(tag.Name) + return self.helpers.Refs.CreateGitResetMenu(tag.Name) } func (self *TagsController) create() error { // leaving commit SHA blank so that we're just creating the tag for the current commit - return self.tagsHelper.CreateTagMenu("", func() { self.context.SetSelectedLineIdx(0) }) + return self.helpers.Tags.CreateTagMenu("", func() { self.context().SetSelectedLineIdx(0) }) } func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func() error { return func() error { - tag := self.context.GetSelected() + tag := self.context().GetSelected() if tag == nil { return nil } @@ -159,5 +132,9 @@ func (self *TagsController) withSelectedTag(f func(tag *models.Tag) error) func( } func (self *TagsController) Context() types.Context { - return self.context + return self.context() +} + +func (self *TagsController) context() *context.TagsContext { + return self.contexts.Tags } diff --git a/pkg/gui/controllers/types.go b/pkg/gui/controllers/types.go index ecd02536c..9783ca3b7 100644 --- a/pkg/gui/controllers/types.go +++ b/pkg/gui/controllers/types.go @@ -6,8 +6,7 @@ import ( // all fields mandatory (except `CanRebase` because it's boolean) type SwitchToCommitFilesContextOpts struct { - RefName string - CanRebase bool - Context types.Context - WindowName string + RefName string + CanRebase bool + Context types.Context } diff --git a/pkg/gui/controllers/undo_controller.go b/pkg/gui/controllers/undo_controller.go index 683fb2b84..bfd6dc444 100644 --- a/pkg/gui/controllers/undo_controller.go +++ b/pkg/gui/controllers/undo_controller.go @@ -1,8 +1,6 @@ package controllers import ( - "github.com/jesseduffield/lazygit/pkg/commands" - "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -20,34 +18,17 @@ import ( type UndoController struct { baseController - - c *types.ControllerCommon - git *commands.GitCommand - - refsHelper IRefsHelper - workingTreeHelper IWorkingTreeHelper - - getFilteredReflogCommits func() []*models.Commit + *controllerCommon } var _ types.IController = &UndoController{} func NewUndoController( - c *types.ControllerCommon, - git *commands.GitCommand, - refsHelper IRefsHelper, - workingTreeHelper IWorkingTreeHelper, - - getFilteredReflogCommits func() []*models.Commit, + common *controllerCommon, ) *UndoController { return &UndoController{ - baseController: baseController{}, - c: c, - git: git, - refsHelper: refsHelper, - workingTreeHelper: workingTreeHelper, - - getFilteredReflogCommits: getFilteredReflogCommits, + baseController: baseController{}, + controllerCommon: common, } } @@ -109,7 +90,7 @@ func (self *UndoController) reflogUndo() error { }) case CHECKOUT: self.c.LogAction(self.c.Tr.Actions.Undo) - return true, self.refsHelper.CheckoutRef(action.from, types.CheckoutRefOptions{ + return true, self.helpers.Refs.CheckoutRef(action.from, types.CheckoutRefOptions{ EnvVars: undoEnvVars, WaitingStatus: undoingStatus, }) @@ -147,7 +128,7 @@ func (self *UndoController) reflogRedo() error { }) case CHECKOUT: self.c.LogAction(self.c.Tr.Actions.Redo) - return true, self.refsHelper.CheckoutRef(action.to, types.CheckoutRefOptions{ + return true, self.helpers.Refs.CheckoutRef(action.to, types.CheckoutRefOptions{ EnvVars: redoEnvVars, WaitingStatus: redoingStatus, }) @@ -168,7 +149,7 @@ func (self *UndoController) reflogRedo() error { // Though we might support this later, hence the use of the CURRENT_REBASE action kind. func (self *UndoController) parseReflogForActions(onUserAction func(counter int, action reflogAction) (bool, error)) error { counter := 0 - reflogCommits := self.getFilteredReflogCommits() + reflogCommits := self.model.FilteredReflogCommits rebaseFinishCommitSha := "" var action *reflogAction for reflogCommitIdx, reflogCommit := range reflogCommits { @@ -222,14 +203,14 @@ type hardResetOptions struct { // only to be used in the undo flow for now (does an autostash) func (self *UndoController) hardResetWithAutoStash(commitSha string, options hardResetOptions) error { reset := func() error { - if err := self.refsHelper.ResetToRef(commitSha, "hard", options.EnvVars); err != nil { + if err := self.helpers.Refs.ResetToRef(commitSha, "hard", options.EnvVars); err != nil { return self.c.Error(err) } return nil } // if we have any modified tracked files we need to ask the user if they want us to stash for them - dirtyWorkingTree := self.workingTreeHelper.IsWorkingTreeDirty() + dirtyWorkingTree := self.helpers.WorkingTree.IsWorkingTreeDirty() if dirtyWorkingTree { // offer to autostash changes return self.c.Ask(types.AskOpts{ diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index e32e5bb11..6bd659bd7 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -54,7 +54,7 @@ func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (s SelectedCommitFile: gui.getSelectedCommitFile(), SelectedCommitFilePath: gui.getSelectedCommitFilePath(), SelectedSubCommit: gui.State.Contexts.SubCommits.GetSelected(), - CheckedOutBranch: gui.getCheckedOutBranch(), + CheckedOutBranch: gui.helpers.Refs.GetCheckedOutRef(), PromptResponses: promptResponses, } diff --git a/pkg/gui/global_handlers.go b/pkg/gui/global_handlers.go index d14c5193d..d03723743 100644 --- a/pkg/gui/global_handlers.go +++ b/pkg/gui/global_handlers.go @@ -189,19 +189,6 @@ func (gui *Gui) handleMouseDownMain() error { return nil } -func (gui *Gui) fetch() (err error) { - gui.c.LogAction("Fetch") - err = gui.git.Sync.Fetch(git_commands.FetchOptions{}) - - if err != nil && strings.Contains(err.Error(), "exit status 128") { - _ = gui.c.ErrorMsg(gui.c.Tr.PassUnameWrong) - } - - _ = gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS, types.REMOTES, types.TAGS}, Mode: types.ASYNC}) - - return err -} - func (gui *Gui) backgroundFetch() (err error) { err = gui.git.Sync.Fetch(git_commands.FetchOptions{Background: true}) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 93e5c5ff3..3966cd48f 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -20,6 +20,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/controllers" + "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" "github.com/jesseduffield/lazygit/pkg/gui/lbl" "github.com/jesseduffield/lazygit/pkg/gui/mergeconflicts" "github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking" @@ -67,17 +68,6 @@ func NewContextManager(initialContext types.Context) ContextManager { } } -type Helpers struct { - Refs *controllers.RefsHelper - Bisect *controllers.BisectHelper - Suggestions *controllers.SuggestionsHelper - Files *controllers.FilesHelper - WorkingTree *controllers.WorkingTreeHelper - Tags *controllers.TagsHelper - Rebase *controllers.RebaseHelper - CherryPick *controllers.CherryPickHelper -} - type Repo string // Gui wraps the gocui Gui object which handles rendering and events @@ -144,9 +134,6 @@ type Gui struct { // flag as to whether or not the diff view should ignore whitespace IgnoreWhitespaceInDiffView bool - // if this is true, we'll load our commits using `git log --all` - ShowWholeGitGraph bool - // we use this to decide whether we'll return to the original directory that // lazygit was opened in, or if we'll retain the one we're currently in. RetainOriginalDir bool @@ -161,8 +148,8 @@ type Gui struct { // process InitialDir string - c *types.ControllerCommon - helpers *Helpers + c *types.HelperCommon + helpers *helpers.Helpers } // we keep track of some stuff from one render to the next to see if certain @@ -488,11 +475,11 @@ func NewGui( ) guiCommon := &guiCommon{gui: gui, IPopupHandler: gui.PopupHandler} - controllerCommon := &types.ControllerCommon{IGuiCommon: guiCommon, Common: cmn} + helperCommon := &types.HelperCommon{IGuiCommon: guiCommon, Common: cmn} // storing this stuff on the gui for now to ease refactoring // TODO: reset these controllers upon changing repos due to state changing - gui.c = controllerCommon + gui.c = helperCommon authors.SetCustomAuthors(gui.UserConfig.Gui.AuthorColors) presentation.SetCustomBranches(gui.UserConfig.Gui.BranchColors) @@ -503,21 +490,23 @@ func NewGui( func (gui *Gui) resetControllers() { controllerCommon := gui.c osCommand := gui.os - rebaseHelper := controllers.NewRebaseHelper(controllerCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling) model := gui.State.Model - gui.helpers = &Helpers{ - Refs: controllers.NewRefsHelper( - controllerCommon, - gui.git, - gui.State.Contexts, - ), - Bisect: controllers.NewBisectHelper(controllerCommon, gui.git), - Suggestions: controllers.NewSuggestionsHelper(controllerCommon, model, gui.refreshSuggestions), - Files: controllers.NewFilesHelper(controllerCommon, gui.git, osCommand), - WorkingTree: controllers.NewWorkingTreeHelper(model), - Tags: controllers.NewTagsHelper(controllerCommon, gui.git), - Rebase: rebaseHelper, - CherryPick: controllers.NewCherryPickHelper( + refsHelper := helpers.NewRefsHelper( + controllerCommon, + gui.git, + gui.State.Contexts, + model, + ) + rebaseHelper := helpers.NewMergeAndRebaseHelper(controllerCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling, refsHelper) + gui.helpers = &helpers.Helpers{ + Refs: refsHelper, + Bisect: helpers.NewBisectHelper(controllerCommon, gui.git), + Suggestions: helpers.NewSuggestionsHelper(controllerCommon, model, gui.refreshSuggestions), + Files: helpers.NewFilesHelper(controllerCommon, gui.git, osCommand), + WorkingTree: helpers.NewWorkingTreeHelper(model), + Tags: helpers.NewTagsHelper(controllerCommon, gui.git), + MergeAndRebase: rebaseHelper, + CherryPick: helpers.NewCherryPickHelper( controllerCommon, gui.git, gui.State.Contexts, @@ -526,109 +515,58 @@ func (gui *Gui) resetControllers() { ), } - syncController := controllers.NewSyncController( + common := controllers.NewControllerCommon( controllerCommon, + osCommand, gui.git, - gui.getCheckedOutBranch, - gui.helpers.Suggestions, + gui.helpers, + model, + gui.State.Contexts, + gui.State.Modes, + ) + + syncController := controllers.NewSyncController( + common, gui.getSuggestedRemote, - gui.helpers.Rebase.CheckMergeOrRebase, ) submodulesController := controllers.NewSubmodulesController( - controllerCommon, - gui.State.Contexts.Submodules, - gui.git, + common, gui.enterSubmodule, ) - bisectController := controllers.NewBisectController( - controllerCommon, - gui.State.Contexts.BranchCommits, - gui.git, - gui.helpers.Bisect, - func() []*models.Commit { return gui.State.Model.Commits }, - ) + bisectController := controllers.NewBisectController(common) gui.Controllers = Controllers{ Submodules: submodulesController, - Global: controllers.NewGlobalController( - controllerCommon, - osCommand, - ), + Global: controllers.NewGlobalController(common), Files: controllers.NewFilesController( - controllerCommon, - gui.State.Contexts.Files, - model, - gui.git, - osCommand, - gui.getSelectedFileNode, - gui.State.Contexts, + common, gui.enterSubmodule, - func() []*models.SubmoduleConfig { return gui.State.Model.Submodules }, gui.getSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage }), gui.withGpgHandling, func() string { return gui.State.failedCommitMessage }, - gui.getSelectedPath, gui.switchToMerge, - gui.helpers.Suggestions, - gui.helpers.Refs, - gui.helpers.Files, - gui.helpers.WorkingTree, - ), - Tags: controllers.NewTagsController( - controllerCommon, - gui.State.Contexts.Tags, - gui.git, - gui.State.Contexts, - gui.helpers.Tags, - gui.helpers.Refs, - gui.helpers.Suggestions, - gui.switchToSubCommitsContext, ), + Tags: controllers.NewTagsController(common), LocalCommits: controllers.NewLocalCommitsController( - controllerCommon, - gui.State.Contexts.BranchCommits, - osCommand, - gui.git, - gui.helpers.Tags, - gui.helpers.Refs, - gui.helpers.CherryPick, - gui.helpers.Rebase, - model, - gui.helpers.Rebase.CheckMergeOrRebase, + common, syncController.HandlePull, - gui.getHostingServiceMgr, gui.SwitchToCommitFilesContext, - func() bool { return gui.ShowWholeGitGraph }, - func(value bool) { gui.ShowWholeGitGraph = value }, ), Remotes: controllers.NewRemotesController( - controllerCommon, - gui.State.Contexts.Remotes, - gui.git, - gui.State.Contexts, + common, func(branches []*models.RemoteBranch) { gui.State.Model.RemoteBranches = branches }, ), - Menu: controllers.NewMenuController( - controllerCommon, - gui.State.Contexts.Menu, - ), - Undo: controllers.NewUndoController( - controllerCommon, - gui.git, - gui.helpers.Refs, - gui.helpers.WorkingTree, - func() []*models.Commit { return gui.State.Model.FilteredReflogCommits }, - ), + Menu: controllers.NewMenuController(common), + Undo: controllers.NewUndoController(common), Sync: syncController, } + branchesController := controllers.NewBranchesController(common) + switchToSubCommitsControllerFactory := controllers.NewSubCommitsSwitchControllerFactory( - controllerCommon, - gui.State.Contexts.SubCommits, - gui.git, - gui.State.Modes, + common, func(commits []*models.Commit) { gui.State.Model.SubCommits = commits }, ) @@ -640,6 +578,7 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(context, switchToSubCommitsControllerFactory.Create(context)) } + controllers.AttachControllers(gui.State.Contexts.Branches, branchesController) controllers.AttachControllers(gui.State.Contexts.Files, gui.Controllers.Files) controllers.AttachControllers(gui.State.Contexts.Tags, gui.Controllers.Tags) controllers.AttachControllers(gui.State.Contexts.Submodules, gui.Controllers.Submodules) diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 4b66281fc..25433eca5 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -194,593 +194,500 @@ func (gui *Gui) noPopupPanel(f func() error) func() error { } } -func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBinding) { - config := gui.c.UserConfig.Keybinding +// renaming receiver to 'self' to aid refactoring. Will probably end up moving all Gui handlers to this pattern eventually. +func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBinding) { + config := self.c.UserConfig.Keybinding guards := types.KeybindingGuards{ - OutsideFilterMode: gui.outsideFilterMode, - NoPopupPanel: gui.noPopupPanel, + OutsideFilterMode: self.outsideFilterMode, + NoPopupPanel: self.noPopupPanel, + } + + opts := types.KeybindingsOpts{ + GetKey: self.getKey, + Config: config, + Guards: guards, } bindings := []*types.Binding{ { ViewName: "", - Key: gui.getKey(config.Universal.Quit), + Key: opts.GetKey(opts.Config.Universal.Quit), Modifier: gocui.ModNone, - Handler: gui.handleQuit, + Handler: self.handleQuit, }, { ViewName: "", - Key: gui.getKey(config.Universal.QuitWithoutChangingDirectory), + Key: opts.GetKey(opts.Config.Universal.QuitWithoutChangingDirectory), Modifier: gocui.ModNone, - Handler: gui.handleQuitWithoutChangingDirectory, + Handler: self.handleQuitWithoutChangingDirectory, }, { ViewName: "", - Key: gui.getKey(config.Universal.QuitAlt1), + Key: opts.GetKey(opts.Config.Universal.QuitAlt1), Modifier: gocui.ModNone, - Handler: gui.handleQuit, + Handler: self.handleQuit, }, { ViewName: "", - Key: gui.getKey(config.Universal.Return), + Key: opts.GetKey(opts.Config.Universal.Return), Modifier: gocui.ModNone, - Handler: gui.handleTopLevelReturn, + Handler: self.handleTopLevelReturn, }, { ViewName: "", - Key: gui.getKey(config.Universal.OpenRecentRepos), - Handler: gui.handleCreateRecentReposMenu, + Key: opts.GetKey(opts.Config.Universal.OpenRecentRepos), + Handler: self.handleCreateRecentReposMenu, Alternative: " ", - Description: gui.c.Tr.SwitchRepo, + Description: self.c.Tr.SwitchRepo, }, { ViewName: "", - Key: gui.getKey(config.Universal.ScrollUpMain), - Handler: gui.scrollUpMain, + Key: opts.GetKey(opts.Config.Universal.ScrollUpMain), + Handler: self.scrollUpMain, Alternative: "fn+up", - Description: gui.c.Tr.LcScrollUpMainPanel, + Description: self.c.Tr.LcScrollUpMainPanel, }, { ViewName: "", - Key: gui.getKey(config.Universal.ScrollDownMain), - Handler: gui.scrollDownMain, + Key: opts.GetKey(opts.Config.Universal.ScrollDownMain), + Handler: self.scrollDownMain, Alternative: "fn+down", - Description: gui.c.Tr.LcScrollDownMainPanel, + Description: self.c.Tr.LcScrollDownMainPanel, }, { ViewName: "", - Key: gui.getKey(config.Universal.ScrollUpMainAlt1), + Key: opts.GetKey(opts.Config.Universal.ScrollUpMainAlt1), Modifier: gocui.ModNone, - Handler: gui.scrollUpMain, + Handler: self.scrollUpMain, }, { ViewName: "", - Key: gui.getKey(config.Universal.ScrollDownMainAlt1), + Key: opts.GetKey(opts.Config.Universal.ScrollDownMainAlt1), Modifier: gocui.ModNone, - Handler: gui.scrollDownMain, + Handler: self.scrollDownMain, }, { ViewName: "", - Key: gui.getKey(config.Universal.ScrollUpMainAlt2), + Key: opts.GetKey(opts.Config.Universal.ScrollUpMainAlt2), Modifier: gocui.ModNone, - Handler: gui.scrollUpMain, + Handler: self.scrollUpMain, }, { ViewName: "", - Key: gui.getKey(config.Universal.ScrollDownMainAlt2), + Key: opts.GetKey(opts.Config.Universal.ScrollDownMainAlt2), Modifier: gocui.ModNone, - Handler: gui.scrollDownMain, + Handler: self.scrollDownMain, }, { ViewName: "", - Key: gui.getKey(config.Universal.CreateRebaseOptionsMenu), - Handler: gui.helpers.Rebase.CreateRebaseOptionsMenu, - Description: gui.c.Tr.ViewMergeRebaseOptions, + Key: opts.GetKey(opts.Config.Universal.CreateRebaseOptionsMenu), + Handler: self.helpers.MergeAndRebase.CreateRebaseOptionsMenu, + Description: self.c.Tr.ViewMergeRebaseOptions, OpensMenu: true, }, { ViewName: "", - Key: gui.getKey(config.Universal.CreatePatchOptionsMenu), - Handler: gui.handleCreatePatchOptionsMenu, - Description: gui.c.Tr.ViewPatchOptions, + Key: opts.GetKey(opts.Config.Universal.CreatePatchOptionsMenu), + Handler: self.handleCreatePatchOptionsMenu, + Description: self.c.Tr.ViewPatchOptions, OpensMenu: true, }, { ViewName: "", - Key: gui.getKey(config.Universal.Refresh), - Handler: gui.handleRefresh, - Description: gui.c.Tr.LcRefresh, + Key: opts.GetKey(opts.Config.Universal.Refresh), + Handler: self.handleRefresh, + Description: self.c.Tr.LcRefresh, }, { ViewName: "", - Key: gui.getKey(config.Universal.OptionMenu), - Handler: gui.handleCreateOptionsMenu, - Description: gui.c.Tr.LcOpenMenu, + Key: opts.GetKey(opts.Config.Universal.OptionMenu), + Handler: self.handleCreateOptionsMenu, + Description: self.c.Tr.LcOpenMenu, OpensMenu: true, }, { ViewName: "", - Key: gui.getKey(config.Universal.OptionMenuAlt1), + Key: opts.GetKey(opts.Config.Universal.OptionMenuAlt1), Modifier: gocui.ModNone, - Handler: gui.handleCreateOptionsMenu, + Handler: self.handleCreateOptionsMenu, }, { ViewName: "status", - Key: gui.getKey(config.Universal.Edit), - Handler: gui.handleEditConfig, - Description: gui.c.Tr.EditConfig, + Key: opts.GetKey(opts.Config.Universal.Edit), + Handler: self.handleEditConfig, + Description: self.c.Tr.EditConfig, }, { ViewName: "", - Key: gui.getKey(config.Universal.NextScreenMode), - Handler: gui.nextScreenMode, - Description: gui.c.Tr.LcNextScreenMode, + Key: opts.GetKey(opts.Config.Universal.NextScreenMode), + Handler: self.nextScreenMode, + Description: self.c.Tr.LcNextScreenMode, }, { ViewName: "", - Key: gui.getKey(config.Universal.PrevScreenMode), - Handler: gui.prevScreenMode, - Description: gui.c.Tr.LcPrevScreenMode, + Key: opts.GetKey(opts.Config.Universal.PrevScreenMode), + Handler: self.prevScreenMode, + Description: self.c.Tr.LcPrevScreenMode, }, { ViewName: "status", - Key: gui.getKey(config.Universal.OpenFile), - Handler: gui.handleOpenConfig, - Description: gui.c.Tr.OpenConfig, + Key: opts.GetKey(opts.Config.Universal.OpenFile), + Handler: self.handleOpenConfig, + Description: self.c.Tr.OpenConfig, }, { ViewName: "status", - Key: gui.getKey(config.Status.CheckForUpdate), - Handler: gui.handleCheckForUpdate, - Description: gui.c.Tr.LcCheckForUpdate, + Key: opts.GetKey(opts.Config.Status.CheckForUpdate), + Handler: self.handleCheckForUpdate, + Description: self.c.Tr.LcCheckForUpdate, }, { ViewName: "status", - Key: gui.getKey(config.Status.RecentRepos), - Handler: gui.handleCreateRecentReposMenu, - Description: gui.c.Tr.SwitchRepo, + Key: opts.GetKey(opts.Config.Status.RecentRepos), + Handler: self.handleCreateRecentReposMenu, + Description: self.c.Tr.SwitchRepo, }, { ViewName: "status", - Key: gui.getKey(config.Status.AllBranchesLogGraph), - Handler: gui.handleShowAllBranchLogs, - Description: gui.c.Tr.LcAllBranchesLogGraph, + Key: opts.GetKey(opts.Config.Status.AllBranchesLogGraph), + Handler: self.handleShowAllBranchLogs, + Description: self.c.Tr.LcAllBranchesLogGraph, }, { ViewName: "files", Contexts: []string{string(context.FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.ViewResetOptions), - Handler: gui.handleCreateResetMenu, - Description: gui.c.Tr.LcViewResetOptions, + Key: opts.GetKey(opts.Config.Files.ViewResetOptions), + Handler: self.handleCreateResetMenu, + Description: self.c.Tr.LcViewResetOptions, OpensMenu: true, }, { ViewName: "files", Contexts: []string{string(context.FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.Fetch), - Handler: gui.handleGitFetch, - Description: gui.c.Tr.LcFetch, - }, - { - ViewName: "files", - Contexts: []string{string(context.FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.CopyToClipboard), - Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.c.Tr.LcCopyFileNameToClipboard, + Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Handler: self.handleCopySelectedSideContextItemToClipboard, + Description: self.c.Tr.LcCopyFileNameToClipboard, }, { ViewName: "branches", Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Select), - Handler: gui.handleBranchPress, - Description: gui.c.Tr.LcCheckout, - }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.CreatePullRequest), - Handler: gui.handleCreatePullRequestPress, - Description: gui.c.Tr.LcCreatePullRequest, - }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.ViewPullRequestOptions), - Handler: gui.handleCreatePullRequestMenu, - Description: gui.c.Tr.LcCreatePullRequestOptions, + Key: opts.GetKey(opts.Config.Branches.ViewGitFlowOptions), + Handler: self.handleCreateGitFlowMenu, + Description: self.c.Tr.LcGitFlowOptions, OpensMenu: true, }, { ViewName: "branches", Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.CopyPullRequestURL), - Handler: gui.handleCopyPullRequestURLPress, - Description: gui.c.Tr.LcCopyPullRequestURL, - }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.CheckoutBranchByName), - Handler: gui.handleCheckoutByName, - Description: gui.c.Tr.LcCheckoutByName, - }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.ForceCheckoutBranch), - Handler: gui.handleForceCheckout, - Description: gui.c.Tr.LcForceCheckout, - }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.New), - Handler: gui.handleNewBranchOffBranch, - Description: gui.c.Tr.LcNewBranch, - }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Remove), - Handler: gui.handleDeleteBranch, - Description: gui.c.Tr.LcDeleteBranch, - }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.RebaseBranch), - Handler: guards.OutsideFilterMode(gui.handleRebaseOntoLocalBranch), - Description: gui.c.Tr.LcRebaseBranch, - }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.MergeIntoCurrentBranch), - Handler: guards.OutsideFilterMode(gui.handleMerge), - Description: gui.c.Tr.LcMergeIntoCurrentBranch, - }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.ViewGitFlowOptions), - Handler: gui.handleCreateGitFlowMenu, - Description: gui.c.Tr.LcGitFlowOptions, - OpensMenu: true, - }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.FastForward), - Handler: gui.handleFastForward, - Description: gui.c.Tr.FastForward, - }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.ViewResetOptions), - Handler: gui.handleCreateResetToBranchMenu, - Description: gui.c.Tr.LcViewResetOptions, - OpensMenu: true, - }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.RenameBranch), - Handler: gui.handleRenameBranch, - Description: gui.c.Tr.LcRenameBranch, - }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.CopyToClipboard), - Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.c.Tr.LcCopyBranchNameToClipboard, + Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Handler: self.handleCopySelectedSideContextItemToClipboard, + Description: self.c.Tr.LcCopyBranchNameToClipboard, }, { ViewName: "branches", Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Return), - Handler: gui.handleRemoteBranchesEscape, - Description: gui.c.Tr.ReturnToRemotesList, + Key: opts.GetKey(opts.Config.Universal.Return), + Handler: self.handleRemoteBranchesEscape, + Description: self.c.Tr.ReturnToRemotesList, }, { ViewName: "branches", Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.ViewResetOptions), - Handler: gui.handleCreateResetToRemoteBranchMenu, - Description: gui.c.Tr.LcViewResetOptions, + Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), + Handler: self.handleCreateResetToRemoteBranchMenu, + Description: self.c.Tr.LcViewResetOptions, OpensMenu: true, }, { ViewName: "commits", Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.CopyToClipboard), - Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.c.Tr.LcCopyCommitShaToClipboard, + Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Handler: self.handleCopySelectedSideContextItemToClipboard, + Description: self.c.Tr.LcCopyCommitShaToClipboard, }, { ViewName: "commits", Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.ResetCherryPick), - Handler: gui.helpers.CherryPick.Reset, - Description: gui.c.Tr.LcResetCherryPick, + Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), + Handler: self.helpers.CherryPick.Reset, + Description: self.c.Tr.LcResetCherryPick, }, { ViewName: "commits", Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.GoInto), - Handler: gui.handleViewReflogCommitFiles, - Description: gui.c.Tr.LcViewCommitFiles, + Key: opts.GetKey(opts.Config.Universal.GoInto), + Handler: self.handleViewReflogCommitFiles, + Description: self.c.Tr.LcViewCommitFiles, }, { ViewName: "commits", Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Select), - Handler: gui.CheckoutReflogCommit, - Description: gui.c.Tr.LcCheckoutCommit, + Key: opts.GetKey(opts.Config.Universal.Select), + Handler: self.CheckoutReflogCommit, + Description: self.c.Tr.LcCheckoutCommit, }, { ViewName: "commits", Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.ViewResetOptions), - Handler: gui.handleCreateReflogResetMenu, - Description: gui.c.Tr.LcViewResetOptions, + Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), + Handler: self.handleCreateReflogResetMenu, + Description: self.c.Tr.LcViewResetOptions, OpensMenu: true, }, { ViewName: "commits", Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.CherryPickCopy), - Handler: guards.OutsideFilterMode(gui.handleCopyReflogCommit), - Description: gui.c.Tr.LcCherryPickCopy, + Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), + Handler: opts.Guards.OutsideFilterMode(self.handleCopyReflogCommit), + Description: self.c.Tr.LcCherryPickCopy, }, { ViewName: "commits", Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.CherryPickCopyRange), - Handler: guards.OutsideFilterMode(gui.handleCopyReflogCommitRange), - Description: gui.c.Tr.LcCherryPickCopyRange, + Key: opts.GetKey(opts.Config.Commits.CherryPickCopyRange), + Handler: opts.Guards.OutsideFilterMode(self.handleCopyReflogCommitRange), + Description: self.c.Tr.LcCherryPickCopyRange, }, { ViewName: "commits", Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.ResetCherryPick), - Handler: gui.helpers.CherryPick.Reset, - Description: gui.c.Tr.LcResetCherryPick, + Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), + Handler: self.helpers.CherryPick.Reset, + Description: self.c.Tr.LcResetCherryPick, }, { ViewName: "commits", Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.CopyToClipboard), - Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.c.Tr.LcCopyCommitShaToClipboard, + Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Handler: self.handleCopySelectedSideContextItemToClipboard, + Description: self.c.Tr.LcCopyCommitShaToClipboard, }, { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.GoInto), - Handler: gui.handleViewSubCommitFiles, - Description: gui.c.Tr.LcViewCommitFiles, + Key: opts.GetKey(opts.Config.Universal.GoInto), + Handler: self.handleViewSubCommitFiles, + Description: self.c.Tr.LcViewCommitFiles, }, { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Select), - Handler: gui.handleCheckoutSubCommit, - Description: gui.c.Tr.LcCheckoutCommit, + Key: opts.GetKey(opts.Config.Universal.Select), + Handler: self.handleCheckoutSubCommit, + Description: self.c.Tr.LcCheckoutCommit, }, { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.ViewResetOptions), - Handler: gui.handleCreateSubCommitResetMenu, - Description: gui.c.Tr.LcViewResetOptions, + Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), + Handler: self.handleCreateSubCommitResetMenu, + Description: self.c.Tr.LcViewResetOptions, OpensMenu: true, }, { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.New), - Handler: gui.handleNewBranchOffSubCommit, - Description: gui.c.Tr.LcNewBranch, + Key: opts.GetKey(opts.Config.Universal.New), + Handler: self.handleNewBranchOffSubCommit, + Description: self.c.Tr.LcNewBranch, }, { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.CherryPickCopy), - Handler: gui.handleCopySubCommit, - Description: gui.c.Tr.LcCherryPickCopy, + Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), + Handler: self.handleCopySubCommit, + Description: self.c.Tr.LcCherryPickCopy, }, { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.CherryPickCopyRange), - Handler: gui.handleCopySubCommitRange, - Description: gui.c.Tr.LcCherryPickCopyRange, + Key: opts.GetKey(opts.Config.Commits.CherryPickCopyRange), + Handler: self.handleCopySubCommitRange, + Description: self.c.Tr.LcCherryPickCopyRange, }, { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Commits.ResetCherryPick), - Handler: gui.helpers.CherryPick.Reset, - Description: gui.c.Tr.LcResetCherryPick, + Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), + Handler: self.helpers.CherryPick.Reset, + Description: self.c.Tr.LcResetCherryPick, }, { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.CopyToClipboard), - Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.c.Tr.LcCopyCommitShaToClipboard, + Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Handler: self.handleCopySelectedSideContextItemToClipboard, + Description: self.c.Tr.LcCopyCommitShaToClipboard, }, { ViewName: "stash", - Key: gui.getKey(config.Universal.GoInto), - Handler: gui.handleViewStashFiles, - Description: gui.c.Tr.LcViewStashFiles, + Key: opts.GetKey(opts.Config.Universal.GoInto), + Handler: self.handleViewStashFiles, + Description: self.c.Tr.LcViewStashFiles, }, { ViewName: "stash", - Key: gui.getKey(config.Universal.Select), - Handler: gui.handleStashApply, - Description: gui.c.Tr.LcApply, + Key: opts.GetKey(opts.Config.Universal.Select), + Handler: self.handleStashApply, + Description: self.c.Tr.LcApply, }, { ViewName: "stash", - Key: gui.getKey(config.Stash.PopStash), - Handler: gui.handleStashPop, - Description: gui.c.Tr.LcPop, + Key: opts.GetKey(opts.Config.Stash.PopStash), + Handler: self.handleStashPop, + Description: self.c.Tr.LcPop, }, { ViewName: "stash", - Key: gui.getKey(config.Universal.Remove), - Handler: gui.handleStashDrop, - Description: gui.c.Tr.LcDrop, + Key: opts.GetKey(opts.Config.Universal.Remove), + Handler: self.handleStashDrop, + Description: self.c.Tr.LcDrop, }, { ViewName: "stash", - Key: gui.getKey(config.Universal.New), - Handler: gui.handleNewBranchOffStashEntry, - Description: gui.c.Tr.LcNewBranch, + Key: opts.GetKey(opts.Config.Universal.New), + Handler: self.handleNewBranchOffStashEntry, + Description: self.c.Tr.LcNewBranch, }, { ViewName: "commitMessage", - Key: gui.getKey(config.Universal.SubmitEditorText), + Key: opts.GetKey(opts.Config.Universal.SubmitEditorText), Modifier: gocui.ModNone, - Handler: gui.handleCommitConfirm, + Handler: self.handleCommitConfirm, }, { ViewName: "commitMessage", - Key: gui.getKey(config.Universal.Return), + Key: opts.GetKey(opts.Config.Universal.Return), Modifier: gocui.ModNone, - Handler: gui.handleCommitClose, + Handler: self.handleCommitClose, }, { ViewName: "credentials", - Key: gui.getKey(config.Universal.Confirm), + Key: opts.GetKey(opts.Config.Universal.Confirm), Modifier: gocui.ModNone, - Handler: gui.handleSubmitCredential, + Handler: self.handleSubmitCredential, }, { ViewName: "credentials", - Key: gui.getKey(config.Universal.Return), + Key: opts.GetKey(opts.Config.Universal.Return), Modifier: gocui.ModNone, - Handler: gui.handleCloseCredentialsView, + Handler: self.handleCloseCredentialsView, }, { ViewName: "menu", - Key: gui.getKey(config.Universal.Return), - Handler: gui.handleMenuClose, - Description: gui.c.Tr.LcCloseMenu, + Key: opts.GetKey(opts.Config.Universal.Return), + Handler: self.handleMenuClose, + Description: self.c.Tr.LcCloseMenu, }, { ViewName: "information", Key: gocui.MouseLeft, Modifier: gocui.ModNone, - Handler: gui.handleInfoClick, + Handler: self.handleInfoClick, }, { ViewName: "commitFiles", - Key: gui.getKey(config.Universal.CopyToClipboard), - Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.c.Tr.LcCopyCommitFileNameToClipboard, + Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Handler: self.handleCopySelectedSideContextItemToClipboard, + Description: self.c.Tr.LcCopyCommitFileNameToClipboard, }, { ViewName: "commitFiles", - Key: gui.getKey(config.CommitFiles.CheckoutCommitFile), - Handler: gui.handleCheckoutCommitFile, - Description: gui.c.Tr.LcCheckoutCommitFile, + Key: opts.GetKey(opts.Config.CommitFiles.CheckoutCommitFile), + Handler: self.handleCheckoutCommitFile, + Description: self.c.Tr.LcCheckoutCommitFile, }, { ViewName: "commitFiles", - Key: gui.getKey(config.Universal.Remove), - Handler: gui.handleDiscardOldFileChange, - Description: gui.c.Tr.LcDiscardOldFileChange, + Key: opts.GetKey(opts.Config.Universal.Remove), + Handler: self.handleDiscardOldFileChange, + Description: self.c.Tr.LcDiscardOldFileChange, }, { ViewName: "commitFiles", - Key: gui.getKey(config.Universal.OpenFile), - Handler: gui.handleOpenOldCommitFile, - Description: gui.c.Tr.LcOpenFile, + Key: opts.GetKey(opts.Config.Universal.OpenFile), + Handler: self.handleOpenOldCommitFile, + Description: self.c.Tr.LcOpenFile, }, { ViewName: "commitFiles", - Key: gui.getKey(config.Universal.Edit), - Handler: gui.handleEditCommitFile, - Description: gui.c.Tr.LcEditFile, + Key: opts.GetKey(opts.Config.Universal.Edit), + Handler: self.handleEditCommitFile, + Description: self.c.Tr.LcEditFile, }, { ViewName: "commitFiles", - Key: gui.getKey(config.Universal.Select), - Handler: gui.handleToggleFileForPatch, - Description: gui.c.Tr.LcToggleAddToPatch, + Key: opts.GetKey(opts.Config.Universal.Select), + Handler: self.handleToggleFileForPatch, + Description: self.c.Tr.LcToggleAddToPatch, }, { ViewName: "commitFiles", - Key: gui.getKey(config.Universal.GoInto), - Handler: gui.handleEnterCommitFile, - Description: gui.c.Tr.LcEnterFile, + Key: opts.GetKey(opts.Config.Universal.GoInto), + Handler: self.handleEnterCommitFile, + Description: self.c.Tr.LcEnterFile, }, { ViewName: "commitFiles", - Key: gui.getKey(config.Files.ToggleTreeView), - Handler: gui.handleToggleCommitFileTreeView, - Description: gui.c.Tr.LcToggleTreeView, + Key: opts.GetKey(opts.Config.Files.ToggleTreeView), + Handler: self.handleToggleCommitFileTreeView, + Description: self.c.Tr.LcToggleTreeView, }, { ViewName: "", - Key: gui.getKey(config.Universal.FilteringMenu), - Handler: gui.handleCreateFilteringMenuPanel, - Description: gui.c.Tr.LcOpenFilteringMenu, + Key: opts.GetKey(opts.Config.Universal.FilteringMenu), + Handler: self.handleCreateFilteringMenuPanel, + Description: self.c.Tr.LcOpenFilteringMenu, OpensMenu: true, }, { ViewName: "", - Key: gui.getKey(config.Universal.DiffingMenu), - Handler: gui.handleCreateDiffingMenuPanel, - Description: gui.c.Tr.LcOpenDiffingMenu, + Key: opts.GetKey(opts.Config.Universal.DiffingMenu), + Handler: self.handleCreateDiffingMenuPanel, + Description: self.c.Tr.LcOpenDiffingMenu, OpensMenu: true, }, { ViewName: "", - Key: gui.getKey(config.Universal.DiffingMenuAlt), - Handler: gui.handleCreateDiffingMenuPanel, - Description: gui.c.Tr.LcOpenDiffingMenu, + Key: opts.GetKey(opts.Config.Universal.DiffingMenuAlt), + Handler: self.handleCreateDiffingMenuPanel, + Description: self.c.Tr.LcOpenDiffingMenu, OpensMenu: true, }, { ViewName: "", - Key: gui.getKey(config.Universal.ExtrasMenu), - Handler: gui.handleCreateExtrasMenuPanel, - Description: gui.c.Tr.LcOpenExtrasMenu, + Key: opts.GetKey(opts.Config.Universal.ExtrasMenu), + Handler: self.handleCreateExtrasMenuPanel, + Description: self.c.Tr.LcOpenExtrasMenu, OpensMenu: true, }, { ViewName: "secondary", Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, - Handler: gui.scrollUpSecondary, + Handler: self.scrollUpSecondary, }, { ViewName: "secondary", Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, - Handler: gui.scrollDownSecondary, + Handler: self.scrollDownSecondary, }, { ViewName: "main", Contexts: []string{string(context.MAIN_NORMAL_CONTEXT_KEY)}, Key: gocui.MouseWheelDown, - Handler: gui.scrollDownMain, - Description: gui.c.Tr.ScrollDown, + Handler: self.scrollDownMain, + Description: self.c.Tr.ScrollDown, Alternative: "fn+up", }, { ViewName: "main", Contexts: []string{string(context.MAIN_NORMAL_CONTEXT_KEY)}, Key: gocui.MouseWheelUp, - Handler: gui.scrollUpMain, - Description: gui.c.Tr.ScrollUp, + Handler: self.scrollUpMain, + Description: self.c.Tr.ScrollUp, Alternative: "fn+down", }, { @@ -788,556 +695,550 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin Contexts: []string{string(context.MAIN_NORMAL_CONTEXT_KEY)}, Key: gocui.MouseLeft, Modifier: gocui.ModNone, - Handler: gui.handleMouseDownMain, + Handler: self.handleMouseDownMain, }, { ViewName: "secondary", Contexts: []string{string(context.MAIN_STAGING_CONTEXT_KEY)}, Key: gocui.MouseLeft, Modifier: gocui.ModNone, - Handler: gui.handleTogglePanelClick, + Handler: self.handleTogglePanelClick, }, { ViewName: "main", Contexts: []string{string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Return), - Handler: gui.handleStagingEscape, - Description: gui.c.Tr.ReturnToFilesPanel, + Key: opts.GetKey(opts.Config.Universal.Return), + Handler: self.handleStagingEscape, + Description: self.c.Tr.ReturnToFilesPanel, }, { ViewName: "main", Contexts: []string{string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Select), - Handler: gui.handleToggleStagedSelection, - Description: gui.c.Tr.StageSelection, + Key: opts.GetKey(opts.Config.Universal.Select), + Handler: self.handleToggleStagedSelection, + Description: self.c.Tr.StageSelection, }, { ViewName: "main", Contexts: []string{string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Remove), - Handler: gui.handleResetSelection, - Description: gui.c.Tr.ResetSelection, + Key: opts.GetKey(opts.Config.Universal.Remove), + Handler: self.handleResetSelection, + Description: self.c.Tr.ResetSelection, }, { ViewName: "main", Contexts: []string{string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.TogglePanel), - Handler: gui.handleTogglePanel, - Description: gui.c.Tr.TogglePanel, + Key: opts.GetKey(opts.Config.Universal.TogglePanel), + Handler: self.handleTogglePanel, + Description: self.c.Tr.TogglePanel, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Return), - Handler: gui.handleEscapePatchBuildingPanel, - Description: gui.c.Tr.ExitLineByLineMode, + Key: opts.GetKey(opts.Config.Universal.Return), + Handler: self.handleEscapePatchBuildingPanel, + Description: self.c.Tr.ExitLineByLineMode, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.OpenFile), - Handler: gui.handleOpenFileAtLine, - Description: gui.c.Tr.LcOpenFile, + Key: opts.GetKey(opts.Config.Universal.OpenFile), + Handler: self.handleOpenFileAtLine, + Description: self.c.Tr.LcOpenFile, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.PrevItem), - Handler: gui.handleSelectPrevLine, - Description: gui.c.Tr.PrevLine, + Key: opts.GetKey(opts.Config.Universal.PrevItem), + Handler: self.handleSelectPrevLine, + Description: self.c.Tr.PrevLine, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.NextItem), - Handler: gui.handleSelectNextLine, - Description: gui.c.Tr.NextLine, + Key: opts.GetKey(opts.Config.Universal.NextItem), + Handler: self.handleSelectNextLine, + Description: self.c.Tr.NextLine, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.PrevItemAlt), + Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Modifier: gocui.ModNone, - Handler: gui.handleSelectPrevLine, + Handler: self.handleSelectPrevLine, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.NextItemAlt), + Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Modifier: gocui.ModNone, - Handler: gui.handleSelectNextLine, + Handler: self.handleSelectNextLine, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, - Handler: gui.scrollUpMain, + Handler: self.scrollUpMain, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, - Handler: gui.scrollDownMain, + Handler: self.scrollDownMain, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.PrevBlock), - Handler: gui.handleSelectPrevHunk, - Description: gui.c.Tr.PrevHunk, + Key: opts.GetKey(opts.Config.Universal.PrevBlock), + Handler: self.handleSelectPrevHunk, + Description: self.c.Tr.PrevHunk, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.PrevBlockAlt), + Key: opts.GetKey(opts.Config.Universal.PrevBlockAlt), Modifier: gocui.ModNone, - Handler: gui.handleSelectPrevHunk, + Handler: self.handleSelectPrevHunk, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.NextBlock), - Handler: gui.handleSelectNextHunk, - Description: gui.c.Tr.NextHunk, + Key: opts.GetKey(opts.Config.Universal.NextBlock), + Handler: self.handleSelectNextHunk, + Description: self.c.Tr.NextHunk, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.NextBlockAlt), + Key: opts.GetKey(opts.Config.Universal.NextBlockAlt), Modifier: gocui.ModNone, - Handler: gui.handleSelectNextHunk, + Handler: self.handleSelectNextHunk, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.CopyToClipboard), + Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), Modifier: gocui.ModNone, - Handler: gui.copySelectedToClipboard, - Description: gui.c.Tr.LcCopySelectedTexToClipboard, + Handler: self.copySelectedToClipboard, + Description: self.c.Tr.LcCopySelectedTexToClipboard, }, { ViewName: "main", Contexts: []string{string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Edit), - Handler: gui.handleLineByLineEdit, - Description: gui.c.Tr.LcEditFile, + Key: opts.GetKey(opts.Config.Universal.Edit), + Handler: self.handleLineByLineEdit, + Description: self.c.Tr.LcEditFile, }, { ViewName: "main", Contexts: []string{string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.OpenFile), - Handler: gui.Controllers.Files.Open, - Description: gui.c.Tr.LcOpenFile, + Key: opts.GetKey(opts.Config.Universal.OpenFile), + Handler: self.Controllers.Files.Open, + Description: self.c.Tr.LcOpenFile, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.NextPage), + Key: opts.GetKey(opts.Config.Universal.NextPage), Modifier: gocui.ModNone, - Handler: gui.handleLineByLineNextPage, - Description: gui.c.Tr.LcNextPage, + Handler: self.handleLineByLineNextPage, + Description: self.c.Tr.LcNextPage, Tag: "navigation", }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.PrevPage), + Key: opts.GetKey(opts.Config.Universal.PrevPage), Modifier: gocui.ModNone, - Handler: gui.handleLineByLinePrevPage, - Description: gui.c.Tr.LcPrevPage, + Handler: self.handleLineByLinePrevPage, + Description: self.c.Tr.LcPrevPage, Tag: "navigation", }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.GotoTop), + Key: opts.GetKey(opts.Config.Universal.GotoTop), Modifier: gocui.ModNone, - Handler: gui.handleLineByLineGotoTop, - Description: gui.c.Tr.LcGotoTop, + Handler: self.handleLineByLineGotoTop, + Description: self.c.Tr.LcGotoTop, Tag: "navigation", }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.GotoBottom), + Key: opts.GetKey(opts.Config.Universal.GotoBottom), Modifier: gocui.ModNone, - Handler: gui.handleLineByLineGotoBottom, - Description: gui.c.Tr.LcGotoBottom, + Handler: self.handleLineByLineGotoBottom, + Description: self.c.Tr.LcGotoBottom, Tag: "navigation", }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.StartSearch), - Handler: func() error { return gui.handleOpenSearch("main") }, - Description: gui.c.Tr.LcStartSearch, + Key: opts.GetKey(opts.Config.Universal.StartSearch), + Handler: func() error { return self.handleOpenSearch("main") }, + Description: self.c.Tr.LcStartSearch, Tag: "navigation", }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Select), - Handler: gui.handleToggleSelectionForPatch, - Description: gui.c.Tr.ToggleSelectionForPatch, + Key: opts.GetKey(opts.Config.Universal.Select), + Handler: self.handleToggleSelectionForPatch, + Description: self.c.Tr.ToggleSelectionForPatch, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Main.ToggleDragSelect), - Handler: gui.handleToggleSelectRange, - Description: gui.c.Tr.ToggleDragSelect, + Key: opts.GetKey(opts.Config.Main.ToggleDragSelect), + Handler: self.handleToggleSelectRange, + Description: self.c.Tr.ToggleDragSelect, }, // Alias 'V' -> 'v' { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Main.ToggleDragSelectAlt), - Handler: gui.handleToggleSelectRange, - Description: gui.c.Tr.ToggleDragSelect, + Key: opts.GetKey(opts.Config.Main.ToggleDragSelectAlt), + Handler: self.handleToggleSelectRange, + Description: self.c.Tr.ToggleDragSelect, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Main.ToggleSelectHunk), - Handler: gui.handleToggleSelectHunk, - Description: gui.c.Tr.ToggleSelectHunk, + Key: opts.GetKey(opts.Config.Main.ToggleSelectHunk), + Handler: self.handleToggleSelectHunk, + Description: self.c.Tr.ToggleSelectHunk, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, Key: gocui.MouseLeft, Modifier: gocui.ModNone, - Handler: gui.handleLBLMouseDown, + Handler: self.handleLBLMouseDown, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, Key: gocui.MouseLeft, Modifier: gocui.ModMotion, - Handler: gui.handleMouseDrag, + Handler: self.handleMouseDrag, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, - Handler: gui.scrollUpMain, + Handler: self.scrollUpMain, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY)}, Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, - Handler: gui.scrollDownMain, + Handler: self.scrollDownMain, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY), string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.ScrollLeft), - Handler: gui.scrollLeftMain, - Description: gui.c.Tr.LcScrollLeft, + Key: opts.GetKey(opts.Config.Universal.ScrollLeft), + Handler: self.scrollLeftMain, + Description: self.c.Tr.LcScrollLeft, }, { ViewName: "main", Contexts: []string{string(context.MAIN_PATCH_BUILDING_CONTEXT_KEY), string(context.MAIN_STAGING_CONTEXT_KEY), string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.ScrollRight), - Handler: gui.scrollRightMain, - Description: gui.c.Tr.LcScrollRight, + Key: opts.GetKey(opts.Config.Universal.ScrollRight), + Handler: self.scrollRightMain, + Description: self.c.Tr.LcScrollRight, }, { ViewName: "main", Contexts: []string{string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.CommitChanges), - Handler: gui.Controllers.Files.HandleCommitPress, - Description: gui.c.Tr.CommitChanges, + Key: opts.GetKey(opts.Config.Files.CommitChanges), + Handler: self.Controllers.Files.HandleCommitPress, + Description: self.c.Tr.CommitChanges, }, { ViewName: "main", Contexts: []string{string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.CommitChangesWithoutHook), - Handler: gui.Controllers.Files.HandleWIPCommitPress, - Description: gui.c.Tr.LcCommitChangesWithoutHook, + Key: opts.GetKey(opts.Config.Files.CommitChangesWithoutHook), + Handler: self.Controllers.Files.HandleWIPCommitPress, + Description: self.c.Tr.LcCommitChangesWithoutHook, }, { ViewName: "main", Contexts: []string{string(context.MAIN_STAGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.CommitChangesWithEditor), - Handler: gui.Controllers.Files.HandleCommitEditorPress, - Description: gui.c.Tr.CommitChangesWithEditor, + Key: opts.GetKey(opts.Config.Files.CommitChangesWithEditor), + Handler: self.Controllers.Files.HandleCommitEditorPress, + Description: self.c.Tr.CommitChangesWithEditor, }, { ViewName: "main", Contexts: []string{string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Return), - Handler: gui.handleEscapeMerge, - Description: gui.c.Tr.ReturnToFilesPanel, + Key: opts.GetKey(opts.Config.Universal.Return), + Handler: self.handleEscapeMerge, + Description: self.c.Tr.ReturnToFilesPanel, }, { ViewName: "main", Contexts: []string{string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Files.OpenMergeTool), - Handler: gui.Controllers.Files.OpenMergeTool, - Description: gui.c.Tr.LcOpenMergeTool, + Key: opts.GetKey(opts.Config.Files.OpenMergeTool), + Handler: self.Controllers.Files.OpenMergeTool, + Description: self.c.Tr.LcOpenMergeTool, }, { ViewName: "main", Contexts: []string{string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Select), - Handler: gui.handlePickHunk, - Description: gui.c.Tr.PickHunk, + Key: opts.GetKey(opts.Config.Universal.Select), + Handler: self.handlePickHunk, + Description: self.c.Tr.PickHunk, }, { ViewName: "main", Contexts: []string{string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Main.PickBothHunks), - Handler: gui.handlePickAllHunks, - Description: gui.c.Tr.PickAllHunks, + Key: opts.GetKey(opts.Config.Main.PickBothHunks), + Handler: self.handlePickAllHunks, + Description: self.c.Tr.PickAllHunks, }, { ViewName: "main", Contexts: []string{string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.PrevBlock), - Handler: gui.handleSelectPrevConflict, - Description: gui.c.Tr.PrevConflict, + Key: opts.GetKey(opts.Config.Universal.PrevBlock), + Handler: self.handleSelectPrevConflict, + Description: self.c.Tr.PrevConflict, }, { ViewName: "main", Contexts: []string{string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.NextBlock), - Handler: gui.handleSelectNextConflict, - Description: gui.c.Tr.NextConflict, + Key: opts.GetKey(opts.Config.Universal.NextBlock), + Handler: self.handleSelectNextConflict, + Description: self.c.Tr.NextConflict, }, { ViewName: "main", Contexts: []string{string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.PrevItem), - Handler: gui.handleSelectPrevConflictHunk, - Description: gui.c.Tr.SelectPrevHunk, + Key: opts.GetKey(opts.Config.Universal.PrevItem), + Handler: self.handleSelectPrevConflictHunk, + Description: self.c.Tr.SelectPrevHunk, }, { ViewName: "main", Contexts: []string{string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.NextItem), - Handler: gui.handleSelectNextConflictHunk, - Description: gui.c.Tr.SelectNextHunk, + Key: opts.GetKey(opts.Config.Universal.NextItem), + Handler: self.handleSelectNextConflictHunk, + Description: self.c.Tr.SelectNextHunk, }, { ViewName: "main", Contexts: []string{string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.PrevBlockAlt), + Key: opts.GetKey(opts.Config.Universal.PrevBlockAlt), Modifier: gocui.ModNone, - Handler: gui.handleSelectPrevConflict, + Handler: self.handleSelectPrevConflict, }, { ViewName: "main", Contexts: []string{string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.NextBlockAlt), + Key: opts.GetKey(opts.Config.Universal.NextBlockAlt), Modifier: gocui.ModNone, - Handler: gui.handleSelectNextConflict, + Handler: self.handleSelectNextConflict, }, { ViewName: "main", Contexts: []string{string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.PrevItemAlt), + Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Modifier: gocui.ModNone, - Handler: gui.handleSelectPrevConflictHunk, + Handler: self.handleSelectPrevConflictHunk, }, { ViewName: "main", Contexts: []string{string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.NextItemAlt), + Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Modifier: gocui.ModNone, - Handler: gui.handleSelectNextConflictHunk, + Handler: self.handleSelectNextConflictHunk, }, { ViewName: "main", Contexts: []string{string(context.MAIN_MERGING_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Undo), - Handler: gui.handleMergeConflictUndo, - Description: gui.c.Tr.LcUndo, + Key: opts.GetKey(opts.Config.Universal.Undo), + Handler: self.handleMergeConflictUndo, + Description: self.c.Tr.LcUndo, }, { ViewName: "branches", Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Select), + Key: opts.GetKey(opts.Config.Universal.Select), // gonna use the exact same handler as the 'n' keybinding because everybody wants this to happen when they checkout a remote branch - Handler: gui.handleNewBranchOffRemoteBranch, - Description: gui.c.Tr.LcCheckout, + Handler: self.handleNewBranchOffRemoteBranch, + Description: self.c.Tr.LcCheckout, }, { ViewName: "branches", Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.New), - Handler: gui.handleNewBranchOffRemoteBranch, - Description: gui.c.Tr.LcNewBranch, + Key: opts.GetKey(opts.Config.Universal.New), + Handler: self.handleNewBranchOffRemoteBranch, + Description: self.c.Tr.LcNewBranch, }, { ViewName: "branches", Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.MergeIntoCurrentBranch), - Handler: guards.OutsideFilterMode(gui.handleMergeRemoteBranch), - Description: gui.c.Tr.LcMergeIntoCurrentBranch, + Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch), + Handler: opts.Guards.OutsideFilterMode(self.handleMergeRemoteBranch), + Description: self.c.Tr.LcMergeIntoCurrentBranch, }, { ViewName: "branches", Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.Remove), - Handler: gui.handleDeleteRemoteBranch, - Description: gui.c.Tr.LcDeleteBranch, + Key: opts.GetKey(opts.Config.Universal.Remove), + Handler: self.handleDeleteRemoteBranch, + Description: self.c.Tr.LcDeleteBranch, }, { ViewName: "branches", Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.RebaseBranch), - Handler: guards.OutsideFilterMode(gui.handleRebaseOntoRemoteBranch), - Description: gui.c.Tr.LcRebaseBranch, + Key: opts.GetKey(opts.Config.Branches.RebaseBranch), + Handler: opts.Guards.OutsideFilterMode(self.handleRebaseOntoRemoteBranch), + Description: self.c.Tr.LcRebaseBranch, }, { ViewName: "branches", Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: gui.getKey(config.Branches.SetUpstream), - Handler: gui.handleSetBranchUpstream, - Description: gui.c.Tr.LcSetUpstream, + Key: opts.GetKey(opts.Config.Branches.SetUpstream), + Handler: self.handleSetBranchUpstream, + Description: self.c.Tr.LcSetUpstream, }, { ViewName: "status", Key: gocui.MouseLeft, Modifier: gocui.ModNone, - Handler: gui.handleStatusClick, + Handler: self.handleStatusClick, }, { ViewName: "search", - Key: gui.getKey(config.Universal.Confirm), + Key: opts.GetKey(opts.Config.Universal.Confirm), Modifier: gocui.ModNone, - Handler: gui.handleSearch, + Handler: self.handleSearch, }, { ViewName: "search", - Key: gui.getKey(config.Universal.Return), + Key: opts.GetKey(opts.Config.Universal.Return), Modifier: gocui.ModNone, - Handler: gui.handleSearchEscape, + Handler: self.handleSearchEscape, }, { ViewName: "confirmation", - Key: gui.getKey(config.Universal.PrevItem), + Key: opts.GetKey(opts.Config.Universal.PrevItem), Modifier: gocui.ModNone, - Handler: gui.scrollUpConfirmationPanel, + Handler: self.scrollUpConfirmationPanel, }, { ViewName: "confirmation", - Key: gui.getKey(config.Universal.NextItem), + Key: opts.GetKey(opts.Config.Universal.NextItem), Modifier: gocui.ModNone, - Handler: gui.scrollDownConfirmationPanel, + Handler: self.scrollDownConfirmationPanel, }, { ViewName: "confirmation", - Key: gui.getKey(config.Universal.PrevItemAlt), + Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Modifier: gocui.ModNone, - Handler: gui.scrollUpConfirmationPanel, + Handler: self.scrollUpConfirmationPanel, }, { ViewName: "confirmation", - Key: gui.getKey(config.Universal.NextItemAlt), + Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Modifier: gocui.ModNone, - Handler: gui.scrollDownConfirmationPanel, + Handler: self.scrollDownConfirmationPanel, }, { ViewName: "files", Contexts: []string{string(context.SUBMODULES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.CopyToClipboard), - Handler: gui.handleCopySelectedSideContextItemToClipboard, - Description: gui.c.Tr.LcCopySubmoduleNameToClipboard, + Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Handler: self.handleCopySelectedSideContextItemToClipboard, + Description: self.c.Tr.LcCopySubmoduleNameToClipboard, }, { ViewName: "files", Contexts: []string{string(context.FILES_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.ToggleWhitespaceInDiffView), - Handler: gui.toggleWhitespaceInDiffView, - Description: gui.c.Tr.ToggleWhitespaceInDiffView, + Key: opts.GetKey(opts.Config.Universal.ToggleWhitespaceInDiffView), + Handler: self.toggleWhitespaceInDiffView, + Description: self.c.Tr.ToggleWhitespaceInDiffView, }, { ViewName: "", - Key: gui.getKey(config.Universal.IncreaseContextInDiffView), - Handler: gui.IncreaseContextInDiffView, - Description: gui.c.Tr.IncreaseContextInDiffView, + Key: opts.GetKey(opts.Config.Universal.IncreaseContextInDiffView), + Handler: self.IncreaseContextInDiffView, + Description: self.c.Tr.IncreaseContextInDiffView, }, { ViewName: "", - Key: gui.getKey(config.Universal.DecreaseContextInDiffView), - Handler: gui.DecreaseContextInDiffView, - Description: gui.c.Tr.DecreaseContextInDiffView, + Key: opts.GetKey(opts.Config.Universal.DecreaseContextInDiffView), + Handler: self.DecreaseContextInDiffView, + Description: self.c.Tr.DecreaseContextInDiffView, }, { ViewName: "extras", Key: gocui.MouseWheelUp, - Handler: gui.scrollUpExtra, + Handler: self.scrollUpExtra, }, { ViewName: "extras", Key: gocui.MouseWheelDown, - Handler: gui.scrollDownExtra, + Handler: self.scrollDownExtra, }, { ViewName: "extras", - Key: gui.getKey(config.Universal.ExtrasMenu), - Handler: gui.handleCreateExtrasMenuPanel, - Description: gui.c.Tr.LcOpenExtrasMenu, + Key: opts.GetKey(opts.Config.Universal.ExtrasMenu), + Handler: self.handleCreateExtrasMenuPanel, + Description: self.c.Tr.LcOpenExtrasMenu, OpensMenu: true, }, { ViewName: "extras", Tag: "navigation", Contexts: []string{string(context.COMMAND_LOG_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.PrevItemAlt), + Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Modifier: gocui.ModNone, - Handler: gui.scrollUpExtra, + Handler: self.scrollUpExtra, }, { ViewName: "extras", Tag: "navigation", Contexts: []string{string(context.COMMAND_LOG_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.PrevItem), + Key: opts.GetKey(opts.Config.Universal.PrevItem), Modifier: gocui.ModNone, - Handler: gui.scrollUpExtra, + Handler: self.scrollUpExtra, }, { ViewName: "extras", Tag: "navigation", Contexts: []string{string(context.COMMAND_LOG_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.NextItem), + Key: opts.GetKey(opts.Config.Universal.NextItem), Modifier: gocui.ModNone, - Handler: gui.scrollDownExtra, + Handler: self.scrollDownExtra, }, { ViewName: "extras", Tag: "navigation", Contexts: []string{string(context.COMMAND_LOG_CONTEXT_KEY)}, - Key: gui.getKey(config.Universal.NextItemAlt), + Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Modifier: gocui.ModNone, - Handler: gui.scrollDownExtra, + Handler: self.scrollDownExtra, }, { ViewName: "extras", Tag: "navigation", Key: gocui.MouseLeft, Modifier: gocui.ModNone, - Handler: gui.handleFocusCommandLog, + Handler: self.handleFocusCommandLog, }, } - keybindingsOpts := types.KeybindingsOpts{ - GetKey: gui.getKey, - Config: config, - Guards: guards, - } - mouseKeybindings := []*gocui.ViewMouseBinding{} - for _, c := range gui.State.Contexts.Flatten() { + for _, c := range self.State.Contexts.Flatten() { viewName := c.GetViewName() contextKey := c.GetKey() - for _, binding := range c.GetKeybindings(keybindingsOpts) { + for _, binding := range c.GetKeybindings(opts) { // TODO: move all mouse keybindings into the mouse keybindings approach below if !gocui.IsMouseKey(binding.Key) && contextKey != context.GLOBAL_CONTEXT_KEY { binding.Contexts = []string{string(contextKey)} @@ -1346,7 +1247,7 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin bindings = append(bindings, binding) } - for _, binding := range c.GetMouseKeybindings(keybindingsOpts) { + for _, binding := range c.GetMouseKeybindings(opts) { if contextKey != context.GLOBAL_CONTEXT_KEY { binding.FromContext = string(contextKey) } @@ -1356,12 +1257,12 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin for _, viewName := range []string{"status", "branches", "files", "commits", "commitFiles", "stash", "menu"} { bindings = append(bindings, []*types.Binding{ - {ViewName: viewName, Key: gui.getKey(config.Universal.PrevBlock), Modifier: gocui.ModNone, Handler: gui.previousSideWindow}, - {ViewName: viewName, Key: gui.getKey(config.Universal.NextBlock), Modifier: gocui.ModNone, Handler: gui.nextSideWindow}, - {ViewName: viewName, Key: gui.getKey(config.Universal.PrevBlockAlt), Modifier: gocui.ModNone, Handler: gui.previousSideWindow}, - {ViewName: viewName, Key: gui.getKey(config.Universal.NextBlockAlt), Modifier: gocui.ModNone, Handler: gui.nextSideWindow}, - {ViewName: viewName, Key: gui.getKey(config.Universal.PrevBlockAlt2), Modifier: gocui.ModNone, Handler: gui.previousSideWindow}, - {ViewName: viewName, Key: gui.getKey(config.Universal.NextBlockAlt2), Modifier: gocui.ModNone, Handler: gui.nextSideWindow}, + {ViewName: viewName, Key: opts.GetKey(opts.Config.Universal.PrevBlock), Modifier: gocui.ModNone, Handler: self.previousSideWindow}, + {ViewName: viewName, Key: opts.GetKey(opts.Config.Universal.NextBlock), Modifier: gocui.ModNone, Handler: self.nextSideWindow}, + {ViewName: viewName, Key: opts.GetKey(opts.Config.Universal.PrevBlockAlt), Modifier: gocui.ModNone, Handler: self.previousSideWindow}, + {ViewName: viewName, Key: opts.GetKey(opts.Config.Universal.NextBlockAlt), Modifier: gocui.ModNone, Handler: self.nextSideWindow}, + {ViewName: viewName, Key: opts.GetKey(opts.Config.Universal.PrevBlockAlt2), Modifier: gocui.ModNone, Handler: self.previousSideWindow}, + {ViewName: viewName, Key: opts.GetKey(opts.Config.Universal.NextBlockAlt2), Modifier: gocui.ModNone, Handler: self.nextSideWindow}, }...) } @@ -1374,26 +1275,26 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin for i, window := range windows { bindings = append(bindings, &types.Binding{ ViewName: "", - Key: gui.getKey(config.Universal.JumpToBlock[i]), + Key: opts.GetKey(opts.Config.Universal.JumpToBlock[i]), Modifier: gocui.ModNone, - Handler: gui.goToSideWindow(window)}) + Handler: self.goToSideWindow(window)}) } } - for viewName := range gui.State.Contexts.InitialViewTabContextMap() { + for viewName := range self.State.Contexts.InitialViewTabContextMap() { bindings = append(bindings, []*types.Binding{ { ViewName: viewName, - Key: gui.getKey(config.Universal.NextTab), - Handler: gui.handleNextTab, - Description: gui.c.Tr.LcNextTab, + Key: opts.GetKey(opts.Config.Universal.NextTab), + Handler: self.handleNextTab, + Description: self.c.Tr.LcNextTab, Tag: "navigation", }, { ViewName: viewName, - Key: gui.getKey(config.Universal.PrevTab), - Handler: gui.handlePrevTab, - Description: gui.c.Tr.LcPrevTab, + Key: opts.GetKey(opts.Config.Universal.PrevTab), + Handler: self.handlePrevTab, + Description: self.c.Tr.LcPrevTab, Tag: "navigation", }, }...) diff --git a/pkg/gui/modes.go b/pkg/gui/modes.go index 6424c8540..882e6d863 100644 --- a/pkg/gui/modes.go +++ b/pkg/gui/modes.go @@ -73,7 +73,7 @@ func (gui *Gui) modeStatuses() []modeStatus { formatWorkingTreeState(workingTreeState), style.FgYellow, ) }, - reset: gui.helpers.Rebase.AbortMergeOrRebaseWithConfirm, + reset: gui.helpers.MergeAndRebase.AbortMergeOrRebaseWithConfirm, }, { isActive: func() bool { diff --git a/pkg/gui/patch_options_panel.go b/pkg/gui/patch_options_panel.go index d69dbda27..81d232da2 100644 --- a/pkg/gui/patch_options_panel.go +++ b/pkg/gui/patch_options_panel.go @@ -102,7 +102,7 @@ func (gui *Gui) handleDeletePatchFromCommit() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.RemovePatchFromCommit) err := gui.git.Patch.DeletePatchesFromCommit(gui.State.Model.Commits, commitIndex) - return gui.helpers.Rebase.CheckMergeOrRebase(err) + return gui.helpers.MergeAndRebase.CheckMergeOrRebase(err) }) } @@ -119,7 +119,7 @@ func (gui *Gui) handleMovePatchToSelectedCommit() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.MovePatchToSelectedCommit) err := gui.git.Patch.MovePatchToSelectedCommit(gui.State.Model.Commits, commitIndex, gui.State.Contexts.BranchCommits.GetSelectedLineIdx()) - return gui.helpers.Rebase.CheckMergeOrRebase(err) + return gui.helpers.MergeAndRebase.CheckMergeOrRebase(err) }) } @@ -137,7 +137,7 @@ func (gui *Gui) handleMovePatchIntoWorkingTree() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoIndex) err := gui.git.Patch.MovePatchIntoIndex(gui.State.Model.Commits, commitIndex, stash) - return gui.helpers.Rebase.CheckMergeOrRebase(err) + return gui.helpers.MergeAndRebase.CheckMergeOrRebase(err) }) } @@ -167,7 +167,7 @@ func (gui *Gui) handlePullPatchIntoNewCommit() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.MovePatchIntoNewCommit) err := gui.git.Patch.PullPatchIntoNewCommit(gui.State.Model.Commits, commitIndex) - return gui.helpers.Rebase.CheckMergeOrRebase(err) + return gui.helpers.MergeAndRebase.CheckMergeOrRebase(err) }) } diff --git a/pkg/gui/pull_request_menu_panel.go b/pkg/gui/pull_request_menu_panel.go deleted file mode 100644 index 1f63c6306..000000000 --- a/pkg/gui/pull_request_menu_panel.go +++ /dev/null @@ -1,78 +0,0 @@ -package gui - -import ( - "fmt" - - "github.com/jesseduffield/lazygit/pkg/commands/hosting_service" - "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - -func (gui *Gui) createPullRequestMenu(selectedBranch *models.Branch, checkedOutBranch *models.Branch) error { - menuItems := make([]*types.MenuItem, 0, 4) - - fromToDisplayStrings := func(from string, to string) []string { - return []string{fmt.Sprintf("%s 鈫 %s", from, to)} - } - - menuItemsForBranch := func(branch *models.Branch) []*types.MenuItem { - return []*types.MenuItem{ - { - DisplayStrings: fromToDisplayStrings(branch.Name, gui.c.Tr.LcDefaultBranch), - OnPress: func() error { - return gui.createPullRequest(branch.Name, "") - }, - }, - { - DisplayStrings: fromToDisplayStrings(branch.Name, gui.c.Tr.LcSelectBranch), - OnPress: func() error { - return gui.c.Prompt(types.PromptOpts{ - Title: branch.Name + " 鈫", - FindSuggestionsFunc: gui.helpers.Suggestions.GetBranchNameSuggestionsFunc(), - HandleConfirm: func(targetBranchName string) error { - return gui.createPullRequest(branch.Name, targetBranchName) - }}, - ) - }, - }, - } - } - - if selectedBranch != checkedOutBranch { - menuItems = append(menuItems, - &types.MenuItem{ - DisplayStrings: fromToDisplayStrings(checkedOutBranch.Name, selectedBranch.Name), - OnPress: func() error { - return gui.createPullRequest(checkedOutBranch.Name, selectedBranch.Name) - }, - }, - ) - menuItems = append(menuItems, menuItemsForBranch(checkedOutBranch)...) - } - - menuItems = append(menuItems, menuItemsForBranch(selectedBranch)...) - - return gui.c.Menu(types.CreateMenuOptions{Title: fmt.Sprintf(gui.c.Tr.CreatePullRequestOptions), Items: menuItems}) -} - -func (gui *Gui) createPullRequest(from string, to string) error { - hostingServiceMgr := gui.getHostingServiceMgr() - url, err := hostingServiceMgr.GetPullRequestURL(from, to) - if err != nil { - return gui.c.Error(err) - } - - gui.c.LogAction(gui.c.Tr.Actions.OpenPullRequest) - - if err := gui.os.OpenLink(url); err != nil { - return gui.c.Error(err) - } - - return nil -} - -func (gui *Gui) getHostingServiceMgr() *hosting_service.HostingServiceMgr { - remoteUrl := gui.git.Config.GetRemoteURL() - configServices := gui.c.UserConfig.Services - return hosting_service.NewHostingServiceMgr(gui.Log, gui.Tr, remoteUrl, configServices) -} diff --git a/pkg/gui/reflog_panel.go b/pkg/gui/reflog_panel.go index 472c073cd..97fd1dd4f 100644 --- a/pkg/gui/reflog_panel.go +++ b/pkg/gui/reflog_panel.go @@ -65,10 +65,9 @@ func (gui *Gui) handleViewReflogCommitFiles() error { } return gui.SwitchToCommitFilesContext(controllers.SwitchToCommitFilesContextOpts{ - RefName: commit.Sha, - CanRebase: false, - Context: gui.State.Contexts.ReflogCommits, - WindowName: "commits", + RefName: commit.Sha, + CanRebase: false, + Context: gui.State.Contexts.ReflogCommits, }) } diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go index 84d58d815..215028609 100644 --- a/pkg/gui/refresh.go +++ b/pkg/gui/refresh.go @@ -215,7 +215,7 @@ func (gui *Gui) refreshCommitsWithLimit() error { FilterPath: gui.State.Modes.Filtering.GetPath(), IncludeRebaseCommits: true, RefName: gui.refForLog(), - All: gui.ShowWholeGitGraph, + All: gui.State.Contexts.BranchCommits.GetShowWholeGitGraph(), }, ) if err != nil { @@ -408,7 +408,7 @@ func (gui *Gui) refreshStateFiles() error { } if gui.git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE && conflictFileCount == 0 && prevConflictFileCount > 0 { - gui.OnUIThread(func() error { return gui.helpers.Rebase.PromptToContinueRebase() }) + gui.OnUIThread(func() error { return gui.helpers.MergeAndRebase.PromptToContinueRebase() }) } fileTreeViewModel.RWMutex.Lock() @@ -526,7 +526,7 @@ func (gui *Gui) refreshStatus() { gui.Mutexes.RefreshingStatusMutex.Lock() defer gui.Mutexes.RefreshingStatusMutex.Unlock() - currentBranch := gui.getCheckedOutBranch() + currentBranch := gui.helpers.Refs.GetCheckedOutRef() if currentBranch == nil { // need to wait for branches to refresh return diff --git a/pkg/gui/remote_branches_panel.go b/pkg/gui/remote_branches_panel.go index 243a7ca4d..eeed4cd13 100644 --- a/pkg/gui/remote_branches_panel.go +++ b/pkg/gui/remote_branches_panel.go @@ -34,7 +34,7 @@ func (gui *Gui) handleRemoteBranchesEscape() error { func (gui *Gui) handleMergeRemoteBranch() error { selectedBranchName := gui.State.Contexts.RemoteBranches.GetSelected().FullName() - return gui.mergeBranchIntoCheckedOutBranch(selectedBranchName) + return gui.helpers.MergeAndRebase.MergeRefIntoCheckedOutBranch(selectedBranchName) } func (gui *Gui) handleDeleteRemoteBranch() error { @@ -63,12 +63,12 @@ func (gui *Gui) handleDeleteRemoteBranch() error { func (gui *Gui) handleRebaseOntoRemoteBranch() error { selectedBranchName := gui.State.Contexts.RemoteBranches.GetSelected().FullName() - return gui.handleRebaseOntoBranch(selectedBranchName) + return gui.helpers.MergeAndRebase.RebaseOntoRef(selectedBranchName) } func (gui *Gui) handleSetBranchUpstream() error { selectedBranch := gui.State.Contexts.RemoteBranches.GetSelected() - checkedOutBranch := gui.getCheckedOutBranch() + checkedOutBranch := gui.helpers.Refs.GetCheckedOutRef() message := utils.ResolvePlaceholderString( gui.c.Tr.SetUpstreamMessage, @@ -101,15 +101,6 @@ func (gui *Gui) handleCreateResetToRemoteBranchMenu() error { return gui.helpers.Refs.CreateGitResetMenu(selectedBranch.FullName()) } -func (gui *Gui) handleEnterRemoteBranch() error { - selectedBranch := gui.State.Contexts.RemoteBranches.GetSelected() - if selectedBranch == nil { - return nil - } - - return gui.switchToSubCommitsContext(selectedBranch.RefName()) -} - func (gui *Gui) handleNewBranchOffRemoteBranch() error { selectedBranch := gui.State.Contexts.RemoteBranches.GetSelected() if selectedBranch == nil { diff --git a/pkg/gui/stash_panel.go b/pkg/gui/stash_panel.go index e51fcc054..6da862004 100644 --- a/pkg/gui/stash_panel.go +++ b/pkg/gui/stash_panel.go @@ -37,8 +37,6 @@ func (gui *Gui) handleStashApply() error { return nil } - skipStashWarning := gui.c.UserConfig.Gui.SkipStashWarning - apply := func() error { gui.c.LogAction(gui.c.Tr.Actions.Stash) err := gui.git.Stash.Apply(stashEntry.Index) @@ -49,7 +47,7 @@ func (gui *Gui) handleStashApply() error { return nil } - if skipStashWarning { + if gui.c.UserConfig.Gui.SkipStashWarning { return apply() } @@ -68,8 +66,6 @@ func (gui *Gui) handleStashPop() error { return nil } - skipStashWarning := gui.c.UserConfig.Gui.SkipStashWarning - pop := func() error { gui.c.LogAction(gui.c.Tr.Actions.Stash) err := gui.git.Stash.Pop(stashEntry.Index) @@ -80,7 +76,7 @@ func (gui *Gui) handleStashPop() error { return nil } - if skipStashWarning { + if gui.c.UserConfig.Gui.SkipStashWarning { return pop() } @@ -125,10 +121,9 @@ func (gui *Gui) handleViewStashFiles() error { } return gui.SwitchToCommitFilesContext(controllers.SwitchToCommitFilesContextOpts{ - RefName: stashEntry.RefName(), - CanRebase: false, - Context: gui.State.Contexts.Stash, - WindowName: "stash", + RefName: stashEntry.RefName(), + CanRebase: false, + Context: gui.State.Contexts.Stash, }) } diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go index fd1d75133..072f41da9 100644 --- a/pkg/gui/status_panel.go +++ b/pkg/gui/status_panel.go @@ -30,7 +30,7 @@ func (gui *Gui) handleCheckForUpdate() error { func (gui *Gui) handleStatusClick() error { // TODO: move into some abstraction (status is currently not a listViewContext where a lot of this code lives) - currentBranch := gui.getCheckedOutBranch() + currentBranch := gui.helpers.Refs.GetCheckedOutRef() if currentBranch == nil { // need to wait for branches to refresh return nil @@ -48,7 +48,7 @@ func (gui *Gui) handleStatusClick() error { case enums.REBASE_MODE_REBASING, enums.REBASE_MODE_MERGING: workingTreeStatus := fmt.Sprintf("(%s)", formatWorkingTreeState(workingTreeState)) if cursorInSubstring(cx, upstreamStatus+" ", workingTreeStatus) { - return gui.helpers.Rebase.CreateRebaseOptionsMenu() + return gui.helpers.MergeAndRebase.CreateRebaseOptionsMenu() } if cursorInSubstring(cx, upstreamStatus+" "+workingTreeStatus+" ", repoName) { return gui.handleCreateRecentReposMenu() @@ -74,7 +74,6 @@ func formatWorkingTreeState(rebaseMode enums.RebaseMode) string { } func (gui *Gui) statusRenderToMain() error { - // TODO: move into some abstraction (status is currently not a listViewContext where a lot of this code lives) dashboardString := strings.Join( []string{ lazygitTitle(), @@ -114,9 +113,8 @@ func (gui *Gui) askForConfigFile(action func(file string) error) error { } } return gui.c.Menu(types.CreateMenuOptions{ - Title: gui.c.Tr.SelectConfigFile, - Items: menuItems, - HideCancel: true, + Title: gui.c.Tr.SelectConfigFile, + Items: menuItems, }) } } diff --git a/pkg/gui/sub_commits_panel.go b/pkg/gui/sub_commits_panel.go index ddcb8f096..5b5637edc 100644 --- a/pkg/gui/sub_commits_panel.go +++ b/pkg/gui/sub_commits_panel.go @@ -63,10 +63,9 @@ func (gui *Gui) handleViewSubCommitFiles() error { } return gui.SwitchToCommitFilesContext(controllers.SwitchToCommitFilesContextOpts{ - RefName: commit.Sha, - CanRebase: false, - Context: gui.State.Contexts.SubCommits, - WindowName: "branches", + RefName: commit.Sha, + CanRebase: false, + Context: gui.State.Contexts.SubCommits, }) } diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 748a2484b..9c13dcd67 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -9,7 +9,7 @@ import ( "gopkg.in/ozeidan/fuzzy-patricia.v3/patricia" ) -type ControllerCommon struct { +type HelperCommon struct { *common.Common IGuiCommon } From 3188526ecb1e48327249a830173de7ab5ce5978a Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 10:39:14 +1100 Subject: [PATCH 057/385] fix cheatsheet crash --- docs/keybindings/Keybindings_en.md | 20 ++++++++++---------- docs/keybindings/Keybindings_nl.md | 19 ++++++++++--------- docs/keybindings/Keybindings_pl.md | 20 ++++++++++---------- docs/keybindings/Keybindings_zh.md | 20 ++++++++++---------- pkg/cheatsheet/generate.go | 2 +- pkg/gui/controllers/helpers/helpers.go | 14 ++++++++++++++ pkg/gui/keybindings.go | 13 +++++++++++-- 7 files changed, 66 insertions(+), 42 deletions(-) diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index 435f48806..cee94e0a3 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -20,6 +20,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct @: open command log menu }: Increase the size of the context shown around changes in the diff view {: Decrease the size of the context shown around changes in the diff view + :: execute custom command z: undo (via reflog) (experimental) ctrl+z: redo (via reflog) (experimental) P: push @@ -41,6 +42,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Branches Panel (Branches Tab) + i: show git-flow options + ctrl+o: copy branch name to clipboard space: checkout o: create pull request O: create pull request options @@ -51,11 +54,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct d: delete branch r: rebase checked-out branch onto this branch M: merge into currently checked out branch - i: show git-flow options f: fast-forward this branch from its upstream g: view reset options R: rename branch - ctrl+o: copy branch name to clipboard enter: view commits@@ -64,13 +65,13 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directesc: Return to remotes list g: view reset options - enter: view commits space: checkout n: new branch M: merge into currently checked out branch d: delete branch r: rebase checked-out branch onto this branch u: set as upstream of checked-out branch + enter: view commits## Branches Panel (Remotes Tab) @@ -122,12 +123,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Commits Panel (Commits)- c: copy commit (cherry-pick) ctrl+o: copy commit SHA to clipboard - C: copy commit range (cherry-pick) - v: paste commits (cherry-pick) - n: create new branch off of commit ctrl+r: reset cherry-picked (copied) commits selection + b: view bisect options s: squash down f: fixup commit r: reword commit @@ -141,6 +139,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+k: move commit up one A: amend commit with staged changes t: revert commit + n: create new branch off of commit + c: copy commit (cherry-pick) + C: copy commit range (cherry-pick) + v: paste commits (cherry-pick) ctrl+l: open log menu g: reset to this commit enter: view commit's files @@ -148,7 +150,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct T: tag commit ctrl+y: copy commit message to clipboard o: open commit in browser - b: view bisect options## Commits Panel (Reflog Tab) @@ -173,7 +174,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directD: view reset options - f: fetch ctrl+o: copy the file name to the clipboard ctrl+w: Toggle whether or not whitespace changes are shown in the diff view space: toggle staged @@ -191,10 +191,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct S: view stash options a: stage/unstage all enter: stage individual hunks/lines for file, or collapse/expand for directory - :: execute custom command g: view upstream reset options `: toggle file tree view M: open external merge tool (git mergetool) + f: fetch## Files Panel (Submodules) diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index b25c18fc5..dde2d47a4 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -21,6 +21,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct @: open command log menu }: Increase the size of the context shown around changes in the diff view {: Decrease the size of the context shown around changes in the diff view + :: voor aangepaste commando uit z: ongedaan maken (via reflog) (experimenteel) ctrl+z: redo (via reflog) (experimenteel) P: push @@ -42,6 +43,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Branches Paneel (Branches Tabblad)+ i: laat git-flow opties zien + ctrl+o: kopieer branch name naar klembord space: uitchecken o: maak een pull-request O: bekijk opties voor pull-aanvraag @@ -52,11 +55,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct d: verwijder branch r: rebase branch M: merge in met huidige checked out branch - i: laat git-flow opties zien f: fast-forward deze branch vanaf zijn upstream g: bekijk reset opties R: hernoem branch - ctrl+o: kopieer branch name naar klembord enter: bekijk commits@@ -65,13 +66,13 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directesc: ga terug naar remotes lijst g: bekijk reset opties - enter: bekijk commits space: uitchecken n: nieuwe branch M: merge in met huidige checked out branch d: verwijder branch r: rebase branch u: stel in als upstream van uitgecheckte branch + enter: bekijk commits## Branches Paneel (Remotes Tabblad) @@ -123,12 +124,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Commits Paneel (Commits)- c: kopieer commit (cherry-pick) ctrl+o: kopieer commit SHA naar klembord - C: kopieer commit reeks (cherry-pick) - v: plak commits (cherry-pick) - n: cre毛er nieuwe branch van commit ctrl+r: reset cherry-picked (gekopieerde) commits selectie + b: view bisect options s: squash beneden f: Fixup commit r: hernoem commit @@ -142,6 +140,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+k: verplaats commit 1 naar boven A: wijzig commit met staged veranderingen t: commit ongedaan maken + n: cre毛er nieuwe branch van commit + c: kopieer commit (cherry-pick) + C: kopieer commit reeks (cherry-pick) + v: plak commits (cherry-pick) ctrl+l: open log menu g: reset naar deze commit enter: bekijk gecommite bestanden @@ -149,7 +151,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct T: tag commit ctrl+y: kopieer commit bericht naar klembord o: open commit in browser - b: view bisect options## Commits Paneel (Reflog Tabblad) @@ -186,10 +187,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct S: bekijk stash opties a: toggle staged alle enter: stage individuele hunks/lijnen - :: voor aangepaste commando uit g: bekijk upstream reset opties `: toggle bestandsboom weergave M: open external merge tool (git mergetool) + f: fetch+ i: show git-flow options + ctrl+o: copy branch name to clipboard space: prze艂膮cz o: utw贸rz 偶膮danie pobrania O: utw贸rz opcje 偶膮dania 艣ci膮gni臋cia @@ -51,11 +54,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct d: usu艅 ga艂膮藕 r: zmiana bazy ga艂臋zi M: scal do obecnej ga艂臋zi - i: show git-flow options f: fast-forward this branch from its upstream g: wy艣wietl opcje resetu R: rename branch - ctrl+o: copy branch name to clipboard enter: view commits@@ -64,13 +65,13 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directesc: wr贸膰 do listy repozytori贸w zdalnych g: wy艣wietl opcje resetu - enter: view commits space: prze艂膮cz n: nowa ga艂膮藕 M: scal do obecnej ga艂臋zi d: usu艅 ga艂膮藕 r: zmiana bazy ga艂臋zi u: set as upstream of checked-out branch + enter: view commits## Ga艂臋zie Panel (Remotes Tab) @@ -122,12 +123,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Commity Panel (Commity)- c: kopiuj commit (przebieranie) ctrl+o: copy commit SHA to clipboard - C: kopiuj zakres commit贸w (przebieranie) - v: wklej commity (przebieranie) - n: create new branch off of commit ctrl+r: reset cherry-picked (copied) commits selection + b: view bisect options s: 艣ci艣nij f: napraw commit r: zmie艅 nazw臋 commita @@ -141,6 +139,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+k: przenie艣 commit 1 w g贸r臋 A: popraw commit zmianami z poczekalni t: odwr贸膰 commit + n: create new branch off of commit + c: kopiuj commit (przebieranie) + C: kopiuj zakres commit贸w (przebieranie) + v: wklej commity (przebieranie) ctrl+l: open log menu g: zresetuj do tego commita enter: przegl膮daj pliki commita @@ -148,7 +150,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct T: tag commit ctrl+y: copy commit message to clipboard o: open commit in browser - b: view bisect options## Commity Panel (Reflog Tab) @@ -173,7 +174,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directD: wy艣wietl opcje resetu - f: pobierz ctrl+o: copy the file name to the clipboard ctrl+w: Toggle whether or not whitespace changes are shown in the diff view space: prze艂膮cz stan poczekalni @@ -191,10 +191,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct S: wy艣wietl opcje schowka a: prze艂膮cz stan poczekalni wszystkich enter: zatwierd藕 pojedyncze linie - :: wykonaj w艂asn膮 komend臋 g: view upstream reset options `: toggle file tree view M: open external merge tool (git mergetool) + f: pobierz## Pliki Panel (Submodules) diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index cec585c66..de1915ba1 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -20,6 +20,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct @: 鎵撳紑鍛戒护鏃ュ織鑿滃崟 }: Increase the size of the context shown around changes in the diff view {: Decrease the size of the context shown around changes in the diff view + :: 鎵ц鑷畾涔夊懡浠 z: 锛堥氳繃 reflog锛夋挙閿銆屽疄楠屽姛鑳姐 ctrl+z: 锛堥氳繃 reflog锛夐噸鍋氥屽疄楠屽姛鑳姐 P: 鎺ㄩ @@ -41,6 +42,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## 鍒嗘敮 闈㈡澘 (鍒嗘敮鏍囩)+ i: 鏄剧ず git-flow 閫夐」 + ctrl+o: 灏嗗垎鏀悕绉板鍒跺埌鍓创鏉 space: 妫鍑 o: 鍒涘缓鎶撳彇璇锋眰 O: 鍒涘缓鎶撳彇璇锋眰閫夐」 @@ -51,11 +54,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct d: 鍒犻櫎鍒嗘敮 r: 灏嗗凡妫鍑虹殑鍒嗘敮鍙樺熀鍒拌鍒嗘敮 M: 鍚堝苟鍒板綋鍓嶆鍑虹殑鍒嗘敮 - i: 鏄剧ず git-flow 閫夐」 f: 浠庝笂娓稿揩杩涙鍒嗘敮 g: 鏌ョ湅閲嶇疆閫夐」 R: 閲嶅懡鍚嶅垎鏀 - ctrl+o: 灏嗗垎鏀悕绉板鍒跺埌鍓创鏉 enter: 鏌ョ湅鎻愪氦@@ -64,13 +65,13 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directesc: 杩斿洖杩滅▼浠撳簱鍒楄〃 g: 鏌ョ湅閲嶇疆閫夐」 - enter: 鏌ョ湅鎻愪氦 space: 妫鍑 n: 鏂板垎鏀 M: 鍚堝苟鍒板綋鍓嶆鍑虹殑鍒嗘敮 d: 鍒犻櫎鍒嗘敮 r: 灏嗗凡妫鍑虹殑鍒嗘敮鍙樺熀鍒拌鍒嗘敮 u: 璁剧疆涓烘鍑哄垎鏀殑涓婃父 + enter: 鏌ョ湅鎻愪氦## 鍒嗘敮 闈㈡澘 (杩滅▼椤甸潰) @@ -122,12 +123,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## 鎻愪氦 闈㈡澘 (鎻愪氦)- c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 - C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 - v: 绮樿创鎻愪氦锛堟嫞閫夛級 - n: 浠庢彁浜ゅ垱寤烘柊鍒嗘敮 ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 + b: view bisect options s: 鍚戜笅鍘嬬缉 f: 淇鎻愪氦锛坒ixup锛 r: 鏀瑰啓鎻愪氦 @@ -141,6 +139,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+k: 涓婄Щ鎻愪氦 A: 鐢ㄥ凡鏆傚瓨鐨勬洿鏀规潵淇ˉ鎻愪氦 t: 杩樺師鎻愪氦 + n: 浠庢彁浜ゅ垱寤烘柊鍒嗘敮 + c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 + C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 + v: 绮樿创鎻愪氦锛堟嫞閫夛級 ctrl+l: open log menu g: 閲嶇疆涓烘鎻愪氦 enter: 鏌ョ湅鎻愪氦鐨勬枃浠 @@ -148,7 +150,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct T: 鏍囩鎻愪氦 ctrl+y: 灏嗘彁浜ゆ秷鎭鍒跺埌鍓创鏉 o: open commit in browser - b: view bisect options## 鎻愪氦 闈㈡澘 (Reflog) @@ -173,7 +174,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directD: 鏌ョ湅閲嶇疆閫夐」 - f: 鎶撳彇 ctrl+o: 灏嗘枃浠跺悕澶嶅埗鍒板壀璐存澘 ctrl+w: 鍒囨崲鏄惁鍦ㄥ樊寮傝鍥句腑鏄剧ず绌虹櫧鏇存敼 space: 鍒囨崲鏆傚瓨鐘舵 @@ -191,10 +191,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct S: 鏌ョ湅闅愯棌閫夐」 a: 鍒囨崲鎵鏈夋枃浠剁殑鏆傚瓨鐘舵 enter: 鏆傚瓨鍗曚釜 鍧/琛 鐢ㄤ簬鏂囦欢, 鎴 鎶樺彔/灞曞紑 鐩綍 - :: 鎵ц鑷畾涔夊懡浠 g: 鏌ョ湅涓婃父閲嶇疆閫夐」 `: 鍒囨崲鏂囦欢鏍戣鍥 M: 鎵撳紑鍚堝苟宸ュ叿 + f: 鎶撳彇## 鏂囦欢 闈㈡澘 (瀛愭ā鍧) diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index f499a2f58..47de22a40 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -124,7 +124,7 @@ func formatBinding(binding *types.Binding) string { func getBindingSections(mApp *app.App) []*bindingSection { bindingSections := []*bindingSection{} - bindings, _ := mApp.Gui.GetInitialKeybindings() + bindings := mApp.Gui.GetCheatsheetKeybindings() type contextAndViewType struct { subtitle string diff --git a/pkg/gui/controllers/helpers/helpers.go b/pkg/gui/controllers/helpers/helpers.go index 65f686ade..2ca4fbd40 100644 --- a/pkg/gui/controllers/helpers/helpers.go +++ b/pkg/gui/controllers/helpers/helpers.go @@ -11,3 +11,17 @@ type Helpers struct { CherryPick *CherryPickHelper Host *HostHelper } + +func NewStubHelpers() *Helpers { + return &Helpers{ + Refs: &RefsHelper{}, + Bisect: &BisectHelper{}, + Suggestions: &SuggestionsHelper{}, + Files: &FilesHelper{}, + WorkingTree: &WorkingTreeHelper{}, + Tags: &TagsHelper{}, + MergeAndRebase: &MergeAndRebaseHelper{}, + CherryPick: &CherryPickHelper{}, + Host: &HostHelper{}, + } +} diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 25433eca5..a2dd7a419 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -10,6 +10,7 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/constants" "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -194,6 +195,16 @@ func (gui *Gui) noPopupPanel(f func() error) func() error { } } +// only to be called from the cheatsheet generate script. This mutates the Gui struct. +func (self *Gui) GetCheatsheetKeybindings() []*types.Binding { + self.helpers = helpers.NewStubHelpers() + self.State = &GuiRepoState{} + self.State.Contexts = self.contextTree() + self.resetControllers() + bindings, _ := self.GetInitialKeybindings() + return bindings +} + // renaming receiver to 'self' to aid refactoring. Will probably end up moving all Gui handlers to this pattern eventually. func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBinding) { config := self.c.UserConfig.Keybinding @@ -1306,8 +1317,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi func (gui *Gui) resetKeybindings() error { gui.g.DeleteAllKeybindings() - bindings := gui.GetCustomCommandKeybindings() - bindings, mouseBindings := gui.GetInitialKeybindings() // prepending because we want to give our custom keybindings precedence over default keybindings From 41527270ed9270ef6c463866e9c761f2285af857 Mon Sep 17 00:00:00 2001 From: Jesse DuffieldDate: Sun, 13 Feb 2022 10:48:41 +1100 Subject: [PATCH 058/385] appease linter --- pkg/gui/arrangement.go | 4 +++ pkg/gui/context.go | 15 ++++++++++ pkg/gui/context_config.go | 28 ------------------ pkg/gui/gui.go | 12 -------- pkg/gui/reflog_panel.go | 5 ---- pkg/gui/view_helpers.go | 60 --------------------------------------- 6 files changed, 19 insertions(+), 105 deletions(-) diff --git a/pkg/gui/arrangement.go b/pkg/gui/arrangement.go index 9766d7885..11336946f 100644 --- a/pkg/gui/arrangement.go +++ b/pkg/gui/arrangement.go @@ -313,6 +313,10 @@ func (gui *Gui) sidePanelChildren(width int, height int) []*boxlayout.Box { } } +func (gui *Gui) getCyclableWindows() []string { + return []string{"status", "files", "branches", "commits", "stash"} +} + func (gui *Gui) currentSideWindowName() string { // there is always one and only one cyclable context in the context stack. We'll look from top to bottom gui.State.ContextManager.RLock() diff --git a/pkg/gui/context.go b/pkg/gui/context.go index b59f0a448..9f097f78a 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -3,6 +3,8 @@ package gui import ( "errors" "fmt" + "sort" + "strings" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/context" @@ -222,6 +224,19 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro return nil } +func (gui *Gui) optionsMapToString(optionsMap map[string]string) string { + optionsArray := make([]string, 0) + for key, description := range optionsMap { + optionsArray = append(optionsArray, key+": "+description) + } + sort.Strings(optionsArray) + return strings.Join(optionsArray, ", ") +} + +func (gui *Gui) renderOptionsMap(optionsMap map[string]string) { + _ = gui.renderString(gui.Views.Options, gui.optionsMapToString(optionsMap)) +} + // also setting context on view for now. We'll need to pick one of these two approaches to stick with. func (gui *Gui) ViewContextMapSet(viewName string, c types.Context) { gui.State.ViewContextMap.Set(viewName, c) diff --git a/pkg/gui/context_config.go b/pkg/gui/context_config.go index 54f139141..c8e9aa0fa 100644 --- a/pkg/gui/context_config.go +++ b/pkg/gui/context_config.go @@ -5,34 +5,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/types" ) -func (gui *Gui) allContexts2() []types.Context { - return []types.Context{ - gui.State.Contexts.Global, - gui.State.Contexts.Status, - gui.State.Contexts.Files, - gui.State.Contexts.Submodules, - gui.State.Contexts.Branches, - gui.State.Contexts.Remotes, - gui.State.Contexts.RemoteBranches, - gui.State.Contexts.Tags, - gui.State.Contexts.BranchCommits, - gui.State.Contexts.CommitFiles, - gui.State.Contexts.ReflogCommits, - gui.State.Contexts.Stash, - gui.State.Contexts.Menu, - gui.State.Contexts.Confirmation, - gui.State.Contexts.Credentials, - gui.State.Contexts.CommitMessage, - gui.State.Contexts.Normal, - gui.State.Contexts.Staging, - gui.State.Contexts.Merging, - gui.State.Contexts.PatchBuilding, - gui.State.Contexts.SubCommits, - gui.State.Contexts.Suggestions, - gui.State.Contexts.CommandLog, - } -} - func (gui *Gui) contextTree() *context.ContextTree { return &context.ContextTree{ Global: context.NewSimpleContext( diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 3966cd48f..7dab1dc99 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -212,18 +212,6 @@ type Controllers struct { Global *controllers.GlobalController } -type listPanelState struct { - SelectedLineIdx int -} - -func (h *listPanelState) SetSelectedLineIdx(value int) { - h.SelectedLineIdx = value -} - -func (h *listPanelState) GetSelectedLineIdx() int { - return h.SelectedLineIdx -} - // for now the staging panel state, unlike the other panel states, is going to be // non-mutative, so that we don't accidentally end up // with mismatches of data. We might change this in the future diff --git a/pkg/gui/reflog_panel.go b/pkg/gui/reflog_panel.go index 97fd1dd4f..e45210fdf 100644 --- a/pkg/gui/reflog_panel.go +++ b/pkg/gui/reflog_panel.go @@ -1,17 +1,12 @@ package gui import ( - "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/types" ) // list panel functions -func (gui *Gui) getSelectedReflogCommit() *models.Commit { - return gui.State.Contexts.ReflogCommits.GetSelected() -} - func (gui *Gui) reflogCommitsRenderToMain() error { commit := gui.State.Contexts.ReflogCommits.GetSelected() var task updateTask diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index 202504c10..234be7a4c 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -2,19 +2,12 @@ package gui import ( "fmt" - "sort" - "strings" "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/spkg/bom" ) -func (gui *Gui) getCyclableWindows() []string { - return []string{"status", "files", "branches", "commits", "stash"} -} - func (gui *Gui) resetOrigin(v *gocui.View) error { _ = v.SetCursor(0, 0) return v.SetOrigin(0, 0) @@ -41,19 +34,6 @@ func (gui *Gui) renderString(view *gocui.View, s string) error { return nil } -func (gui *Gui) optionsMapToString(optionsMap map[string]string) string { - optionsArray := make([]string, 0) - for key, description := range optionsMap { - optionsArray = append(optionsArray, key+": "+description) - } - sort.Strings(optionsArray) - return strings.Join(optionsArray, ", ") -} - -func (gui *Gui) renderOptionsMap(optionsMap map[string]string) { - _ = gui.renderString(gui.Views.Options, gui.optionsMapToString(optionsMap)) -} - func (gui *Gui) currentViewName() string { currentView := gui.g.CurrentView() if currentView == nil { @@ -85,46 +65,6 @@ func (gui *Gui) resizePopupPanel(v *gocui.View, content string) error { return err } -func (gui *Gui) changeSelectedLine(panelState types.IListPanelState, total int, change int) { - // TODO: find out why we're doing this - line := panelState.GetSelectedLineIdx() - - if line == -1 { - return - } - var newLine int - if line+change < 0 { - newLine = 0 - } else if line+change >= total { - newLine = total - 1 - } else { - newLine = line + change - } - - panelState.SetSelectedLineIdx(newLine) -} - -func (gui *Gui) refreshSelectedLine(panelState types.IListPanelState, total int) { - line := panelState.GetSelectedLineIdx() - - if line == -1 && total > 0 { - panelState.SetSelectedLineIdx(0) - } else if total-1 < line { - panelState.SetSelectedLineIdx(total - 1) - } -} - -func (gui *Gui) renderDisplayStrings(v *gocui.View, displayStrings [][]string) { - list := utils.RenderDisplayStrings(displayStrings) - v.SetContent(list) -} - -func (gui *Gui) renderDisplayStringsInViewPort(v *gocui.View, displayStrings [][]string) { - list := utils.RenderDisplayStrings(displayStrings) - _, y := v.Origin() - v.OverwriteLines(y, list) -} - func (gui *Gui) globalOptionsMap() map[string]string { keybindingConfig := gui.c.UserConfig.Keybinding From 94d66b267dc4c5c415887566dcceb8e267d4ff06 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 10:57:30 +1100 Subject: [PATCH 059/385] defend against view not yet having a context defined against it --- pkg/gui/context.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 9f097f78a..8d147f4c9 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -181,7 +181,12 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro if err != nil { return err } - originalViewContextKey := gui.State.ViewContextMap.Get(viewName).GetKey() + + originalViewContext := gui.State.ViewContextMap.Get(viewName) + var originalViewContextKey types.ContextKey = "" + if originalViewContext != nil { + originalViewContextKey = originalViewContext.GetKey() + } gui.setWindowContext(c) gui.setViewTabForContext(c) From 943a8e83da2f5ab9afc7dc22f32bfb4609ff6347 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 11:35:42 +1100 Subject: [PATCH 060/385] ensure we retain state when returning to submodule parent --- pkg/gui/context/context.go | 6 ++++++ pkg/gui/gui.go | 19 ++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/pkg/gui/context/context.go b/pkg/gui/context/context.go index 5f7c8f163..e33a6c253 100644 --- a/pkg/gui/context/context.go +++ b/pkg/gui/context/context.go @@ -137,6 +137,12 @@ func (self *ViewContextMap) Set(viewName string, context types.Context) { self.content[viewName] = context } +func (self *ViewContextMap) Entries() map[string]types.Context { + self.Lock() + defer self.Unlock() + return self.content +} + type TabContext struct { Tab string Contexts []types.Context diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 7dab1dc99..84203c9e5 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -323,6 +323,8 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { if state := gui.RepoStateMap[Repo(currentDir)]; state != nil { gui.State = state gui.State.ViewsSetup = false + gui.syncViewContexts() + return } } else { gui.c.Log.Error(err) @@ -341,11 +343,6 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { viewContextMap := context.NewViewContextMap() for viewName, context := range initialViewContextMapping(contextTree) { viewContextMap.Set(viewName, context) - view, err := gui.g.View(viewName) - if err != nil { - panic(err) - } - view.Context = string(context.GetKey()) } gui.State = &GuiRepoState{ @@ -380,9 +377,21 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { Contexts: contextTree, } + gui.syncViewContexts() + gui.RepoStateMap[Repo(currentDir)] = gui.State } +func (gui *Gui) syncViewContexts() { + for viewName, context := range gui.State.ViewContextMap.Entries() { + view, err := gui.g.View(viewName) + if err != nil { + panic(err) + } + view.Context = string(context.GetKey()) + } +} + func initialViewContextMapping(contextTree *context.ContextTree) map[string]types.Context { return map[string]types.Context{ "status": contextTree.Status, From 33a223e9813daf426d033c07fce5a5fab4276653 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 11:40:49 +1100 Subject: [PATCH 061/385] remove dead code --- pkg/gui/sub_commits_panel.go | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/pkg/gui/sub_commits_panel.go b/pkg/gui/sub_commits_panel.go index 5b5637edc..0d39038d4 100644 --- a/pkg/gui/sub_commits_panel.go +++ b/pkg/gui/sub_commits_panel.go @@ -1,7 +1,6 @@ package gui import ( - "github.com/jesseduffield/lazygit/pkg/commands/loaders" "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -69,27 +68,6 @@ func (gui *Gui) handleViewSubCommitFiles() error { }) } -func (gui *Gui) switchToSubCommitsContext(refName string) error { - // need to populate my sub commits - commits, err := gui.git.Loaders.Commits.GetCommits( - loaders.GetCommitsOptions{ - Limit: true, - FilterPath: gui.State.Modes.Filtering.GetPath(), - IncludeRebaseCommits: false, - RefName: refName, - }, - ) - if err != nil { - return err - } - - gui.State.Model.SubCommits = commits - gui.State.Contexts.SubCommits.SetSelectedLineIdx(0) - gui.State.Contexts.SubCommits.SetParentContext(gui.currentSideListContext()) - - return gui.c.PushContext(gui.State.Contexts.SubCommits) -} - func (gui *Gui) handleNewBranchOffSubCommit() error { commit := gui.State.Contexts.SubCommits.GetSelected() if commit == nil { From 55af07a1bb4e1d3f85a456c2604c46e5535aca40 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 12:47:15 +1100 Subject: [PATCH 062/385] fix CI --- pkg/gui/context.go | 7 ++++--- pkg/gui/context/list_context_trait.go | 2 +- pkg/gui/diffing.go | 26 +++++++++++++++----------- pkg/gui/presentation/files_test.go | 2 ++ 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 8d147f4c9..79f9acd94 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -43,13 +43,12 @@ func (gui *Gui) currentContextKeyIgnoringPopups() types.ContextKey { // use replaceContext when you don't want to return to the original context upon // hitting escape: you want to go that context's parent instead. func (gui *Gui) replaceContext(c types.Context) error { - gui.State.ContextManager.Lock() - defer gui.State.ContextManager.Unlock() - if !c.IsFocusable() { return nil } + gui.State.ContextManager.Lock() + if len(gui.State.ContextManager.ContextStack) == 0 { gui.State.ContextManager.ContextStack = []types.Context{c} } else { @@ -57,6 +56,8 @@ func (gui *Gui) replaceContext(c types.Context) error { gui.State.ContextManager.ContextStack = append(gui.State.ContextManager.ContextStack[0:len(gui.State.ContextManager.ContextStack)-1], c) } + defer gui.State.ContextManager.Unlock() + return gui.activateContext(c) } diff --git a/pkg/gui/context/list_context_trait.go b/pkg/gui/context/list_context_trait.go index 6deb5dfc1..e508c8029 100644 --- a/pkg/gui/context/list_context_trait.go +++ b/pkg/gui/context/list_context_trait.go @@ -43,7 +43,7 @@ func (self *ListContextTrait) HandleFocus(opts ...types.OnFocusOpts) error { func (self *ListContextTrait) HandleFocusLost() error { self.viewTrait.SetOriginX(0) - return self.Context.HandleFocus() + return self.Context.HandleFocusLost() } // OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view diff --git a/pkg/gui/diffing.go b/pkg/gui/diffing.go index a23772ab3..daa659f7f 100644 --- a/pkg/gui/diffing.go +++ b/pkg/gui/diffing.go @@ -33,15 +33,19 @@ func (gui *Gui) renderDiff() error { // which becomes an option when you bring up the diff menu, but when you're just // flicking through branches it will be using the local branch name. func (gui *Gui) currentDiffTerminals() []string { - switch gui.currentContext().GetKey() { - case "": + c := gui.currentSideContext() + + if c.GetKey() == "" { return nil - case context.FILES_CONTEXT_KEY, context.SUBMODULES_CONTEXT_KEY: + } + + switch v := c.(type) { + case *context.WorkingTreeContext, *context.SubmodulesContext: // TODO: should we just return nil here? return []string{""} - case context.COMMIT_FILES_CONTEXT_KEY: - return []string{gui.State.Contexts.CommitFiles.GetRefName()} - case context.LOCAL_BRANCHES_CONTEXT_KEY: + case *context.CommitFilesContext: + return []string{v.GetRefName()} + case *context.BranchesContext: // for our local branches we want to include both the branch and its upstream branch := gui.State.Contexts.Branches.GetSelected() if branch != nil { @@ -52,13 +56,13 @@ func (gui *Gui) currentDiffTerminals() []string { return names } return nil - default: - itemId := gui.getSideContextSelectedItemId() - if itemId == "" { - return nil - } + case types.IListContext: + itemId := v.GetSelectedItemId() + return []string{itemId} } + + return nil } func (gui *Gui) currentDiffTerminal() string { diff --git a/pkg/gui/presentation/files_test.go b/pkg/gui/presentation/files_test.go index 441ec7b69..fcca2c27d 100644 --- a/pkg/gui/presentation/files_test.go +++ b/pkg/gui/presentation/files_test.go @@ -70,6 +70,7 @@ M file1 s := s t.Run(s.name, func(t *testing.T) { viewModel := filetree.NewFileTree(func() []*models.File { return s.files }, utils.NewDummyLog(), true) + viewModel.SetTree() for _, path := range s.collapsedPaths { viewModel.ToggleCollapsed(path) } @@ -128,6 +129,7 @@ M file1 s := s t.Run(s.name, func(t *testing.T) { viewModel := filetree.NewCommitFileTreeViewModel(func() []*models.CommitFile { return s.files }, utils.NewDummyLog(), true) + viewModel.SetTree() for _, path := range s.collapsedPaths { viewModel.ToggleCollapsed(path) } From 371b8d638b55ecce5c99700072051a9d15df7d96 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 17:01:53 +1100 Subject: [PATCH 063/385] more consistent naming --- pkg/gui/commit_files_panel.go | 4 ++-- pkg/gui/commits_panel.go | 6 +++--- pkg/gui/context.go | 2 +- pkg/gui/context/context.go | 10 +++++----- pkg/gui/context/local_commits_context.go | 2 +- pkg/gui/context_config.go | 2 +- pkg/gui/controllers/bisect_controller.go | 2 +- .../controllers/helpers/cherry_pick_helper.go | 2 +- pkg/gui/controllers/helpers/refs_helper.go | 12 ++++++------ .../controllers/local_commits_controller.go | 2 +- pkg/gui/custom_commands.go | 2 +- pkg/gui/diff_context_size.go | 2 +- pkg/gui/filtering.go | 4 ++-- pkg/gui/gui.go | 10 +++++----- pkg/gui/keybindings.go | 4 ++-- pkg/gui/list_context_config.go | 8 ++++---- pkg/gui/patch_options_panel.go | 4 ++-- pkg/gui/refresh.go | 18 +++++++++--------- 18 files changed, 48 insertions(+), 48 deletions(-) diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index 8f1201ccb..610973399 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -84,7 +84,7 @@ func (gui *Gui) handleDiscardOldFileChange() error { HandleConfirm: func() error { return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { gui.c.LogAction(gui.c.Tr.Actions.DiscardOldFileChange) - if err := gui.git.Rebase.DiscardOldFileChanges(gui.State.Model.Commits, gui.State.Contexts.BranchCommits.GetSelectedLineIdx(), fileName); err != nil { + if err := gui.git.Rebase.DiscardOldFileChanges(gui.State.Model.Commits, gui.State.Contexts.LocalCommits.GetSelectedLineIdx(), fileName); err != nil { if err := gui.helpers.MergeAndRebase.CheckMergeOrRebase(err); err != nil { return err } @@ -98,7 +98,7 @@ func (gui *Gui) handleDiscardOldFileChange() error { func (gui *Gui) refreshCommitFilesView() error { currentSideContext := gui.currentSideContext() - if currentSideContext.GetKey() == context.COMMIT_FILES_CONTEXT_KEY || currentSideContext.GetKey() == context.BRANCH_COMMITS_CONTEXT_KEY { + if currentSideContext.GetKey() == context.COMMIT_FILES_CONTEXT_KEY || currentSideContext.GetKey() == context.LOCAL_COMMITS_CONTEXT_KEY { if err := gui.handleRefreshPatchBuildingPanel(-1); err != nil { return err } diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go index bed39a05a..126fac3a7 100644 --- a/pkg/gui/commits_panel.go +++ b/pkg/gui/commits_panel.go @@ -11,11 +11,11 @@ const COMMIT_THRESHOLD = 200 // list panel functions func (gui *Gui) getSelectedLocalCommit() *models.Commit { - return gui.State.Contexts.BranchCommits.GetSelected() + return gui.State.Contexts.LocalCommits.GetSelected() } func (gui *Gui) onCommitFocus() error { - context := gui.State.Contexts.BranchCommits + context := gui.State.Contexts.LocalCommits if context.GetSelectedLineIdx() > COMMIT_THRESHOLD && context.GetLimitCommits() { context.SetLimitCommits(false) go utils.Safe(func() { @@ -32,7 +32,7 @@ func (gui *Gui) onCommitFocus() error { func (gui *Gui) branchCommitsRenderToMain() error { var task updateTask - commit := gui.State.Contexts.BranchCommits.GetSelected() + commit := gui.State.Contexts.LocalCommits.GetSelected() if commit == nil { task = NewRenderStringTask(gui.c.Tr.NoCommitsThisBranch) } else { diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 79f9acd94..748354c3d 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -336,7 +336,7 @@ func (gui *Gui) currentStaticContext() types.Context { func (gui *Gui) defaultSideContext() types.Context { if gui.State.Modes.Filtering.Active() { - return gui.State.Contexts.BranchCommits + return gui.State.Contexts.LocalCommits } else { return gui.State.Contexts.Files } diff --git a/pkg/gui/context/context.go b/pkg/gui/context/context.go index e33a6c253..f57cb507d 100644 --- a/pkg/gui/context/context.go +++ b/pkg/gui/context/context.go @@ -14,7 +14,7 @@ const ( REMOTES_CONTEXT_KEY types.ContextKey = "remotes" REMOTE_BRANCHES_CONTEXT_KEY types.ContextKey = "remoteBranches" TAGS_CONTEXT_KEY types.ContextKey = "tags" - BRANCH_COMMITS_CONTEXT_KEY types.ContextKey = "commits" + LOCAL_COMMITS_CONTEXT_KEY types.ContextKey = "commits" REFLOG_COMMITS_CONTEXT_KEY types.ContextKey = "reflogCommits" SUB_COMMITS_CONTEXT_KEY types.ContextKey = "subCommits" COMMIT_FILES_CONTEXT_KEY types.ContextKey = "commitFiles" @@ -41,7 +41,7 @@ var AllContextKeys = []types.ContextKey{ REMOTES_CONTEXT_KEY, REMOTE_BRANCHES_CONTEXT_KEY, TAGS_CONTEXT_KEY, - BRANCH_COMMITS_CONTEXT_KEY, + LOCAL_COMMITS_CONTEXT_KEY, REFLOG_COMMITS_CONTEXT_KEY, SUB_COMMITS_CONTEXT_KEY, COMMIT_FILES_CONTEXT_KEY, @@ -67,7 +67,7 @@ type ContextTree struct { Menu *MenuContext Branches *BranchesContext Tags *TagsContext - BranchCommits *LocalCommitsContext + LocalCommits *LocalCommitsContext CommitFiles *CommitFilesContext Remotes *RemotesContext Submodules *SubmodulesContext @@ -97,7 +97,7 @@ func (self *ContextTree) Flatten() []types.Context { self.Remotes, self.RemoteBranches, self.Tags, - self.BranchCommits, + self.LocalCommits, self.CommitFiles, self.ReflogCommits, self.Stash, @@ -170,7 +170,7 @@ func (tree ContextTree) InitialViewTabContextMap() map[string][]TabContext { "commits": { { Tab: "Commits", - Contexts: []types.Context{tree.BranchCommits}, + Contexts: []types.Context{tree.LocalCommits}, }, { Tab: "Reflog", diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index 9da4721e3..408a906ba 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -34,7 +34,7 @@ func NewLocalCommitsContext( Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ ViewName: "commits", WindowName: "commits", - Key: BRANCH_COMMITS_CONTEXT_KEY, + Key: LOCAL_COMMITS_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, Focusable: true, }), ContextCallbackOpts{ diff --git a/pkg/gui/context_config.go b/pkg/gui/context_config.go index c8e9aa0fa..348c5b21b 100644 --- a/pkg/gui/context_config.go +++ b/pkg/gui/context_config.go @@ -36,7 +36,7 @@ func (gui *Gui) contextTree() *context.ContextTree { Menu: gui.menuListContext(), Remotes: gui.remotesListContext(), RemoteBranches: gui.remoteBranchesListContext(), - BranchCommits: gui.branchCommitsListContext(), + LocalCommits: gui.branchCommitsListContext(), CommitFiles: gui.commitFilesListContext(), ReflogCommits: gui.reflogCommitsListContext(), SubCommits: gui.subCommitsListContext(), diff --git a/pkg/gui/controllers/bisect_controller.go b/pkg/gui/controllers/bisect_controller.go index addcd8d80..5dae02a38 100644 --- a/pkg/gui/controllers/bisect_controller.go +++ b/pkg/gui/controllers/bisect_controller.go @@ -239,5 +239,5 @@ func (self *BisectController) Context() types.Context { } func (self *BisectController) context() *context.LocalCommitsContext { - return self.contexts.BranchCommits + return self.contexts.LocalCommits } diff --git a/pkg/gui/controllers/helpers/cherry_pick_helper.go b/pkg/gui/controllers/helpers/cherry_pick_helper.go index a0fd4ebca..badbf0dfe 100644 --- a/pkg/gui/controllers/helpers/cherry_pick_helper.go +++ b/pkg/gui/controllers/helpers/cherry_pick_helper.go @@ -143,7 +143,7 @@ func (self *CherryPickHelper) resetIfNecessary(context types.Context) error { func (self *CherryPickHelper) rerender() error { for _, context := range []types.Context{ - self.contexts.BranchCommits, + self.contexts.LocalCommits, self.contexts.ReflogCommits, self.contexts.SubCommits, } { diff --git a/pkg/gui/controllers/helpers/refs_helper.go b/pkg/gui/controllers/helpers/refs_helper.go index 3b132a32f..e3e050117 100644 --- a/pkg/gui/controllers/helpers/refs_helper.go +++ b/pkg/gui/controllers/helpers/refs_helper.go @@ -55,9 +55,9 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions onSuccess := func() { self.contexts.Branches.SetSelectedLineIdx(0) self.contexts.ReflogCommits.SetSelectedLineIdx(0) - self.contexts.BranchCommits.SetSelectedLineIdx(0) + self.contexts.LocalCommits.SetSelectedLineIdx(0) // loading a heap of commits is slow so we limit them whenever doing a reset - self.contexts.BranchCommits.SetLimitCommits(true) + self.contexts.LocalCommits.SetLimitCommits(true) } return self.c.WithWaitingStatus(waitingStatus, func() error { @@ -117,12 +117,12 @@ func (self *RefsHelper) ResetToRef(ref string, strength string, envVars []string return self.c.Error(err) } - self.contexts.BranchCommits.SetSelectedLineIdx(0) + self.contexts.LocalCommits.SetSelectedLineIdx(0) self.contexts.ReflogCommits.SetSelectedLineIdx(0) // loading a heap of commits is slow so we limit them whenever doing a reset - self.contexts.BranchCommits.SetLimitCommits(true) + self.contexts.LocalCommits.SetLimitCommits(true) - if err := self.c.PushContext(self.contexts.BranchCommits); err != nil { + if err := self.c.PushContext(self.contexts.LocalCommits); err != nil { return err } @@ -179,7 +179,7 @@ func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggest } } - self.contexts.BranchCommits.SetSelectedLineIdx(0) + self.contexts.LocalCommits.SetSelectedLineIdx(0) self.contexts.Branches.SetSelectedLineIdx(0) return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index 0a7d51ae6..fa2df887e 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -746,7 +746,7 @@ func (self *LocalCommitsController) Context() types.Context { } func (self *LocalCommitsController) context() *context.LocalCommitsContext { - return self.contexts.BranchCommits + return self.contexts.LocalCommits } func (self *LocalCommitsController) newBranch(commit *models.Commit) error { diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index 6bd659bd7..01a37adce 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -44,7 +44,7 @@ func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (s objects := CustomCommandObjects{ SelectedFile: gui.getSelectedFile(), SelectedPath: gui.getSelectedPath(), - SelectedLocalCommit: gui.State.Contexts.BranchCommits.GetSelected(), + SelectedLocalCommit: gui.State.Contexts.LocalCommits.GetSelected(), SelectedReflogCommit: gui.State.Contexts.ReflogCommits.GetSelected(), SelectedLocalBranch: gui.State.Contexts.Branches.GetSelected(), SelectedRemoteBranch: gui.State.Contexts.RemoteBranches.GetSelected(), diff --git a/pkg/gui/diff_context_size.go b/pkg/gui/diff_context_size.go index e16b26852..96ec29ee2 100644 --- a/pkg/gui/diff_context_size.go +++ b/pkg/gui/diff_context_size.go @@ -11,7 +11,7 @@ var CONTEXT_KEYS_SHOWING_DIFFS = []types.ContextKey{ context.FILES_CONTEXT_KEY, context.COMMIT_FILES_CONTEXT_KEY, context.STASH_CONTEXT_KEY, - context.BRANCH_COMMITS_CONTEXT_KEY, + context.LOCAL_COMMITS_CONTEXT_KEY, context.SUB_COMMITS_CONTEXT_KEY, context.MAIN_STAGING_CONTEXT_KEY, context.MAIN_PATCH_BUILDING_CONTEXT_KEY, diff --git a/pkg/gui/filtering.go b/pkg/gui/filtering.go index 4780387c9..ac365e3a7 100644 --- a/pkg/gui/filtering.go +++ b/pkg/gui/filtering.go @@ -46,11 +46,11 @@ func (gui *Gui) setFiltering(path string) error { gui.State.ScreenMode = SCREEN_HALF } - if err := gui.c.PushContext(gui.State.Contexts.BranchCommits); err != nil { + if err := gui.c.PushContext(gui.State.Contexts.LocalCommits); err != nil { return err } return gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.COMMITS}, Then: func() { - gui.State.Contexts.BranchCommits.SetSelectedLineIdx(0) + gui.State.Contexts.LocalCommits.SetSelectedLineIdx(0) }}) } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 84203c9e5..8b5cef4c4 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -278,7 +278,7 @@ type guiMutexes struct { RefreshingFilesMutex *sync.Mutex RefreshingStatusMutex *sync.Mutex SyncMutex *sync.Mutex - BranchCommitsMutex *sync.Mutex + LocalCommitsMutex *sync.Mutex LineByLinePanelMutex *sync.Mutex SubprocessMutex *sync.Mutex } @@ -337,7 +337,7 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { var initialContext types.IListContext = contextTree.Files if filterPath != "" { screenMode = SCREEN_HALF - initialContext = contextTree.BranchCommits + initialContext = contextTree.LocalCommits } viewContextMap := context.NewViewContextMap() @@ -397,7 +397,7 @@ func initialViewContextMapping(contextTree *context.ContextTree) map[string]type "status": contextTree.Status, "files": contextTree.Files, "branches": contextTree.Branches, - "commits": contextTree.BranchCommits, + "commits": contextTree.LocalCommits, "commitFiles": contextTree.CommitFiles, "stash": contextTree.Stash, "menu": contextTree.Menu, @@ -440,7 +440,7 @@ func NewGui( RefreshingFilesMutex: &sync.Mutex{}, RefreshingStatusMutex: &sync.Mutex{}, SyncMutex: &sync.Mutex{}, - BranchCommitsMutex: &sync.Mutex{}, + LocalCommitsMutex: &sync.Mutex{}, LineByLinePanelMutex: &sync.Mutex{}, SubprocessMutex: &sync.Mutex{}, }, @@ -579,7 +579,7 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(gui.State.Contexts.Files, gui.Controllers.Files) controllers.AttachControllers(gui.State.Contexts.Tags, gui.Controllers.Tags) controllers.AttachControllers(gui.State.Contexts.Submodules, gui.Controllers.Submodules) - controllers.AttachControllers(gui.State.Contexts.BranchCommits, gui.Controllers.LocalCommits, bisectController) + controllers.AttachControllers(gui.State.Contexts.LocalCommits, gui.Controllers.LocalCommits, bisectController) controllers.AttachControllers(gui.State.Contexts.Remotes, gui.Controllers.Remotes) controllers.AttachControllers(gui.State.Contexts.Menu, gui.Controllers.Menu) controllers.AttachControllers(gui.State.Contexts.Global, gui.Controllers.Sync, gui.Controllers.Undo, gui.Controllers.Global) diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index a2dd7a419..662d8a327 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -412,14 +412,14 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi }, { ViewName: "commits", - Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)}, + Contexts: []string{string(context.LOCAL_COMMITS_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), Handler: self.handleCopySelectedSideContextItemToClipboard, Description: self.c.Tr.LcCopyCommitShaToClipboard, }, { ViewName: "commits", - Contexts: []string{string(context.BRANCH_COMMITS_CONTEXT_KEY)}, + Contexts: []string{string(context.LOCAL_COMMITS_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), Handler: self.helpers.CherryPick.Reset, Description: self.c.Tr.LcResetCherryPick, diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index b8609e9b7..397e38bd9 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -114,8 +114,8 @@ func (gui *Gui) branchCommitsListContext() *context.LocalCommitsContext { gui.Views.Commits, func(startIdx int, length int) [][]string { selectedCommitSha := "" - if gui.currentContext().GetKey() == context.BRANCH_COMMITS_CONTEXT_KEY { - selectedCommit := gui.State.Contexts.BranchCommits.GetSelected() + if gui.currentContext().GetKey() == context.LOCAL_COMMITS_CONTEXT_KEY { + selectedCommit := gui.State.Contexts.LocalCommits.GetSelected() if selectedCommit != nil { selectedCommitSha = selectedCommit.Sha } @@ -266,7 +266,7 @@ func (gui *Gui) submodulesListContext() *context.SubmodulesContext { func (gui *Gui) suggestionsListContext() *context.SuggestionsContext { return context.NewSuggestionsContext( func() []*types.Suggestion { return gui.State.Suggestions }, - gui.Views.Files, + gui.Views.Suggestions, func(startIdx int, length int) [][]string { return presentation.GetSuggestionListDisplayStrings(gui.State.Suggestions) }, @@ -285,7 +285,7 @@ func (gui *Gui) getListContexts() []types.IListContext { gui.State.Contexts.Remotes, gui.State.Contexts.RemoteBranches, gui.State.Contexts.Tags, - gui.State.Contexts.BranchCommits, + gui.State.Contexts.LocalCommits, gui.State.Contexts.ReflogCommits, gui.State.Contexts.SubCommits, gui.State.Contexts.Stash, diff --git a/pkg/gui/patch_options_panel.go b/pkg/gui/patch_options_panel.go index 81d232da2..14de524a5 100644 --- a/pkg/gui/patch_options_panel.go +++ b/pkg/gui/patch_options_panel.go @@ -44,7 +44,7 @@ func (gui *Gui) handleCreatePatchOptionsMenu() error { }, }...) - if gui.currentContext().GetKey() == gui.State.Contexts.BranchCommits.GetKey() { + if gui.currentContext().GetKey() == gui.State.Contexts.LocalCommits.GetKey() { selectedCommit := gui.getSelectedLocalCommit() if selectedCommit != nil && gui.git.Patch.PatchManager.To != selectedCommit.Sha { // adding this option to index 1 @@ -118,7 +118,7 @@ func (gui *Gui) handleMovePatchToSelectedCommit() error { return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { commitIndex := gui.getPatchCommitIndex() gui.c.LogAction(gui.c.Tr.Actions.MovePatchToSelectedCommit) - err := gui.git.Patch.MovePatchToSelectedCommit(gui.State.Model.Commits, commitIndex, gui.State.Contexts.BranchCommits.GetSelectedLineIdx()) + err := gui.git.Patch.MovePatchToSelectedCommit(gui.State.Model.Commits, commitIndex, gui.State.Contexts.LocalCommits.GetSelectedLineIdx()) return gui.helpers.MergeAndRebase.CheckMergeOrRebase(err) }) } diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go index 215028609..d9d661cff 100644 --- a/pkg/gui/refresh.go +++ b/pkg/gui/refresh.go @@ -186,7 +186,7 @@ func (gui *Gui) refreshCommits() { go utils.Safe(func() { _ = gui.refreshCommitsWithLimit() ctx, ok := gui.State.Contexts.CommitFiles.GetParentContext() - if ok && ctx.GetKey() == context.BRANCH_COMMITS_CONTEXT_KEY { + if ok && ctx.GetKey() == context.LOCAL_COMMITS_CONTEXT_KEY { // This makes sense when we've e.g. just amended a commit, meaning we get a new commit SHA at the same position. // However if we've just added a brand new commit, it pushes the list down by one and so we would end up // showing the contents of a different commit than the one we initially entered. @@ -206,16 +206,16 @@ func (gui *Gui) refreshCommits() { } func (gui *Gui) refreshCommitsWithLimit() error { - gui.Mutexes.BranchCommitsMutex.Lock() - defer gui.Mutexes.BranchCommitsMutex.Unlock() + gui.Mutexes.LocalCommitsMutex.Lock() + defer gui.Mutexes.LocalCommitsMutex.Unlock() commits, err := gui.git.Loaders.Commits.GetCommits( loaders.GetCommitsOptions{ - Limit: gui.State.Contexts.BranchCommits.GetLimitCommits(), + Limit: gui.State.Contexts.LocalCommits.GetLimitCommits(), FilterPath: gui.State.Modes.Filtering.GetPath(), IncludeRebaseCommits: true, RefName: gui.refForLog(), - All: gui.State.Contexts.BranchCommits.GetShowWholeGitGraph(), + All: gui.State.Contexts.LocalCommits.GetShowWholeGitGraph(), }, ) if err != nil { @@ -223,12 +223,12 @@ func (gui *Gui) refreshCommitsWithLimit() error { } gui.State.Model.Commits = commits - return gui.c.PostRefreshUpdate(gui.State.Contexts.BranchCommits) + return gui.c.PostRefreshUpdate(gui.State.Contexts.LocalCommits) } func (gui *Gui) refreshRebaseCommits() error { - gui.Mutexes.BranchCommitsMutex.Lock() - defer gui.Mutexes.BranchCommitsMutex.Unlock() + gui.Mutexes.LocalCommitsMutex.Lock() + defer gui.Mutexes.LocalCommitsMutex.Unlock() updatedCommits, err := gui.git.Loaders.Commits.MergeRebasingCommits(gui.State.Model.Commits) if err != nil { @@ -236,7 +236,7 @@ func (gui *Gui) refreshRebaseCommits() error { } gui.State.Model.Commits = updatedCommits - return gui.c.PostRefreshUpdate(gui.State.Contexts.BranchCommits) + return gui.c.PostRefreshUpdate(gui.State.Contexts.LocalCommits) } func (self *Gui) refreshTags() error { From eab00de273590a3bef5c76e7a4484c7840073f47 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 17:13:09 +1100 Subject: [PATCH 064/385] reflog controller --- pkg/gui/controllers/reflog_controller.go | 120 +++++++++++++++++++++++ pkg/gui/gui.go | 3 + pkg/gui/keybindings.go | 43 -------- pkg/gui/reflog_panel.go | 66 ------------- 4 files changed, 123 insertions(+), 109 deletions(-) create mode 100644 pkg/gui/controllers/reflog_controller.go diff --git a/pkg/gui/controllers/reflog_controller.go b/pkg/gui/controllers/reflog_controller.go new file mode 100644 index 000000000..c1251936e --- /dev/null +++ b/pkg/gui/controllers/reflog_controller.go @@ -0,0 +1,120 @@ +package controllers + +import ( + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type ReflogController struct { + baseController + *controllerCommon + + switchToCommitFilesContext SwitchToCommitFilesContextFn +} + +var _ types.IController = &ReflogController{} + +func NewReflogController( + common *controllerCommon, + switchToCommitFilesContext SwitchToCommitFilesContextFn, +) *ReflogController { + return &ReflogController{ + baseController: baseController{}, + controllerCommon: common, + switchToCommitFilesContext: switchToCommitFilesContext, + } +} + +func (self *ReflogController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + bindings := []*types.Binding{ + { + Key: opts.GetKey(opts.Config.Universal.GoInto), + Handler: self.checkSelected(self.handleViewReflogCommitFiles), + Description: self.c.Tr.LcViewCommitFiles, + }, + { + Key: opts.GetKey(opts.Config.Universal.Select), + Handler: self.checkSelected(self.CheckoutReflogCommit), + Description: self.c.Tr.LcCheckoutCommit, + }, + { + Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), + Handler: self.checkSelected(self.handleCreateReflogResetMenu), + Description: self.c.Tr.LcViewResetOptions, + OpensMenu: true, + }, + { + Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), + Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.handleCopyReflogCommit)), + Description: self.c.Tr.LcCherryPickCopy, + }, + { + Key: opts.GetKey(opts.Config.Commits.CherryPickCopyRange), + Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.handleCopyReflogCommitRange)), + Description: self.c.Tr.LcCherryPickCopyRange, + }, + { + Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), + Handler: self.helpers.CherryPick.Reset, + Description: self.c.Tr.LcResetCherryPick, + }, + } + + return bindings +} + +func (self *ReflogController) checkSelected(callback func(*models.Commit) error) func() error { + return func() error { + commit := self.context().GetSelected() + if commit == nil { + return nil + } + + return callback(commit) + } +} + +func (self *ReflogController) Context() types.Context { + return self.context() +} + +func (self *ReflogController) context() *context.ReflogCommitsContext { + return self.contexts.ReflogCommits +} + +func (self *ReflogController) CheckoutReflogCommit(commit *models.Commit) error { + err := self.c.Ask(types.AskOpts{ + Title: self.c.Tr.LcCheckoutCommit, + Prompt: self.c.Tr.SureCheckoutThisCommit, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.CheckoutReflogCommit) + return self.helpers.Refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) + }, + }) + if err != nil { + return err + } + + return nil +} + +func (self *ReflogController) handleCreateReflogResetMenu(commit *models.Commit) error { + return self.helpers.Refs.CreateGitResetMenu(commit.Sha) +} + +func (self *ReflogController) handleViewReflogCommitFiles(commit *models.Commit) error { + return self.switchToCommitFilesContext(SwitchToCommitFilesContextOpts{ + RefName: commit.Sha, + CanRebase: false, + Context: self.context(), + }) +} + +func (self *ReflogController) handleCopyReflogCommit(commit *models.Commit) error { + return self.helpers.CherryPick.Copy(commit, self.model.FilteredReflogCommits, self.context()) +} + +func (self *ReflogController) handleCopyReflogCommitRange(commit *models.Commit) error { + return self.helpers.CherryPick.CopyRange(self.context().GetSelectedLineIdx(), self.model.FilteredReflogCommits, self.context()) +} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 8b5cef4c4..e0f6eb41f 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -534,6 +534,8 @@ func (gui *Gui) resetControllers() { bisectController := controllers.NewBisectController(common) + reflogController := controllers.NewReflogController(common, gui.SwitchToCommitFilesContext) + gui.Controllers = Controllers{ Submodules: submodulesController, Global: controllers.NewGlobalController(common), @@ -580,6 +582,7 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(gui.State.Contexts.Tags, gui.Controllers.Tags) controllers.AttachControllers(gui.State.Contexts.Submodules, gui.Controllers.Submodules) controllers.AttachControllers(gui.State.Contexts.LocalCommits, gui.Controllers.LocalCommits, bisectController) + controllers.AttachControllers(gui.State.Contexts.ReflogCommits, reflogController) controllers.AttachControllers(gui.State.Contexts.Remotes, gui.Controllers.Remotes) controllers.AttachControllers(gui.State.Contexts.Menu, gui.Controllers.Menu) controllers.AttachControllers(gui.State.Contexts.Global, gui.Controllers.Sync, gui.Controllers.Undo, gui.Controllers.Global) diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 662d8a327..4cdf8d8ae 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -424,49 +424,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Handler: self.helpers.CherryPick.Reset, Description: self.c.Tr.LcResetCherryPick, }, - { - ViewName: "commits", - Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Universal.GoInto), - Handler: self.handleViewReflogCommitFiles, - Description: self.c.Tr.LcViewCommitFiles, - }, - { - ViewName: "commits", - Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Universal.Select), - Handler: self.CheckoutReflogCommit, - Description: self.c.Tr.LcCheckoutCommit, - }, - { - ViewName: "commits", - Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), - Handler: self.handleCreateReflogResetMenu, - Description: self.c.Tr.LcViewResetOptions, - OpensMenu: true, - }, - { - ViewName: "commits", - Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), - Handler: opts.Guards.OutsideFilterMode(self.handleCopyReflogCommit), - Description: self.c.Tr.LcCherryPickCopy, - }, - { - ViewName: "commits", - Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Commits.CherryPickCopyRange), - Handler: opts.Guards.OutsideFilterMode(self.handleCopyReflogCommitRange), - Description: self.c.Tr.LcCherryPickCopyRange, - }, - { - ViewName: "commits", - Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), - Handler: self.helpers.CherryPick.Reset, - Description: self.c.Tr.LcResetCherryPick, - }, { ViewName: "commits", Contexts: []string{string(context.REFLOG_COMMITS_CONTEXT_KEY)}, diff --git a/pkg/gui/reflog_panel.go b/pkg/gui/reflog_panel.go index e45210fdf..f13783fbd 100644 --- a/pkg/gui/reflog_panel.go +++ b/pkg/gui/reflog_panel.go @@ -1,12 +1,5 @@ package gui -import ( - "github.com/jesseduffield/lazygit/pkg/gui/controllers" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - -// list panel functions - func (gui *Gui) reflogCommitsRenderToMain() error { commit := gui.State.Contexts.ReflogCommits.GetSelected() var task updateTask @@ -25,62 +18,3 @@ func (gui *Gui) reflogCommitsRenderToMain() error { }, }) } - -func (gui *Gui) CheckoutReflogCommit() error { - commit := gui.State.Contexts.ReflogCommits.GetSelected() - if commit == nil { - return nil - } - - err := gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.LcCheckoutCommit, - Prompt: gui.c.Tr.SureCheckoutThisCommit, - HandleConfirm: func() error { - gui.c.LogAction(gui.c.Tr.Actions.CheckoutReflogCommit) - return gui.helpers.Refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) - }, - }) - if err != nil { - return err - } - - return nil -} - -func (gui *Gui) handleCreateReflogResetMenu() error { - commit := gui.State.Contexts.ReflogCommits.GetSelected() - - return gui.helpers.Refs.CreateGitResetMenu(commit.Sha) -} - -func (gui *Gui) handleViewReflogCommitFiles() error { - commit := gui.State.Contexts.ReflogCommits.GetSelected() - if commit == nil { - return nil - } - - return gui.SwitchToCommitFilesContext(controllers.SwitchToCommitFilesContextOpts{ - RefName: commit.Sha, - CanRebase: false, - Context: gui.State.Contexts.ReflogCommits, - }) -} - -func (gui *Gui) handleCopyReflogCommit() error { - commit := gui.State.Contexts.ReflogCommits.GetSelected() - if commit == nil { - return nil - } - - return gui.helpers.CherryPick.Copy(commit, gui.State.Model.FilteredReflogCommits, gui.State.Contexts.ReflogCommits) -} - -func (gui *Gui) handleCopyReflogCommitRange() error { - // just doing this to ensure something is selected - commit := gui.State.Contexts.ReflogCommits.GetSelected() - if commit == nil { - return nil - } - - return gui.helpers.CherryPick.CopyRange(gui.State.Contexts.ReflogCommits.GetSelectedLineIdx(), gui.State.Model.FilteredReflogCommits, gui.State.Contexts.ReflogCommits) -} From 1253100431a93dca4b4953f2d4bfe73d22e15645 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 17:24:37 +1100 Subject: [PATCH 065/385] cleanup --- .../controllers/local_commits_controller.go | 69 +++++---- pkg/gui/controllers/reflog_controller.go | 20 +-- pkg/gui/controllers/sub_commits_controller.go | 131 ++++++++++++++++++ pkg/gui/keybindings.go | 50 ------- pkg/gui/sub_commits_panel.go | 75 ---------- 5 files changed, 174 insertions(+), 171 deletions(-) create mode 100644 pkg/gui/controllers/sub_commits_controller.go diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index fa2df887e..d071ab3fb 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -42,12 +42,12 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ outsideFilterModeBindings := []*types.Binding{ { Key: opts.GetKey(opts.Config.Commits.SquashDown), - Handler: self.squashDown, + Handler: self.checkSelected(self.squashDown), Description: self.c.Tr.LcSquashDown, }, { Key: opts.GetKey(opts.Config.Commits.MarkCommitAsFixup), - Handler: self.fixup, + Handler: self.checkSelected(self.fixup), Description: self.c.Tr.LcFixupCommit, }, { @@ -57,22 +57,22 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ }, { Key: opts.GetKey(opts.Config.Commits.RenameCommitWithEditor), - Handler: self.rewordEditor, + Handler: self.checkSelected(self.rewordEditor), Description: self.c.Tr.LcRenameCommitEditor, }, { Key: opts.GetKey(opts.Config.Universal.Remove), - Handler: self.drop, + Handler: self.checkSelected(self.drop), Description: self.c.Tr.LcDeleteCommit, }, { Key: opts.GetKey(opts.Config.Universal.Edit), - Handler: self.edit, + Handler: self.checkSelected(self.edit), Description: self.c.Tr.LcEditCommit, }, { Key: opts.GetKey(opts.Config.Commits.PickCommit), - Handler: self.pick, + Handler: self.checkSelected(self.pick), Description: self.c.Tr.LcPickCommit, }, { @@ -87,17 +87,17 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ }, { Key: opts.GetKey(opts.Config.Commits.MoveDownCommit), - Handler: self.handleCommitMoveDown, + Handler: self.checkSelected(self.handleCommitMoveDown), Description: self.c.Tr.LcMoveDownCommit, }, { Key: opts.GetKey(opts.Config.Commits.MoveUpCommit), - Handler: self.handleCommitMoveUp, + Handler: self.checkSelected(self.handleCommitMoveUp), Description: self.c.Tr.LcMoveUpCommit, }, { Key: opts.GetKey(opts.Config.Commits.AmendToCommit), - Handler: self.handleCommitAmendTo, + Handler: self.checkSelected(self.handleCommitAmendTo), Description: self.c.Tr.LcAmendToCommit, }, { @@ -192,12 +192,12 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ return bindings } -func (self *LocalCommitsController) squashDown() error { +func (self *LocalCommitsController) squashDown(commit *models.Commit) error { if len(self.model.Commits) <= 1 { return self.c.ErrorMsg(self.c.Tr.YouNoCommitsToSquash) } - applied, err := self.handleMidRebaseCommand("squash") + applied, err := self.handleMidRebaseCommand("squash", commit) if err != nil { return err } @@ -217,12 +217,12 @@ func (self *LocalCommitsController) squashDown() error { }) } -func (self *LocalCommitsController) fixup() error { +func (self *LocalCommitsController) fixup(commit *models.Commit) error { if len(self.model.Commits) <= 1 { return self.c.ErrorMsg(self.c.Tr.YouNoCommitsToSquash) } - applied, err := self.handleMidRebaseCommand("fixup") + applied, err := self.handleMidRebaseCommand("fixup", commit) if err != nil { return err } @@ -243,7 +243,7 @@ func (self *LocalCommitsController) fixup() error { } func (self *LocalCommitsController) reword(commit *models.Commit) error { - applied, err := self.handleMidRebaseCommand("reword") + applied, err := self.handleMidRebaseCommand("reword", commit) if err != nil { return err } @@ -271,8 +271,8 @@ func (self *LocalCommitsController) reword(commit *models.Commit) error { }) } -func (self *LocalCommitsController) rewordEditor() error { - applied, err := self.handleMidRebaseCommand("reword") +func (self *LocalCommitsController) rewordEditor(commit *models.Commit) error { + applied, err := self.handleMidRebaseCommand("reword", commit) if err != nil { return err } @@ -294,8 +294,8 @@ func (self *LocalCommitsController) rewordEditor() error { return nil } -func (self *LocalCommitsController) drop() error { - applied, err := self.handleMidRebaseCommand("drop") +func (self *LocalCommitsController) drop(commit *models.Commit) error { + applied, err := self.handleMidRebaseCommand("drop", commit) if err != nil { return err } @@ -315,8 +315,8 @@ func (self *LocalCommitsController) drop() error { }) } -func (self *LocalCommitsController) edit() error { - applied, err := self.handleMidRebaseCommand("edit") +func (self *LocalCommitsController) edit(commit *models.Commit) error { + applied, err := self.handleMidRebaseCommand("edit", commit) if err != nil { return err } @@ -330,8 +330,8 @@ func (self *LocalCommitsController) edit() error { }) } -func (self *LocalCommitsController) pick() error { - applied, err := self.handleMidRebaseCommand("pick") +func (self *LocalCommitsController) pick(commit *models.Commit) error { + applied, err := self.handleMidRebaseCommand("pick", commit) if err != nil { return err } @@ -352,9 +352,8 @@ func (self *LocalCommitsController) interactiveRebase(action string) error { // handleMidRebaseCommand sees if the selected commit is in fact a rebasing // commit meaning you are trying to edit the todo file rather than actually // begin a rebase. It then updates the todo file with that action -func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool, error) { - selectedCommit := self.context().GetSelected() - if selectedCommit.Status != "rebasing" { +func (self *LocalCommitsController) handleMidRebaseCommand(action string, commit *models.Commit) (bool, error) { + if commit.Status != "rebasing" { return false, nil } @@ -368,7 +367,7 @@ func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool, self.c.LogAction("Update rebase TODO") self.c.LogCommand( - fmt.Sprintf("Updating rebase action of commit %s to '%s'", selectedCommit.ShortSha(), action), + fmt.Sprintf("Updating rebase action of commit %s to '%s'", commit.ShortSha(), action), false, ) @@ -383,11 +382,10 @@ func (self *LocalCommitsController) handleMidRebaseCommand(action string) (bool, }) } -func (self *LocalCommitsController) handleCommitMoveDown() error { +func (self *LocalCommitsController) handleCommitMoveDown(commit *models.Commit) error { index := self.context().GetSelectedLineIdx() commits := self.model.Commits - selectedCommit := self.model.Commits[index] - if selectedCommit.Status == "rebasing" { + if commit.Status == "rebasing" { if commits[index+1].Status != "rebasing" { return nil } @@ -395,7 +393,7 @@ func (self *LocalCommitsController) handleCommitMoveDown() error { // logging directly here because MoveTodoDown doesn't have enough information // to provide a useful log self.c.LogAction(self.c.Tr.Actions.MoveCommitDown) - self.c.LogCommand(fmt.Sprintf("Moving commit %s down", selectedCommit.ShortSha()), false) + self.c.LogCommand(fmt.Sprintf("Moving commit %s down", commit.ShortSha()), false) if err := self.git.Rebase.MoveTodoDown(index); err != nil { return self.c.Error(err) @@ -416,19 +414,18 @@ func (self *LocalCommitsController) handleCommitMoveDown() error { }) } -func (self *LocalCommitsController) handleCommitMoveUp() error { +func (self *LocalCommitsController) handleCommitMoveUp(commit *models.Commit) error { index := self.context().GetSelectedLineIdx() if index == 0 { return nil } - selectedCommit := self.model.Commits[index] - if selectedCommit.Status == "rebasing" { + if commit.Status == "rebasing" { // logging directly here because MoveTodoDown doesn't have enough information // to provide a useful log self.c.LogAction(self.c.Tr.Actions.MoveCommitUp) self.c.LogCommand( - fmt.Sprintf("Moving commit %s up", selectedCommit.ShortSha()), + fmt.Sprintf("Moving commit %s up", commit.ShortSha()), false, ) @@ -451,14 +448,14 @@ func (self *LocalCommitsController) handleCommitMoveUp() error { }) } -func (self *LocalCommitsController) handleCommitAmendTo() error { +func (self *LocalCommitsController) handleCommitAmendTo(commit *models.Commit) error { return self.c.Ask(types.AskOpts{ Title: self.c.Tr.AmendCommitTitle, Prompt: self.c.Tr.AmendCommitPrompt, HandleConfirm: func() error { return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func() error { self.c.LogAction(self.c.Tr.Actions.AmendCommit) - err := self.git.Rebase.AmendTo(self.context().GetSelected().Sha) + err := self.git.Rebase.AmendTo(commit.Sha) return self.helpers.MergeAndRebase.CheckMergeOrRebase(err) }) }, diff --git a/pkg/gui/controllers/reflog_controller.go b/pkg/gui/controllers/reflog_controller.go index c1251936e..549348040 100644 --- a/pkg/gui/controllers/reflog_controller.go +++ b/pkg/gui/controllers/reflog_controller.go @@ -30,28 +30,28 @@ func (self *ReflogController) GetKeybindings(opts types.KeybindingsOpts) []*type bindings := []*types.Binding{ { Key: opts.GetKey(opts.Config.Universal.GoInto), - Handler: self.checkSelected(self.handleViewReflogCommitFiles), + Handler: self.checkSelected(self.enter), Description: self.c.Tr.LcViewCommitFiles, }, { Key: opts.GetKey(opts.Config.Universal.Select), - Handler: self.checkSelected(self.CheckoutReflogCommit), + Handler: self.checkSelected(self.checkout), Description: self.c.Tr.LcCheckoutCommit, }, { Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), - Handler: self.checkSelected(self.handleCreateReflogResetMenu), + Handler: self.checkSelected(self.openResetMenu), Description: self.c.Tr.LcViewResetOptions, OpensMenu: true, }, { Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), - Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.handleCopyReflogCommit)), + Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.copy)), Description: self.c.Tr.LcCherryPickCopy, }, { Key: opts.GetKey(opts.Config.Commits.CherryPickCopyRange), - Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.handleCopyReflogCommitRange)), + Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.copyRange)), Description: self.c.Tr.LcCherryPickCopyRange, }, { @@ -83,7 +83,7 @@ func (self *ReflogController) context() *context.ReflogCommitsContext { return self.contexts.ReflogCommits } -func (self *ReflogController) CheckoutReflogCommit(commit *models.Commit) error { +func (self *ReflogController) checkout(commit *models.Commit) error { err := self.c.Ask(types.AskOpts{ Title: self.c.Tr.LcCheckoutCommit, Prompt: self.c.Tr.SureCheckoutThisCommit, @@ -99,11 +99,11 @@ func (self *ReflogController) CheckoutReflogCommit(commit *models.Commit) error return nil } -func (self *ReflogController) handleCreateReflogResetMenu(commit *models.Commit) error { +func (self *ReflogController) openResetMenu(commit *models.Commit) error { return self.helpers.Refs.CreateGitResetMenu(commit.Sha) } -func (self *ReflogController) handleViewReflogCommitFiles(commit *models.Commit) error { +func (self *ReflogController) enter(commit *models.Commit) error { return self.switchToCommitFilesContext(SwitchToCommitFilesContextOpts{ RefName: commit.Sha, CanRebase: false, @@ -111,10 +111,10 @@ func (self *ReflogController) handleViewReflogCommitFiles(commit *models.Commit) }) } -func (self *ReflogController) handleCopyReflogCommit(commit *models.Commit) error { +func (self *ReflogController) copy(commit *models.Commit) error { return self.helpers.CherryPick.Copy(commit, self.model.FilteredReflogCommits, self.context()) } -func (self *ReflogController) handleCopyReflogCommitRange(commit *models.Commit) error { +func (self *ReflogController) copyRange(commit *models.Commit) error { return self.helpers.CherryPick.CopyRange(self.context().GetSelectedLineIdx(), self.model.FilteredReflogCommits, self.context()) } diff --git a/pkg/gui/controllers/sub_commits_controller.go b/pkg/gui/controllers/sub_commits_controller.go new file mode 100644 index 000000000..7d07fb644 --- /dev/null +++ b/pkg/gui/controllers/sub_commits_controller.go @@ -0,0 +1,131 @@ +package controllers + +import ( + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type SubCommitsController struct { + baseController + *controllerCommon + + switchToCommitFilesContext SwitchToCommitFilesContextFn +} + +var _ types.IController = &SubCommitsController{} + +func NewSubCommitsController( + common *controllerCommon, + switchToCommitFilesContext SwitchToCommitFilesContextFn, +) *SubCommitsController { + return &SubCommitsController{ + baseController: baseController{}, + controllerCommon: common, + switchToCommitFilesContext: switchToCommitFilesContext, + } +} + +func (self *SubCommitsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + bindings := []*types.Binding{ + { + Key: opts.GetKey(opts.Config.Universal.GoInto), + Handler: self.checkSelected(self.enter), + Description: self.c.Tr.LcViewCommitFiles, + }, + { + Key: opts.GetKey(opts.Config.Universal.Select), + Handler: self.checkSelected(self.checkout), + Description: self.c.Tr.LcCheckoutCommit, + }, + { + Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), + Handler: self.checkSelected(self.openResetMenu), + Description: self.c.Tr.LcViewResetOptions, + OpensMenu: true, + }, + { + Key: opts.GetKey(opts.Config.Universal.New), + Handler: self.checkSelected(self.newBranch), + Description: self.c.Tr.LcNewBranch, + }, + { + Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), + Handler: self.checkSelected(self.copy), + Description: self.c.Tr.LcCherryPickCopy, + }, + { + Key: opts.GetKey(opts.Config.Commits.CherryPickCopyRange), + Handler: self.checkSelected(self.copyRange), + Description: self.c.Tr.LcCherryPickCopyRange, + }, + { + Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), + Handler: self.helpers.CherryPick.Reset, + Description: self.c.Tr.LcResetCherryPick, + }, + } + + return bindings +} + +func (self *SubCommitsController) checkSelected(callback func(*models.Commit) error) func() error { + return func() error { + commit := self.context().GetSelected() + if commit == nil { + return nil + } + + return callback(commit) + } +} + +func (self *SubCommitsController) Context() types.Context { + return self.context() +} + +func (self *SubCommitsController) context() *context.ReflogCommitsContext { + return self.contexts.ReflogCommits +} + +func (self *SubCommitsController) checkout(commit *models.Commit) error { + err := self.c.Ask(types.AskOpts{ + Title: self.c.Tr.LcCheckoutCommit, + Prompt: self.c.Tr.SureCheckoutThisCommit, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.CheckoutCommit) + return self.helpers.Refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) + }, + }) + if err != nil { + return err + } + + self.context().SetSelectedLineIdx(0) + + return nil +} + +func (self *SubCommitsController) openResetMenu(commit *models.Commit) error { + return self.helpers.Refs.CreateGitResetMenu(commit.Sha) +} + +func (self *SubCommitsController) enter(commit *models.Commit) error { + return self.switchToCommitFilesContext(SwitchToCommitFilesContextOpts{ + RefName: commit.Sha, + CanRebase: false, + Context: self.context(), + }) +} + +func (self *SubCommitsController) newBranch(commit *models.Commit) error { + return self.helpers.Refs.NewBranch(commit.RefName(), commit.Description(), "") +} + +func (self *SubCommitsController) copy(commit *models.Commit) error { + return self.helpers.CherryPick.Copy(commit, self.model.SubCommits, self.context()) +} + +func (self *SubCommitsController) copyRange(commit *models.Commit) error { + return self.helpers.CherryPick.CopyRange(self.context().GetSelectedLineIdx(), self.model.SubCommits, self.context()) +} diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 4cdf8d8ae..c6b1cee82 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -431,56 +431,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Handler: self.handleCopySelectedSideContextItemToClipboard, Description: self.c.Tr.LcCopyCommitShaToClipboard, }, - { - ViewName: "branches", - Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Universal.GoInto), - Handler: self.handleViewSubCommitFiles, - Description: self.c.Tr.LcViewCommitFiles, - }, - { - ViewName: "branches", - Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Universal.Select), - Handler: self.handleCheckoutSubCommit, - Description: self.c.Tr.LcCheckoutCommit, - }, - { - ViewName: "branches", - Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), - Handler: self.handleCreateSubCommitResetMenu, - Description: self.c.Tr.LcViewResetOptions, - OpensMenu: true, - }, - { - ViewName: "branches", - Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Universal.New), - Handler: self.handleNewBranchOffSubCommit, - Description: self.c.Tr.LcNewBranch, - }, - { - ViewName: "branches", - Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), - Handler: self.handleCopySubCommit, - Description: self.c.Tr.LcCherryPickCopy, - }, - { - ViewName: "branches", - Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Commits.CherryPickCopyRange), - Handler: self.handleCopySubCommitRange, - Description: self.c.Tr.LcCherryPickCopyRange, - }, - { - ViewName: "branches", - Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), - Handler: self.helpers.CherryPick.Reset, - Description: self.c.Tr.LcResetCherryPick, - }, { ViewName: "branches", Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)}, diff --git a/pkg/gui/sub_commits_panel.go b/pkg/gui/sub_commits_panel.go index 0d39038d4..b79e890b9 100644 --- a/pkg/gui/sub_commits_panel.go +++ b/pkg/gui/sub_commits_panel.go @@ -1,10 +1,5 @@ package gui -import ( - "github.com/jesseduffield/lazygit/pkg/gui/controllers" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - // list panel functions func (gui *Gui) subCommitsRenderToMain() error { @@ -25,73 +20,3 @@ func (gui *Gui) subCommitsRenderToMain() error { }, }) } - -func (gui *Gui) handleCheckoutSubCommit() error { - commit := gui.State.Contexts.SubCommits.GetSelected() - if commit == nil { - return nil - } - - err := gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.LcCheckoutCommit, - Prompt: gui.c.Tr.SureCheckoutThisCommit, - HandleConfirm: func() error { - gui.c.LogAction(gui.c.Tr.Actions.CheckoutCommit) - return gui.helpers.Refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) - }, - }) - if err != nil { - return err - } - - gui.State.Contexts.SubCommits.SetSelectedLineIdx(0) - - return nil -} - -func (gui *Gui) handleCreateSubCommitResetMenu() error { - commit := gui.State.Contexts.SubCommits.GetSelected() - - return gui.helpers.Refs.CreateGitResetMenu(commit.Sha) -} - -func (gui *Gui) handleViewSubCommitFiles() error { - commit := gui.State.Contexts.SubCommits.GetSelected() - if commit == nil { - return nil - } - - return gui.SwitchToCommitFilesContext(controllers.SwitchToCommitFilesContextOpts{ - RefName: commit.Sha, - CanRebase: false, - Context: gui.State.Contexts.SubCommits, - }) -} - -func (gui *Gui) handleNewBranchOffSubCommit() error { - commit := gui.State.Contexts.SubCommits.GetSelected() - if commit == nil { - return nil - } - - return gui.helpers.Refs.NewBranch(commit.RefName(), commit.Description(), "") -} - -func (gui *Gui) handleCopySubCommit() error { - commit := gui.State.Contexts.SubCommits.GetSelected() - if commit == nil { - return nil - } - - return gui.helpers.CherryPick.Copy(commit, gui.State.Model.SubCommits, gui.State.Contexts.SubCommits) -} - -func (gui *Gui) handleCopySubCommitRange() error { - // just doing this to ensure something is selected - commit := gui.State.Contexts.SubCommits.GetSelected() - if commit == nil { - return nil - } - - return gui.helpers.CherryPick.CopyRange(gui.State.Contexts.SubCommits.GetSelectedLineIdx(), gui.State.Model.SubCommits, gui.State.Contexts.SubCommits) -} From 574c5ca0de046fc0572e722822db3bfbddff4d10 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 17:41:58 +1100 Subject: [PATCH 066/385] add subcommits controller --- pkg/gui/gui.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index e0f6eb41f..525521fc0 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -535,6 +535,7 @@ func (gui *Gui) resetControllers() { bisectController := controllers.NewBisectController(common) reflogController := controllers.NewReflogController(common, gui.SwitchToCommitFilesContext) + subCommitsController := controllers.NewSubCommitsController(common, gui.SwitchToCommitFilesContext) gui.Controllers = Controllers{ Submodules: submodulesController, @@ -583,6 +584,7 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(gui.State.Contexts.Submodules, gui.Controllers.Submodules) controllers.AttachControllers(gui.State.Contexts.LocalCommits, gui.Controllers.LocalCommits, bisectController) controllers.AttachControllers(gui.State.Contexts.ReflogCommits, reflogController) + controllers.AttachControllers(gui.State.Contexts.SubCommits, subCommitsController) controllers.AttachControllers(gui.State.Contexts.Remotes, gui.Controllers.Remotes) controllers.AttachControllers(gui.State.Contexts.Menu, gui.Controllers.Menu) controllers.AttachControllers(gui.State.Contexts.Global, gui.Controllers.Sync, gui.Controllers.Undo, gui.Controllers.Global) From bef26b9634a6a4c85028dcb1577161ed2c662b4e Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 17:54:36 +1100 Subject: [PATCH 067/385] add common commit controller --- pkg/gui/context/local_commits_context.go | 4 + pkg/gui/context/reflog_commits_context.go | 4 + pkg/gui/context/sub_commits_context.go | 4 + .../controllers/common_commit_controller.go | 81 +++++++++++++++++++ .../controllers/local_commits_controller.go | 13 --- pkg/gui/controllers/reflog_controller.go | 13 --- pkg/gui/controllers/sub_commits_controller.go | 13 --- pkg/gui/gui.go | 13 +++ 8 files changed, 106 insertions(+), 39 deletions(-) create mode 100644 pkg/gui/controllers/common_commit_controller.go diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index 408a906ba..1937995ff 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -82,6 +82,10 @@ func NewLocalCommitsViewModel(getModel func() []*models.Commit) *LocalCommitsVie return self } +func (self *LocalCommitsContext) CanRebase() bool { + return true +} + func (self *LocalCommitsViewModel) GetItemsLength() int { return len(self.getModel()) } diff --git a/pkg/gui/context/reflog_commits_context.go b/pkg/gui/context/reflog_commits_context.go index 4a53fe393..8e0dfb8ba 100644 --- a/pkg/gui/context/reflog_commits_context.go +++ b/pkg/gui/context/reflog_commits_context.go @@ -58,6 +58,10 @@ func (self *ReflogCommitsContext) GetSelectedItemId() string { return item.ID() } +func (self *ReflogCommitsContext) CanRebase() bool { + return false +} + type ReflogCommitsViewModel struct { *traits.ListCursor getModel func() []*models.Commit diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go index 10c2cf41a..b12d86f13 100644 --- a/pkg/gui/context/sub_commits_context.go +++ b/pkg/gui/context/sub_commits_context.go @@ -59,6 +59,10 @@ func (self *SubCommitsContext) GetSelectedItemId() string { return item.ID() } +func (self *SubCommitsContext) CanRebase() bool { + return false +} + type SubCommitsViewModel struct { *traits.ListCursor getModel func() []*models.Commit diff --git a/pkg/gui/controllers/common_commit_controller.go b/pkg/gui/controllers/common_commit_controller.go new file mode 100644 index 000000000..f6ae68eab --- /dev/null +++ b/pkg/gui/controllers/common_commit_controller.go @@ -0,0 +1,81 @@ +package controllers + +import ( + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type CommonCommitControllerFactory struct { + controllerCommon *controllerCommon + viewFiles func(SwitchToCommitFilesContextOpts) error +} + +var _ types.IController = &CommonCommitController{} + +type CommitContext interface { + types.Context + CanRebase() bool + GetSelected() *models.Commit +} + +type CommonCommitController struct { + baseController + *controllerCommon + context CommitContext + + viewFiles func(SwitchToCommitFilesContextOpts) error +} + +func NewCommonCommitControllerFactory( + common *controllerCommon, + viewFiles func(SwitchToCommitFilesContextOpts) error, +) *CommonCommitControllerFactory { + return &CommonCommitControllerFactory{ + controllerCommon: common, + viewFiles: viewFiles, + } +} + +func (self *CommonCommitControllerFactory) Create(context CommitContext) *CommonCommitController { + return &CommonCommitController{ + baseController: baseController{}, + controllerCommon: self.controllerCommon, + context: context, + viewFiles: self.viewFiles, + } +} + +func (self *CommonCommitController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + bindings := []*types.Binding{ + { + Key: opts.GetKey(opts.Config.Universal.GoInto), + Handler: self.checkSelected(self.enter), + Description: self.c.Tr.LcViewCommitFiles, + }, + } + + return bindings +} + +func (self *CommonCommitController) checkSelected(callback func(*models.Commit) error) func() error { + return func() error { + commit := self.context.GetSelected() + if commit == nil { + return nil + } + + return callback(commit) + } +} + +func (self *CommonCommitController) enter(commit *models.Commit) error { + return self.viewFiles(SwitchToCommitFilesContextOpts{ + RefName: commit.Sha, + CanRebase: self.context.CanRebase(), + Context: self.context, + }) +} + +func (self *CommonCommitController) Context() types.Context { + return self.context +} diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index d071ab3fb..694d7396f 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -162,11 +162,6 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ Handler: self.checkSelected(self.handleCreateCommitResetMenu), Description: self.c.Tr.LcResetToThisCommit, }, - { - Key: opts.GetKey(opts.Config.Universal.GoInto), - Handler: self.checkSelected(self.enter), - Description: self.c.Tr.LcViewCommitFiles, - }, { Key: opts.GetKey(opts.Config.Commits.CheckoutCommit), Handler: self.checkSelected(self.handleCheckoutCommit), @@ -516,14 +511,6 @@ func (self *LocalCommitsController) afterRevertCommit() error { }) } -func (self *LocalCommitsController) enter(commit *models.Commit) error { - return self.switchToCommitFilesContext(SwitchToCommitFilesContextOpts{ - RefName: commit.Sha, - CanRebase: true, - Context: self.context(), - }) -} - func (self *LocalCommitsController) handleCreateFixupCommit(commit *models.Commit) error { prompt := utils.ResolvePlaceholderString( self.c.Tr.SureCreateFixupCommit, diff --git a/pkg/gui/controllers/reflog_controller.go b/pkg/gui/controllers/reflog_controller.go index 549348040..43413a6ac 100644 --- a/pkg/gui/controllers/reflog_controller.go +++ b/pkg/gui/controllers/reflog_controller.go @@ -28,11 +28,6 @@ func NewReflogController( func (self *ReflogController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ - { - Key: opts.GetKey(opts.Config.Universal.GoInto), - Handler: self.checkSelected(self.enter), - Description: self.c.Tr.LcViewCommitFiles, - }, { Key: opts.GetKey(opts.Config.Universal.Select), Handler: self.checkSelected(self.checkout), @@ -103,14 +98,6 @@ func (self *ReflogController) openResetMenu(commit *models.Commit) error { return self.helpers.Refs.CreateGitResetMenu(commit.Sha) } -func (self *ReflogController) enter(commit *models.Commit) error { - return self.switchToCommitFilesContext(SwitchToCommitFilesContextOpts{ - RefName: commit.Sha, - CanRebase: false, - Context: self.context(), - }) -} - func (self *ReflogController) copy(commit *models.Commit) error { return self.helpers.CherryPick.Copy(commit, self.model.FilteredReflogCommits, self.context()) } diff --git a/pkg/gui/controllers/sub_commits_controller.go b/pkg/gui/controllers/sub_commits_controller.go index 7d07fb644..300f5b3fa 100644 --- a/pkg/gui/controllers/sub_commits_controller.go +++ b/pkg/gui/controllers/sub_commits_controller.go @@ -28,11 +28,6 @@ func NewSubCommitsController( func (self *SubCommitsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ - { - Key: opts.GetKey(opts.Config.Universal.GoInto), - Handler: self.checkSelected(self.enter), - Description: self.c.Tr.LcViewCommitFiles, - }, { Key: opts.GetKey(opts.Config.Universal.Select), Handler: self.checkSelected(self.checkout), @@ -110,14 +105,6 @@ func (self *SubCommitsController) openResetMenu(commit *models.Commit) error { return self.helpers.Refs.CreateGitResetMenu(commit.Sha) } -func (self *SubCommitsController) enter(commit *models.Commit) error { - return self.switchToCommitFilesContext(SwitchToCommitFilesContextOpts{ - RefName: commit.Sha, - CanRebase: false, - Context: self.context(), - }) -} - func (self *SubCommitsController) newBranch(commit *models.Commit) error { return self.helpers.Refs.NewBranch(commit.RefName(), commit.Description(), "") } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 525521fc0..4e5007f1a 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -578,6 +578,19 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(context, switchToSubCommitsControllerFactory.Create(context)) } + commonCommitControllerFactory := controllers.NewCommonCommitControllerFactory( + common, + gui.SwitchToCommitFilesContext, + ) + + for _, context := range []controllers.CommitContext{ + gui.State.Contexts.LocalCommits, + gui.State.Contexts.ReflogCommits, + gui.State.Contexts.SubCommits, + } { + controllers.AttachControllers(context, commonCommitControllerFactory.Create(context)) + } + controllers.AttachControllers(gui.State.Contexts.Branches, branchesController) controllers.AttachControllers(gui.State.Contexts.Files, gui.Controllers.Files) controllers.AttachControllers(gui.State.Contexts.Tags, gui.Controllers.Tags) From 8a555dd62ebdb985041f421dca650b941007afc1 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 18:04:09 +1100 Subject: [PATCH 068/385] refactor --- pkg/gui/controllers/files_controller.go | 28 ------- ...r_remove.go => files_remove_controller.go} | 74 ++++++++++++++++++- pkg/gui/gui.go | 3 +- 3 files changed, 75 insertions(+), 30 deletions(-) rename pkg/gui/controllers/{files_controller_remove.go => files_remove_controller.go} (56%) diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index 6868586e6..018322f1a 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -98,12 +98,6 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types Handler: self.checkSelectedFileNode(self.ignore), Description: self.c.Tr.LcIgnoreFile, }, - { - Key: opts.GetKey(opts.Config.Universal.Remove), - Handler: self.checkSelectedFileNode(self.remove), - Description: self.c.Tr.LcViewDiscardOptions, - OpensMenu: true, - }, { Key: opts.GetKey(opts.Config.Files.RefreshFiles), Handler: self.refresh, @@ -619,28 +613,6 @@ func (self *FilesController) OpenMergeTool() error { }) } -func (self *FilesController) ResetSubmodule(submodule *models.SubmoduleConfig) error { - return self.c.WithWaitingStatus(self.c.Tr.LcResettingSubmoduleStatus, func() error { - self.c.LogAction(self.c.Tr.Actions.ResetSubmodule) - - file := self.helpers.WorkingTree.FileForSubmodule(submodule) - if file != nil { - if err := self.git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil { - return self.c.Error(err) - } - } - - if err := self.git.Submodule.Stash(submodule); err != nil { - return self.c.Error(err) - } - if err := self.git.Submodule.Reset(submodule); err != nil { - return self.c.Error(err) - } - - return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.SUBMODULES}}) - }) -} - func (self *FilesController) handleStashSave(stashFunc func(message string) error) error { if !self.helpers.WorkingTree.IsWorkingTreeDirty() { return self.c.ErrorMsg(self.c.Tr.NoTrackedStagedFilesStash) diff --git a/pkg/gui/controllers/files_controller_remove.go b/pkg/gui/controllers/files_remove_controller.go similarity index 56% rename from pkg/gui/controllers/files_controller_remove.go rename to pkg/gui/controllers/files_remove_controller.go index cdebf8914..521167c33 100644 --- a/pkg/gui/controllers/files_controller_remove.go +++ b/pkg/gui/controllers/files_remove_controller.go @@ -1,13 +1,44 @@ package controllers import ( + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/types" ) // splitting this action out into its own file because it's self-contained -func (self *FilesController) remove(node *filetree.FileNode) error { +type FilesRemoveController struct { + baseController + *controllerCommon +} + +var _ types.IController = &FilesRemoveController{} + +func NewFilesRemoveController( + common *controllerCommon, +) *FilesRemoveController { + return &FilesRemoveController{ + baseController: baseController{}, + controllerCommon: common, + } +} + +func (self *FilesRemoveController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + bindings := []*types.Binding{ + { + Key: opts.GetKey(opts.Config.Universal.Remove), + Handler: self.checkSelectedFileNode(self.remove), + Description: self.c.Tr.LcViewDiscardOptions, + OpensMenu: true, + }, + } + + return bindings +} + +func (self *FilesRemoveController) remove(node *filetree.FileNode) error { var menuItems []*types.MenuItem if node.File == nil { menuItems = []*types.MenuItem{ @@ -83,3 +114,44 @@ func (self *FilesController) remove(node *filetree.FileNode) error { return self.c.Menu(types.CreateMenuOptions{Title: node.GetPath(), Items: menuItems}) } + +func (self *FilesRemoveController) ResetSubmodule(submodule *models.SubmoduleConfig) error { + return self.c.WithWaitingStatus(self.c.Tr.LcResettingSubmoduleStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.ResetSubmodule) + + file := self.helpers.WorkingTree.FileForSubmodule(submodule) + if file != nil { + if err := self.git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil { + return self.c.Error(err) + } + } + + if err := self.git.Submodule.Stash(submodule); err != nil { + return self.c.Error(err) + } + if err := self.git.Submodule.Reset(submodule); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES, types.SUBMODULES}}) + }) +} + +func (self *FilesRemoveController) checkSelectedFileNode(callback func(*filetree.FileNode) error) func() error { + return func() error { + node := self.context().GetSelectedFileNode() + if node == nil { + return nil + } + + return callback(node) + } +} + +func (self *FilesRemoveController) Context() types.Context { + return self.context() +} + +func (self *FilesRemoveController) context() *context.WorkingTreeContext { + return self.contexts.Files +} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 4e5007f1a..069d8a5a7 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -564,6 +564,7 @@ func (gui *Gui) resetControllers() { } branchesController := controllers.NewBranchesController(common) + filesRemoveController := controllers.NewFilesRemoveController(common) switchToSubCommitsControllerFactory := controllers.NewSubCommitsSwitchControllerFactory( common, @@ -592,7 +593,7 @@ func (gui *Gui) resetControllers() { } controllers.AttachControllers(gui.State.Contexts.Branches, branchesController) - controllers.AttachControllers(gui.State.Contexts.Files, gui.Controllers.Files) + controllers.AttachControllers(gui.State.Contexts.Files, gui.Controllers.Files, filesRemoveController) controllers.AttachControllers(gui.State.Contexts.Tags, gui.Controllers.Tags) controllers.AttachControllers(gui.State.Contexts.Submodules, gui.Controllers.Submodules) controllers.AttachControllers(gui.State.Contexts.LocalCommits, gui.Controllers.LocalCommits, bisectController) From e842d1bc9e2db9436fe968a9fad7aacca78570ea Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 18:12:21 +1100 Subject: [PATCH 069/385] move git flow --- pkg/gui/controllers/git_flow_controller.go | 119 +++++++++++++++++++++ pkg/gui/git_flow.go | 74 ------------- pkg/gui/gui.go | 3 +- pkg/gui/keybindings.go | 8 -- 4 files changed, 121 insertions(+), 83 deletions(-) create mode 100644 pkg/gui/controllers/git_flow_controller.go delete mode 100644 pkg/gui/git_flow.go diff --git a/pkg/gui/controllers/git_flow_controller.go b/pkg/gui/controllers/git_flow_controller.go new file mode 100644 index 000000000..a6d8f1da4 --- /dev/null +++ b/pkg/gui/controllers/git_flow_controller.go @@ -0,0 +1,119 @@ +package controllers + +import ( + "fmt" + + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +type GitFlowController struct { + baseController + *controllerCommon +} + +var _ types.IController = &GitFlowController{} + +func NewGitFlowController( + common *controllerCommon, +) *GitFlowController { + return &GitFlowController{ + baseController: baseController{}, + controllerCommon: common, + } +} + +func (self *GitFlowController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + bindings := []*types.Binding{ + { + Key: opts.GetKey(opts.Config.Branches.ViewGitFlowOptions), + Handler: self.checkSelected(self.handleCreateGitFlowMenu), + Description: self.c.Tr.LcGitFlowOptions, + OpensMenu: true, + }, + } + + return bindings +} + +func (self *GitFlowController) handleCreateGitFlowMenu(branch *models.Branch) error { + if !self.git.Flow.GitFlowEnabled() { + return self.c.ErrorMsg("You need to install git-flow and enable it in this repo to use git-flow features") + } + + startHandler := func(branchType string) func() error { + return func() error { + title := utils.ResolvePlaceholderString(self.c.Tr.NewGitFlowBranchPrompt, map[string]string{"branchType": branchType}) + + return self.c.Prompt(types.PromptOpts{ + Title: title, + HandleConfirm: func(name string) error { + self.c.LogAction(self.c.Tr.Actions.GitFlowStart) + return self.c.RunSubprocessAndRefresh( + self.git.Flow.StartCmdObj(branchType, name), + ) + }, + }) + } + } + + return self.c.Menu(types.CreateMenuOptions{ + Title: "git flow", + Items: []*types.MenuItem{ + { + // not localising here because it's one to one with the actual git flow commands + DisplayString: fmt.Sprintf("finish branch '%s'", branch.Name), + OnPress: func() error { + return self.gitFlowFinishBranch(branch.Name) + }, + }, + { + DisplayString: "start feature", + OnPress: startHandler("feature"), + }, + { + DisplayString: "start hotfix", + OnPress: startHandler("hotfix"), + }, + { + DisplayString: "start bugfix", + OnPress: startHandler("bugfix"), + }, + { + DisplayString: "start release", + OnPress: startHandler("release"), + }, + }, + }) +} + +func (self *GitFlowController) gitFlowFinishBranch(branchName string) error { + cmdObj, err := self.git.Flow.FinishCmdObj(branchName) + if err != nil { + return self.c.Error(err) + } + + self.c.LogAction(self.c.Tr.Actions.GitFlowFinish) + return self.c.RunSubprocessAndRefresh(cmdObj) +} + +func (self *GitFlowController) checkSelected(callback func(*models.Branch) error) func() error { + return func() error { + node := self.context().GetSelected() + if node == nil { + return nil + } + + return callback(node) + } +} + +func (self *GitFlowController) Context() types.Context { + return self.context() +} + +func (self *GitFlowController) context() *context.BranchesContext { + return self.contexts.Branches +} diff --git a/pkg/gui/git_flow.go b/pkg/gui/git_flow.go deleted file mode 100644 index c26b94a70..000000000 --- a/pkg/gui/git_flow.go +++ /dev/null @@ -1,74 +0,0 @@ -package gui - -import ( - "fmt" - - "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/jesseduffield/lazygit/pkg/utils" -) - -func (gui *Gui) handleCreateGitFlowMenu() error { - branch := gui.State.Contexts.Branches.GetSelected() - if branch == nil { - return nil - } - - if !gui.git.Flow.GitFlowEnabled() { - return gui.c.ErrorMsg("You need to install git-flow and enable it in this repo to use git-flow features") - } - - startHandler := func(branchType string) func() error { - return func() error { - title := utils.ResolvePlaceholderString(gui.c.Tr.NewGitFlowBranchPrompt, map[string]string{"branchType": branchType}) - - return gui.c.Prompt(types.PromptOpts{ - Title: title, - HandleConfirm: func(name string) error { - gui.c.LogAction(gui.c.Tr.Actions.GitFlowStart) - return gui.runSubprocessWithSuspenseAndRefresh( - gui.git.Flow.StartCmdObj(branchType, name), - ) - }, - }) - } - } - - return gui.c.Menu(types.CreateMenuOptions{ - Title: "git flow", - Items: []*types.MenuItem{ - { - // not localising here because it's one to one with the actual git flow commands - DisplayString: fmt.Sprintf("finish branch '%s'", branch.Name), - OnPress: func() error { - return gui.gitFlowFinishBranch(branch.Name) - }, - }, - { - DisplayString: "start feature", - OnPress: startHandler("feature"), - }, - { - DisplayString: "start hotfix", - OnPress: startHandler("hotfix"), - }, - { - DisplayString: "start bugfix", - OnPress: startHandler("bugfix"), - }, - { - DisplayString: "start release", - OnPress: startHandler("release"), - }, - }, - }) -} - -func (gui *Gui) gitFlowFinishBranch(branchName string) error { - cmdObj, err := gui.git.Flow.FinishCmdObj(branchName) - if err != nil { - return gui.c.Error(err) - } - - gui.c.LogAction(gui.c.Tr.Actions.GitFlowFinish) - return gui.runSubprocessWithSuspenseAndRefresh(cmdObj) -} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 069d8a5a7..77b406e6f 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -564,6 +564,7 @@ func (gui *Gui) resetControllers() { } branchesController := controllers.NewBranchesController(common) + gitFlowController := controllers.NewGitFlowController(common) filesRemoveController := controllers.NewFilesRemoveController(common) switchToSubCommitsControllerFactory := controllers.NewSubCommitsSwitchControllerFactory( @@ -592,7 +593,7 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(context, commonCommitControllerFactory.Create(context)) } - controllers.AttachControllers(gui.State.Contexts.Branches, branchesController) + controllers.AttachControllers(gui.State.Contexts.Branches, branchesController, gitFlowController) controllers.AttachControllers(gui.State.Contexts.Files, gui.Controllers.Files, filesRemoveController) controllers.AttachControllers(gui.State.Contexts.Tags, gui.Controllers.Tags) controllers.AttachControllers(gui.State.Contexts.Submodules, gui.Controllers.Submodules) diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index c6b1cee82..9d278aa2d 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -380,14 +380,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Handler: self.handleCopySelectedSideContextItemToClipboard, Description: self.c.Tr.LcCopyFileNameToClipboard, }, - { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Branches.ViewGitFlowOptions), - Handler: self.handleCreateGitFlowMenu, - Description: self.c.Tr.LcGitFlowOptions, - OpensMenu: true, - }, { ViewName: "branches", Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, From a643957f89c85fc304b78e3a6aad6e5c1a365d50 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 18:26:44 +1100 Subject: [PATCH 070/385] include stash in commitish controller --- pkg/gui/context/local_commits_context.go | 10 +++ pkg/gui/context/reflog_commits_context.go | 10 +++ pkg/gui/context/stash_context.go | 14 ++++ pkg/gui/context/sub_commits_context.go | 10 +++ pkg/gui/controllers/commitish_controller.go | 82 +++++++++++++++++++ .../controllers/common_commit_controller.go | 81 ------------------ pkg/gui/gui.go | 7 +- pkg/gui/keybindings.go | 6 -- pkg/gui/stash_panel.go | 14 ---- pkg/i18n/chinese.go | 3 +- pkg/i18n/dutch.go | 3 +- pkg/i18n/english.go | 6 +- pkg/i18n/polish.go | 2 +- 13 files changed, 135 insertions(+), 113 deletions(-) create mode 100644 pkg/gui/controllers/commitish_controller.go delete mode 100644 pkg/gui/controllers/common_commit_controller.go diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index 1937995ff..2930348e8 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -86,6 +86,16 @@ func (self *LocalCommitsContext) CanRebase() bool { return true } +func (self *LocalCommitsContext) GetSelectedRefName() string { + item := self.GetSelected() + + if item == nil { + return "" + } + + return item.RefName() +} + func (self *LocalCommitsViewModel) GetItemsLength() int { return len(self.getModel()) } diff --git a/pkg/gui/context/reflog_commits_context.go b/pkg/gui/context/reflog_commits_context.go index 8e0dfb8ba..fa136a7d4 100644 --- a/pkg/gui/context/reflog_commits_context.go +++ b/pkg/gui/context/reflog_commits_context.go @@ -62,6 +62,16 @@ func (self *ReflogCommitsContext) CanRebase() bool { return false } +func (self *ReflogCommitsContext) GetSelectedRefName() string { + item := self.GetSelected() + + if item == nil { + return "" + } + + return item.RefName() +} + type ReflogCommitsViewModel struct { *traits.ListCursor getModel func() []*models.Commit diff --git a/pkg/gui/context/stash_context.go b/pkg/gui/context/stash_context.go index 95efeaef1..d538fadf1 100644 --- a/pkg/gui/context/stash_context.go +++ b/pkg/gui/context/stash_context.go @@ -58,6 +58,20 @@ func (self *StashContext) GetSelectedItemId() string { return item.ID() } +func (self *StashContext) CanRebase() bool { + return false +} + +func (self *StashContext) GetSelectedRefName() string { + item := self.GetSelected() + + if item == nil { + return "" + } + + return item.RefName() +} + type StashViewModel struct { *traits.ListCursor getModel func() []*models.StashEntry diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go index b12d86f13..83e76e1e0 100644 --- a/pkg/gui/context/sub_commits_context.go +++ b/pkg/gui/context/sub_commits_context.go @@ -63,6 +63,16 @@ func (self *SubCommitsContext) CanRebase() bool { return false } +func (self *SubCommitsContext) GetSelectedRefName() string { + item := self.GetSelected() + + if item == nil { + return "" + } + + return item.RefName() +} + type SubCommitsViewModel struct { *traits.ListCursor getModel func() []*models.Commit diff --git a/pkg/gui/controllers/commitish_controller.go b/pkg/gui/controllers/commitish_controller.go new file mode 100644 index 000000000..b570e4aba --- /dev/null +++ b/pkg/gui/controllers/commitish_controller.go @@ -0,0 +1,82 @@ +package controllers + +import ( + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +// This controller is for all contexts that contain commit files. + +type CommitishControllerFactory struct { + controllerCommon *controllerCommon + viewFiles func(SwitchToCommitFilesContextOpts) error +} + +var _ types.IController = &CommitishController{} + +type Commitish interface { + types.Context + CanRebase() bool + GetSelectedRefName() string +} + +type CommitishController struct { + baseController + *controllerCommon + context Commitish + + viewFiles func(SwitchToCommitFilesContextOpts) error +} + +func NewCommitishControllerFactory( + common *controllerCommon, + viewFiles func(SwitchToCommitFilesContextOpts) error, +) *CommitishControllerFactory { + return &CommitishControllerFactory{ + controllerCommon: common, + viewFiles: viewFiles, + } +} + +func (self *CommitishControllerFactory) Create(context Commitish) *CommitishController { + return &CommitishController{ + baseController: baseController{}, + controllerCommon: self.controllerCommon, + context: context, + viewFiles: self.viewFiles, + } +} + +func (self *CommitishController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + bindings := []*types.Binding{ + { + Key: opts.GetKey(opts.Config.Universal.GoInto), + Handler: self.checkSelected(self.enter), + Description: self.c.Tr.LcViewItemFiles, + }, + } + + return bindings +} + +func (self *CommitishController) checkSelected(callback func(string) error) func() error { + return func() error { + refName := self.context.GetSelectedRefName() + if refName == "" { + return nil + } + + return callback(refName) + } +} + +func (self *CommitishController) enter(refName string) error { + return self.viewFiles(SwitchToCommitFilesContextOpts{ + RefName: refName, + CanRebase: self.context.CanRebase(), + Context: self.context, + }) +} + +func (self *CommitishController) Context() types.Context { + return self.context +} diff --git a/pkg/gui/controllers/common_commit_controller.go b/pkg/gui/controllers/common_commit_controller.go deleted file mode 100644 index f6ae68eab..000000000 --- a/pkg/gui/controllers/common_commit_controller.go +++ /dev/null @@ -1,81 +0,0 @@ -package controllers - -import ( - "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - -type CommonCommitControllerFactory struct { - controllerCommon *controllerCommon - viewFiles func(SwitchToCommitFilesContextOpts) error -} - -var _ types.IController = &CommonCommitController{} - -type CommitContext interface { - types.Context - CanRebase() bool - GetSelected() *models.Commit -} - -type CommonCommitController struct { - baseController - *controllerCommon - context CommitContext - - viewFiles func(SwitchToCommitFilesContextOpts) error -} - -func NewCommonCommitControllerFactory( - common *controllerCommon, - viewFiles func(SwitchToCommitFilesContextOpts) error, -) *CommonCommitControllerFactory { - return &CommonCommitControllerFactory{ - controllerCommon: common, - viewFiles: viewFiles, - } -} - -func (self *CommonCommitControllerFactory) Create(context CommitContext) *CommonCommitController { - return &CommonCommitController{ - baseController: baseController{}, - controllerCommon: self.controllerCommon, - context: context, - viewFiles: self.viewFiles, - } -} - -func (self *CommonCommitController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { - bindings := []*types.Binding{ - { - Key: opts.GetKey(opts.Config.Universal.GoInto), - Handler: self.checkSelected(self.enter), - Description: self.c.Tr.LcViewCommitFiles, - }, - } - - return bindings -} - -func (self *CommonCommitController) checkSelected(callback func(*models.Commit) error) func() error { - return func() error { - commit := self.context.GetSelected() - if commit == nil { - return nil - } - - return callback(commit) - } -} - -func (self *CommonCommitController) enter(commit *models.Commit) error { - return self.viewFiles(SwitchToCommitFilesContextOpts{ - RefName: commit.Sha, - CanRebase: self.context.CanRebase(), - Context: self.context, - }) -} - -func (self *CommonCommitController) Context() types.Context { - return self.context -} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 77b406e6f..a31c781ed 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -580,17 +580,18 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(context, switchToSubCommitsControllerFactory.Create(context)) } - commonCommitControllerFactory := controllers.NewCommonCommitControllerFactory( + commitishControllerFactory := controllers.NewCommitishControllerFactory( common, gui.SwitchToCommitFilesContext, ) - for _, context := range []controllers.CommitContext{ + for _, context := range []controllers.Commitish{ gui.State.Contexts.LocalCommits, gui.State.Contexts.ReflogCommits, gui.State.Contexts.SubCommits, + gui.State.Contexts.Stash, } { - controllers.AttachControllers(context, commonCommitControllerFactory.Create(context)) + controllers.AttachControllers(context, commitishControllerFactory.Create(context)) } controllers.AttachControllers(gui.State.Contexts.Branches, branchesController, gitFlowController) diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 9d278aa2d..ba30bd407 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -430,12 +430,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Handler: self.handleCopySelectedSideContextItemToClipboard, Description: self.c.Tr.LcCopyCommitShaToClipboard, }, - { - ViewName: "stash", - Key: opts.GetKey(opts.Config.Universal.GoInto), - Handler: self.handleViewStashFiles, - Description: self.c.Tr.LcViewStashFiles, - }, { ViewName: "stash", Key: opts.GetKey(opts.Config.Universal.Select), diff --git a/pkg/gui/stash_panel.go b/pkg/gui/stash_panel.go index 6da862004..c0110f553 100644 --- a/pkg/gui/stash_panel.go +++ b/pkg/gui/stash_panel.go @@ -2,7 +2,6 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/controllers" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -114,19 +113,6 @@ func (gui *Gui) postStashRefresh() error { return gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}}) } -func (gui *Gui) handleViewStashFiles() error { - stashEntry := gui.getSelectedStashEntry() - if stashEntry == nil { - return nil - } - - return gui.SwitchToCommitFilesContext(controllers.SwitchToCommitFilesContextOpts{ - RefName: stashEntry.RefName(), - CanRebase: false, - Context: gui.State.Contexts.Stash, - }) -} - func (gui *Gui) handleNewBranchOffStashEntry() error { stashEntry := gui.getSelectedStashEntry() if stashEntry == nil { diff --git a/pkg/i18n/chinese.go b/pkg/i18n/chinese.go index ac4e53b1b..551f55750 100644 --- a/pkg/i18n/chinese.go +++ b/pkg/i18n/chinese.go @@ -245,7 +245,7 @@ func chineseTranslationSet() TranslationSet { CheckingOutStatus: "妫鍑", CommittingStatus: "姝e湪鎻愪氦", CommitFiles: "鎻愪氦鏂囦欢", - LcViewCommitFiles: "鏌ョ湅鎻愪氦鐨勬枃浠", + LcViewItemFiles: "鏌ョ湅鎻愪氦鐨勬枃浠", CommitFilesTitle: "鎻愪氦鏂囦欢", LcCheckoutCommitFile: "妫鍑烘枃浠", LcDiscardOldFileChange: "鏀惧純瀵规鏂囦欢鐨勬彁浜ゆ洿鏀", @@ -380,7 +380,6 @@ func chineseTranslationSet() TranslationSet { UnstageLinesTitle: "鏈殏瀛樼殑琛", UnstageLinesPrompt: "鎮ㄧ‘瀹氳鍒犻櫎鎵閫夌殑琛岋紙git reset锛夊悧锛熻繖鏄笉鍙嗙殑銆俓n瑕佺鐢ㄦ瀵硅瘽妗嗭紝璇峰皢 'gui.skipUnstageLineWarning' 鐨勯厤缃敭璁剧疆涓 true", LcCreateNewBranchFromCommit: "浠庢彁浜ゅ垱寤烘柊鍒嗘敮", - LcViewStashFiles: "鏌ョ湅璐棌鏉$洰涓殑鏂囦欢", LcBuildingPatch: "姝e湪鏋勫缓琛ヤ竵", LcViewCommits: "鏌ョ湅鎻愪氦", MinGitVersionError: "Git 鐗堟湰蹇呴』鑷冲皯涓 2.0锛堝嵆浠 2014 骞村紑濮嬶級銆傝鍗囩骇鎮ㄧ殑 git 鐗堟湰銆傛垨鑰呭湪 https://github.com/jesseduffield/lazygit/issues 涓婃彁鍑轰竴涓棶棰橈紝浠ヤ娇 lazygit 鏇村姞鍚戝悗鍏煎銆", diff --git a/pkg/i18n/dutch.go b/pkg/i18n/dutch.go index c7b31e157..147cf3c6e 100644 --- a/pkg/i18n/dutch.go +++ b/pkg/i18n/dutch.go @@ -214,7 +214,7 @@ func dutchTranslationSet() TranslationSet { RedoingStatus: "redoing", CheckingOutStatus: "uitchecken", CommitFiles: "Commit bestanden", - LcViewCommitFiles: "bekijk gecommite bestanden", + LcViewItemFiles: "bekijk gecommite bestanden", CommitFilesTitle: "Commit bestanden", LcCheckoutCommitFile: "bestand uitchecken", LcDiscardOldFileChange: "uitsluit deze commit zijn veranderingen aan dit bestand", @@ -357,7 +357,6 @@ func dutchTranslationSet() TranslationSet { LcAddSubmodule: "voeg nieuwe submodule toe", LcInitSubmodule: "initialiseer submodule", LcViewBulkSubmoduleOptions: "bekijk bulk submodule opties", - LcViewStashFiles: "bekijk bestanden van stash entry", CreatePullRequestOptions: "Bekijk opties voor pull-aanvraag", LcCreatePullRequestOptions: "bekijk opties voor pull-aanvraag", ConfirmRevertCommit: "Weet u zeker dat u {{.selectedCommit}} ongedaan wilt maken?", diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 711ec02da..649b04fd9 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -231,7 +231,7 @@ type TranslationSet struct { CheckingOutStatus string CommittingStatus string CommitFiles string - LcViewCommitFiles string + LcViewItemFiles string CommitFilesTitle string LcCheckoutCommitFile string LcDiscardOldFileChange string @@ -375,7 +375,6 @@ type TranslationSet struct { UnstageLinesTitle string UnstageLinesPrompt string LcCreateNewBranchFromCommit string - LcViewStashFiles string LcBuildingPatch string LcViewCommits string MinGitVersionError string @@ -804,7 +803,7 @@ func EnglishTranslationSet() TranslationSet { CheckingOutStatus: "checking out", CommittingStatus: "committing", CommitFiles: "Commit files", - LcViewCommitFiles: "view commit's files", + LcViewItemFiles: "view selected item's files", CommitFilesTitle: "Commit Files", LcCheckoutCommitFile: "checkout file", LcDiscardOldFileChange: "discard this commit's changes to this file", @@ -949,7 +948,6 @@ func EnglishTranslationSet() TranslationSet { UnstageLinesTitle: "Unstage lines", UnstageLinesPrompt: "Are you sure you want to delete the selected lines (git reset)? It is irreversible.\nTo disable this dialogue set the config key of 'gui.skipUnstageLineWarning' to true", LcCreateNewBranchFromCommit: "create new branch off of commit", - LcViewStashFiles: "view stash entry's files", LcBuildingPatch: "building patch", LcViewCommits: "view commits", MinGitVersionError: "Git version must be at least 2.0 (i.e. from 2014 onwards). Please upgrade your git version. Alternatively raise an issue at https://github.com/jesseduffield/lazygit/issues for lazygit to be more backwards compatible.", diff --git a/pkg/i18n/polish.go b/pkg/i18n/polish.go index 5ff66f979..ae6942abe 100644 --- a/pkg/i18n/polish.go +++ b/pkg/i18n/polish.go @@ -175,7 +175,7 @@ func polishTranslationSet() TranslationSet { AmendingStatus: "poprawianie", CherryPickingStatus: "przebieranie", CommitFiles: "Pliki commita", - LcViewCommitFiles: "przegl膮daj pliki commita", + LcViewItemFiles: "przegl膮daj pliki commita", CommitFilesTitle: "Pliki commita", LcCheckoutCommitFile: "plik wybierania", LcDiscardOldFileChange: "porzu膰 zmiany commita dla tego pliku", From c685a413c94d06f154587015a86701ec82d2ee0c Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 18:33:46 +1100 Subject: [PATCH 071/385] stash controller --- pkg/gui/controllers/stash_controller.go | 141 ++++++++++++++++++++++++ pkg/gui/gui.go | 2 + pkg/gui/keybindings.go | 24 ---- pkg/gui/stash_panel.go | 107 +----------------- 4 files changed, 144 insertions(+), 130 deletions(-) create mode 100644 pkg/gui/controllers/stash_controller.go diff --git a/pkg/gui/controllers/stash_controller.go b/pkg/gui/controllers/stash_controller.go new file mode 100644 index 000000000..2ff9e1cfb --- /dev/null +++ b/pkg/gui/controllers/stash_controller.go @@ -0,0 +1,141 @@ +package controllers + +import ( + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type StashController struct { + baseController + *controllerCommon +} + +var _ types.IController = &StashController{} + +func NewStashController( + common *controllerCommon, +) *StashController { + return &StashController{ + baseController: baseController{}, + controllerCommon: common, + } +} + +func (self *StashController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + bindings := []*types.Binding{ + { + Key: opts.GetKey(opts.Config.Universal.Select), + Handler: self.checkSelected(self.handleStashApply), + Description: self.c.Tr.LcApply, + }, + { + Key: opts.GetKey(opts.Config.Stash.PopStash), + Handler: self.checkSelected(self.handleStashPop), + Description: self.c.Tr.LcPop, + }, + { + Key: opts.GetKey(opts.Config.Universal.Remove), + Handler: self.checkSelected(self.handleStashDrop), + Description: self.c.Tr.LcDrop, + }, + { + Key: opts.GetKey(opts.Config.Universal.New), + Handler: self.checkSelected(self.handleNewBranchOffStashEntry), + Description: self.c.Tr.LcNewBranch, + }, + } + + return bindings +} + +func (self *StashController) checkSelected(callback func(*models.StashEntry) error) func() error { + return func() error { + item := self.context().GetSelected() + if item == nil { + return nil + } + + return callback(item) + } +} + +func (self *StashController) Context() types.Context { + return self.context() +} + +func (self *StashController) context() *context.StashContext { + return self.contexts.Stash +} + +func (self *StashController) handleStashApply(stashEntry *models.StashEntry) error { + apply := func() error { + self.c.LogAction(self.c.Tr.Actions.Stash) + err := self.git.Stash.Apply(stashEntry.Index) + _ = self.postStashRefresh() + if err != nil { + return self.c.Error(err) + } + return nil + } + + if self.c.UserConfig.Gui.SkipStashWarning { + return apply() + } + + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.StashApply, + Prompt: self.c.Tr.SureApplyStashEntry, + HandleConfirm: func() error { + return apply() + }, + }) +} + +func (self *StashController) handleStashPop(stashEntry *models.StashEntry) error { + pop := func() error { + self.c.LogAction(self.c.Tr.Actions.Stash) + err := self.git.Stash.Pop(stashEntry.Index) + _ = self.postStashRefresh() + if err != nil { + return self.c.Error(err) + } + return nil + } + + if self.c.UserConfig.Gui.SkipStashWarning { + return pop() + } + + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.StashPop, + Prompt: self.c.Tr.SurePopStashEntry, + HandleConfirm: func() error { + return pop() + }, + }) +} + +func (self *StashController) handleStashDrop(stashEntry *models.StashEntry) error { + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.StashDrop, + Prompt: self.c.Tr.SureDropStashEntry, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.Stash) + err := self.git.Stash.Drop(stashEntry.Index) + _ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}}) + if err != nil { + return self.c.Error(err) + } + return nil + }, + }) +} + +func (self *StashController) postStashRefresh() error { + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}}) +} + +func (self *StashController) handleNewBranchOffStashEntry(stashEntry *models.StashEntry) error { + return self.helpers.Refs.NewBranch(stashEntry.RefName(), stashEntry.Description(), "") +} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index a31c781ed..982ecae1e 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -566,6 +566,7 @@ func (gui *Gui) resetControllers() { branchesController := controllers.NewBranchesController(common) gitFlowController := controllers.NewGitFlowController(common) filesRemoveController := controllers.NewFilesRemoveController(common) + stashController := controllers.NewStashController(common) switchToSubCommitsControllerFactory := controllers.NewSubCommitsSwitchControllerFactory( common, @@ -602,6 +603,7 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(gui.State.Contexts.ReflogCommits, reflogController) controllers.AttachControllers(gui.State.Contexts.SubCommits, subCommitsController) controllers.AttachControllers(gui.State.Contexts.Remotes, gui.Controllers.Remotes) + controllers.AttachControllers(gui.State.Contexts.Stash, stashController) controllers.AttachControllers(gui.State.Contexts.Menu, gui.Controllers.Menu) controllers.AttachControllers(gui.State.Contexts.Global, gui.Controllers.Sync, gui.Controllers.Undo, gui.Controllers.Global) diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index ba30bd407..dfff8c9e1 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -430,30 +430,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Handler: self.handleCopySelectedSideContextItemToClipboard, Description: self.c.Tr.LcCopyCommitShaToClipboard, }, - { - ViewName: "stash", - Key: opts.GetKey(opts.Config.Universal.Select), - Handler: self.handleStashApply, - Description: self.c.Tr.LcApply, - }, - { - ViewName: "stash", - Key: opts.GetKey(opts.Config.Stash.PopStash), - Handler: self.handleStashPop, - Description: self.c.Tr.LcPop, - }, - { - ViewName: "stash", - Key: opts.GetKey(opts.Config.Universal.Remove), - Handler: self.handleStashDrop, - Description: self.c.Tr.LcDrop, - }, - { - ViewName: "stash", - Key: opts.GetKey(opts.Config.Universal.New), - Handler: self.handleNewBranchOffStashEntry, - Description: self.c.Tr.LcNewBranch, - }, { ViewName: "commitMessage", Key: opts.GetKey(opts.Config.Universal.SubmitEditorText), diff --git a/pkg/gui/stash_panel.go b/pkg/gui/stash_panel.go index c0110f553..2c8df1177 100644 --- a/pkg/gui/stash_panel.go +++ b/pkg/gui/stash_panel.go @@ -1,19 +1,8 @@ package gui -import ( - "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - -// list panel functions - -func (gui *Gui) getSelectedStashEntry() *models.StashEntry { - return gui.State.Contexts.Stash.GetSelected() -} - func (gui *Gui) stashRenderToMain() error { var task updateTask - stashEntry := gui.getSelectedStashEntry() + stashEntry := gui.State.Contexts.Stash.GetSelected() if stashEntry == nil { task = NewRenderStringTask(gui.c.Tr.NoStashEntries) } else { @@ -27,97 +16,3 @@ func (gui *Gui) stashRenderToMain() error { }, }) } - -// specific functions - -func (gui *Gui) handleStashApply() error { - stashEntry := gui.getSelectedStashEntry() - if stashEntry == nil { - return nil - } - - apply := func() error { - gui.c.LogAction(gui.c.Tr.Actions.Stash) - err := gui.git.Stash.Apply(stashEntry.Index) - _ = gui.postStashRefresh() - if err != nil { - return gui.c.Error(err) - } - return nil - } - - if gui.c.UserConfig.Gui.SkipStashWarning { - return apply() - } - - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.StashApply, - Prompt: gui.c.Tr.SureApplyStashEntry, - HandleConfirm: func() error { - return apply() - }, - }) -} - -func (gui *Gui) handleStashPop() error { - stashEntry := gui.getSelectedStashEntry() - if stashEntry == nil { - return nil - } - - pop := func() error { - gui.c.LogAction(gui.c.Tr.Actions.Stash) - err := gui.git.Stash.Pop(stashEntry.Index) - _ = gui.postStashRefresh() - if err != nil { - return gui.c.Error(err) - } - return nil - } - - if gui.c.UserConfig.Gui.SkipStashWarning { - return pop() - } - - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.StashPop, - Prompt: gui.c.Tr.SurePopStashEntry, - HandleConfirm: func() error { - return pop() - }, - }) -} - -func (gui *Gui) handleStashDrop() error { - stashEntry := gui.getSelectedStashEntry() - if stashEntry == nil { - return nil - } - - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.StashDrop, - Prompt: gui.c.Tr.SureDropStashEntry, - HandleConfirm: func() error { - gui.c.LogAction(gui.c.Tr.Actions.Stash) - err := gui.git.Stash.Drop(stashEntry.Index) - _ = gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}}) - if err != nil { - return gui.c.Error(err) - } - return nil - }, - }) -} - -func (gui *Gui) postStashRefresh() error { - return gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}}) -} - -func (gui *Gui) handleNewBranchOffStashEntry() error { - stashEntry := gui.getSelectedStashEntry() - if stashEntry == nil { - return nil - } - - return gui.helpers.Refs.NewBranch(stashEntry.RefName(), stashEntry.Description(), "") -} From 85f23198971de56195a4a1790d70e9d3b4ea1908 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 13 Feb 2022 19:15:22 +1100 Subject: [PATCH 072/385] refactor custom commands panel --- pkg/gui/commit_files_panel.go | 14 +-- pkg/gui/custom_commands.go | 167 +++++++++++++++++++--------------- 2 files changed, 101 insertions(+), 80 deletions(-) diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index 610973399..df37f6b41 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -256,6 +256,13 @@ func (gui *Gui) handleToggleCommitFileDirCollapsed() error { return nil } +// NOTE: this is very similar to handleToggleFileTreeView, could be DRY'd with generics +func (gui *Gui) handleToggleCommitFileTreeView() error { + gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.ToggleShowTree() + + return gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles) +} + func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesContextOpts) error { // sometimes the commitFiles view is already shown in another window, so we need to ensure that window // no longer considers the commitFiles view as its main view. @@ -273,10 +280,3 @@ func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesC return gui.c.PushContext(gui.State.Contexts.CommitFiles) } - -// NOTE: this is very similar to handleToggleFileTreeView, could be DRY'd with generics -func (gui *Gui) handleToggleCommitFileTreeView() error { - gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.ToggleShowTree() - - return gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles) -} diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index 01a37adce..b4c977f3b 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -40,7 +40,7 @@ type commandMenuEntry struct { value string } -func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (string, error) { +func (gui *Gui) getResolveTemplateFn(promptResponses []string) func(string) (string, error) { objects := CustomCommandObjects{ SelectedFile: gui.getSelectedFile(), SelectedPath: gui.getSelectedPath(), @@ -58,71 +58,101 @@ func (gui *Gui) resolveTemplate(templateStr string, promptResponses []string) (s PromptResponses: promptResponses, } - return utils.ResolveTemplate(templateStr, objects) + return func(templateStr string) (string, error) { return utils.ResolveTemplate(templateStr, objects) } } -func (gui *Gui) inputPrompt(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error { - title, err := gui.resolveTemplate(prompt.Title, promptResponses) +func resolveCustomCommandPrompt(prompt *config.CustomCommandPrompt, resolveTemplate func(string) (string, error)) (*config.CustomCommandPrompt, error) { + var err error + result := &config.CustomCommandPrompt{} + + result.Title, err = resolveTemplate(prompt.Title) if err != nil { - return gui.c.Error(err) + return nil, err } - initialValue, err := gui.resolveTemplate(prompt.InitialValue, promptResponses) + result.InitialValue, err = resolveTemplate(prompt.InitialValue) if err != nil { - return gui.c.Error(err) + return nil, err } + result.Command, err = resolveTemplate(prompt.Command) + if err != nil { + return nil, err + } + + result.Filter, err = resolveTemplate(prompt.Filter) + if err != nil { + return nil, err + } + + if len(prompt.Options) > 0 { + newOptions := make([]config.CustomCommandMenuOption, len(prompt.Options)) + for _, option := range prompt.Options { + option := option + newOption, err := resolveMenuOption(&option, resolveTemplate) + if err != nil { + return nil, err + } + newOptions = append(newOptions, *newOption) + } + prompt.Options = newOptions + } + + return result, nil +} + +func resolveMenuOption(option *config.CustomCommandMenuOption, resolveTemplate func(string) (string, error)) (*config.CustomCommandMenuOption, error) { + nameTemplate := option.Name + if nameTemplate == "" { + // this allows you to only pass values rather than bother with names/descriptions + nameTemplate = option.Value + } + + name, err := resolveTemplate(nameTemplate) + if err != nil { + return nil, err + } + + description, err := resolveTemplate(option.Description) + if err != nil { + return nil, err + } + + value, err := resolveTemplate(option.Value) + if err != nil { + return nil, err + } + + return &config.CustomCommandMenuOption{ + Name: name, + Description: description, + Value: value, + }, nil +} + +func (gui *Gui) inputPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error { return gui.c.Prompt(types.PromptOpts{ - Title: title, - InitialContent: initialValue, + Title: prompt.Title, + InitialContent: prompt.InitialValue, HandleConfirm: func(str string) error { - promptResponses[responseIdx] = str - return wrappedF() + return wrappedF(str) }, }) } -func (gui *Gui) menuPrompt(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error { - // need to make a menu here some how +func (gui *Gui) menuPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error { menuItems := make([]*types.MenuItem, len(prompt.Options)) for i, option := range prompt.Options { option := option - - nameTemplate := option.Name - if nameTemplate == "" { - // this allows you to only pass values rather than bother with names/descriptions - nameTemplate = option.Value - } - name, err := gui.resolveTemplate(nameTemplate, promptResponses) - if err != nil { - return gui.c.Error(err) - } - - description, err := gui.resolveTemplate(option.Description, promptResponses) - if err != nil { - return gui.c.Error(err) - } - - value, err := gui.resolveTemplate(option.Value, promptResponses) - if err != nil { - return gui.c.Error(err) - } - menuItems[i] = &types.MenuItem{ - DisplayStrings: []string{name, style.FgYellow.Sprint(description)}, + DisplayStrings: []string{option.Name, style.FgYellow.Sprint(option.Description)}, OnPress: func() error { - promptResponses[responseIdx] = value - return wrappedF() + return wrappedF(option.Value) }, } } - title, err := gui.resolveTemplate(prompt.Title, promptResponses) - if err != nil { - return gui.c.Error(err) - } - - return gui.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems}) + return gui.c.Menu(types.CreateMenuOptions{Title: prompt.Title, Items: menuItems}) } func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, labelFormat string) ([]commandMenuEntry, error) { @@ -191,27 +221,15 @@ func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, label return candidates, err } -func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptResponses []string, responseIdx int, wrappedF func() error) error { - // Collect cmd to run from config - cmdStr, err := gui.resolveTemplate(prompt.Command, promptResponses) - if err != nil { - return gui.c.Error(err) - } - - // Collect Filter regexp - filter, err := gui.resolveTemplate(prompt.Filter, promptResponses) - if err != nil { - return gui.c.Error(err) - } - +func (gui *Gui) menuPromptFromCommand(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error { // Run and save output - message, err := gui.git.Custom.RunWithOutput(cmdStr) + message, err := gui.git.Custom.RunWithOutput(prompt.Command) if err != nil { return gui.c.Error(err) } // Need to make a menu out of what the cmd has displayed - candidates, err := gui.GenerateMenuCandidates(message, filter, prompt.ValueFormat, prompt.LabelFormat) + candidates, err := gui.GenerateMenuCandidates(message, prompt.Filter, prompt.ValueFormat, prompt.LabelFormat) if err != nil { return gui.c.Error(err) } @@ -222,18 +240,12 @@ func (gui *Gui) menuPromptFromCommand(prompt config.CustomCommandPrompt, promptR menuItems[i] = &types.MenuItem{ DisplayStrings: []string{candidates[i].label}, OnPress: func() error { - promptResponses[responseIdx] = candidates[i].value - return wrappedF() + return wrappedF(candidates[i].value) }, } } - title, err := gui.resolveTemplate(prompt.Title, promptResponses) - if err != nil { - return gui.c.Error(err) - } - - return gui.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems}) + return gui.c.Menu(types.CreateMenuOptions{Title: prompt.Title, Items: menuItems}) } func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand) func() error { @@ -241,7 +253,8 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand promptResponses := make([]string, len(customCommand.Prompts)) f := func() error { - cmdStr, err := gui.resolveTemplate(customCommand.Command, promptResponses) + resolveTemplate := gui.getResolveTemplateFn(promptResponses) + cmdStr, err := resolveTemplate(customCommand.Command) if err != nil { return gui.c.Error(err) } @@ -254,6 +267,7 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand if loadingText == "" { loadingText = gui.c.Tr.LcRunningCustomCommandStatus } + return gui.c.WithWaitingStatus(loadingText, func() error { gui.c.LogAction(gui.c.Tr.Actions.CustomCommand) cmdObj := gui.os.Cmd.NewShell(cmdStr) @@ -276,26 +290,33 @@ func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand // going backwards so the outermost prompt is the first one prompt := customCommand.Prompts[idx] - // need to do this because f's value will change with each iteration - wrappedF := f + wrappedF := func(response string) error { + promptResponses[idx] = response + return f() + } + + resolveTemplate := gui.getResolveTemplateFn(promptResponses) + resolvedPrompt, err := resolveCustomCommandPrompt(&prompt, resolveTemplate) + if err != nil { + return gui.c.Error(err) + } switch prompt.Type { case "input": f = func() error { - return gui.inputPrompt(prompt, promptResponses, idx, wrappedF) + return gui.inputPrompt(resolvedPrompt, wrappedF) } case "menu": f = func() error { - return gui.menuPrompt(prompt, promptResponses, idx, wrappedF) + return gui.menuPrompt(resolvedPrompt, wrappedF) } case "menuFromCommand": f = func() error { - return gui.menuPromptFromCommand(prompt, promptResponses, idx, wrappedF) + return gui.menuPromptFromCommand(resolvedPrompt, wrappedF) } default: return gui.c.ErrorMsg("custom command prompt must have a type of 'input', 'menu' or 'menuFromCommand'") } - } return f() From ecaff7fc6cc3d2e510a88e336abcb74567de3f12 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Tue, 22 Feb 2022 20:13:11 +1100 Subject: [PATCH 073/385] add commit files controller --- pkg/gui/commit_files_panel.go | 240 +++------------- .../controllers/commits_files_controller.go | 259 ++++++++++++++++++ pkg/gui/controllers/helpers/helpers.go | 2 + .../helpers/patch_building_helper.go | 33 +++ .../controllers/local_commits_controller.go | 14 +- pkg/gui/controllers/reflog_controller.go | 8 +- pkg/gui/controllers/sub_commits_controller.go | 8 +- pkg/gui/global_handlers.go | 9 - pkg/gui/gui.go | 15 +- pkg/gui/keybindings.go | 49 ---- pkg/gui/line_by_line_panel.go | 9 - pkg/gui/modes/diffing/diffing.go | 18 +- pkg/gui/patch_building_panel.go | 15 +- 13 files changed, 358 insertions(+), 321 deletions(-) create mode 100644 pkg/gui/controllers/commits_files_controller.go create mode 100644 pkg/gui/controllers/helpers/patch_building_helper.go diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index df37f6b41..be8ec1a53 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -2,10 +2,8 @@ package gui import ( "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/commands/patch" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/controllers" - "github.com/jesseduffield/lazygit/pkg/gui/types" ) func (gui *Gui) getSelectedCommitFile() *models.CommitFile { @@ -37,7 +35,7 @@ func (gui *Gui) commitFilesRenderToMain() error { } to := gui.State.Contexts.CommitFiles.GetRefName() - from, reverse := gui.getFromAndReverseArgsForDiff(to) + from, reverse := gui.State.Modes.Diffing.GetFromAndReverseArgsForDiff(to) cmdObj := gui.git.WorkingTree.ShowFileDiffCmdObj(from, to, reverse, node.GetPath(), false) task := NewRunPtyTask(cmdObj.GetCmd()) @@ -57,212 +55,6 @@ func (gui *Gui) commitFilesRenderToMain() error { }) } -func (gui *Gui) handleCheckoutCommitFile() error { - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() - if node == nil { - return nil - } - - gui.c.LogAction(gui.c.Tr.Actions.CheckoutFile) - if err := gui.git.WorkingTree.CheckoutFile(gui.State.Contexts.CommitFiles.GetRefName(), node.GetPath()); err != nil { - return gui.c.Error(err) - } - - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) -} - -func (gui *Gui) handleDiscardOldFileChange() error { - if ok, err := gui.validateNormalWorkingTreeState(); !ok { - return err - } - - fileName := gui.getSelectedCommitFileName() - - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.DiscardFileChangesTitle, - Prompt: gui.c.Tr.DiscardFileChangesPrompt, - HandleConfirm: func() error { - return gui.c.WithWaitingStatus(gui.c.Tr.RebasingStatus, func() error { - gui.c.LogAction(gui.c.Tr.Actions.DiscardOldFileChange) - if err := gui.git.Rebase.DiscardOldFileChanges(gui.State.Model.Commits, gui.State.Contexts.LocalCommits.GetSelectedLineIdx(), fileName); err != nil { - if err := gui.helpers.MergeAndRebase.CheckMergeOrRebase(err); err != nil { - return err - } - } - - return gui.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI}) - }) - }, - }) -} - -func (gui *Gui) refreshCommitFilesView() error { - currentSideContext := gui.currentSideContext() - if currentSideContext.GetKey() == context.COMMIT_FILES_CONTEXT_KEY || currentSideContext.GetKey() == context.LOCAL_COMMITS_CONTEXT_KEY { - if err := gui.handleRefreshPatchBuildingPanel(-1); err != nil { - return err - } - } - - to := gui.State.Contexts.CommitFiles.GetRefName() - from, reverse := gui.getFromAndReverseArgsForDiff(to) - - files, err := gui.git.Loaders.CommitFiles.GetFilesInDiff(from, to, reverse) - if err != nil { - return gui.c.Error(err) - } - gui.State.Model.CommitFiles = files - gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.SetTree() - - return gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles) -} - -func (gui *Gui) handleOpenOldCommitFile() error { - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() - if node == nil { - return nil - } - - return gui.helpers.Files.OpenFile(node.GetPath()) -} - -func (gui *Gui) handleEditCommitFile() error { - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() - if node == nil { - return nil - } - - if node.File == nil { - return gui.c.ErrorMsg(gui.c.Tr.ErrCannotEditDirectory) - } - - return gui.helpers.Files.EditFile(node.GetPath()) -} - -func (gui *Gui) handleToggleFileForPatch() error { - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() - if node == nil { - return nil - } - - toggleTheFile := func() error { - if !gui.git.Patch.PatchManager.Active() { - if err := gui.startPatchManager(); err != nil { - return err - } - } - - // if there is any file that hasn't been fully added we'll fully add everything, - // otherwise we'll remove everything - adding := node.AnyFile(func(file *models.CommitFile) bool { - return gui.git.Patch.PatchManager.GetFileStatus(file.Name, gui.State.Contexts.CommitFiles.GetRefName()) != patch.WHOLE - }) - - err := node.ForEachFile(func(file *models.CommitFile) error { - if adding { - return gui.git.Patch.PatchManager.AddFileWhole(file.Name) - } else { - return gui.git.Patch.PatchManager.RemoveFile(file.Name) - } - }) - - if err != nil { - return gui.c.Error(err) - } - - if gui.git.Patch.PatchManager.IsEmpty() { - gui.git.Patch.PatchManager.Reset() - } - - return gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles) - } - - if gui.git.Patch.PatchManager.Active() && gui.git.Patch.PatchManager.To != gui.State.Contexts.CommitFiles.GetRefName() { - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.DiscardPatch, - Prompt: gui.c.Tr.DiscardPatchConfirm, - HandleConfirm: func() error { - gui.git.Patch.PatchManager.Reset() - return toggleTheFile() - }, - }) - } - - return toggleTheFile() -} - -func (gui *Gui) startPatchManager() error { - commitFilesContext := gui.State.Contexts.CommitFiles - - canRebase := commitFilesContext.GetCanRebase() - to := commitFilesContext.GetRefName() - - from, reverse := gui.getFromAndReverseArgsForDiff(to) - - gui.git.Patch.PatchManager.Start(from, to, reverse, canRebase) - return nil -} - -func (gui *Gui) handleEnterCommitFile() error { - return gui.enterCommitFile(types.OnFocusOpts{ClickedViewName: "", ClickedViewLineIdx: -1}) -} - -func (gui *Gui) enterCommitFile(opts types.OnFocusOpts) error { - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() - if node == nil { - return nil - } - - if node.File == nil { - return gui.handleToggleCommitFileDirCollapsed() - } - - enterTheFile := func() error { - if !gui.git.Patch.PatchManager.Active() { - if err := gui.startPatchManager(); err != nil { - return err - } - } - - return gui.c.PushContext(gui.State.Contexts.PatchBuilding, opts) - } - - if gui.git.Patch.PatchManager.Active() && gui.git.Patch.PatchManager.To != gui.State.Contexts.CommitFiles.GetRefName() { - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.DiscardPatch, - Prompt: gui.c.Tr.DiscardPatchConfirm, - HandleConfirm: func() error { - gui.git.Patch.PatchManager.Reset() - return enterTheFile() - }, - }) - } - - return enterTheFile() -} - -func (gui *Gui) handleToggleCommitFileDirCollapsed() error { - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() - if node == nil { - return nil - } - - gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.ToggleCollapsed(node.GetPath()) - - if err := gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles); err != nil { - gui.c.Log.Error(err) - } - - return nil -} - -// NOTE: this is very similar to handleToggleFileTreeView, could be DRY'd with generics -func (gui *Gui) handleToggleCommitFileTreeView() error { - gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.ToggleShowTree() - - return gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles) -} - func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesContextOpts) error { // sometimes the commitFiles view is already shown in another window, so we need to ensure that window // no longer considers the commitFiles view as its main view. @@ -280,3 +72,33 @@ func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesC return gui.c.PushContext(gui.State.Contexts.CommitFiles) } + +func (gui *Gui) refreshCommitFilesView() error { + currentSideContext := gui.currentSideContext() + if currentSideContext.GetKey() == context.COMMIT_FILES_CONTEXT_KEY || currentSideContext.GetKey() == context.LOCAL_COMMITS_CONTEXT_KEY { + if err := gui.handleRefreshPatchBuildingPanel(-1); err != nil { + return err + } + } + + to := gui.State.Contexts.CommitFiles.GetRefName() + from, reverse := gui.State.Modes.Diffing.GetFromAndReverseArgsForDiff(to) + + files, err := gui.git.Loaders.CommitFiles.GetFilesInDiff(from, to, reverse) + if err != nil { + return gui.c.Error(err) + } + gui.State.Model.CommitFiles = files + gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.SetTree() + + return gui.c.PostRefreshUpdate(gui.State.Contexts.CommitFiles) +} + +func (gui *Gui) getSelectedCommitFileName() string { + node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() + if node == nil { + return "" + } + + return node.Path +} diff --git a/pkg/gui/controllers/commits_files_controller.go b/pkg/gui/controllers/commits_files_controller.go new file mode 100644 index 000000000..33d4ff4c1 --- /dev/null +++ b/pkg/gui/controllers/commits_files_controller.go @@ -0,0 +1,259 @@ +package controllers + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/commands/patch" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/filetree" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type CommitFilesController struct { + baseController + *controllerCommon +} + +var _ types.IController = &CommitFilesController{} + +func NewCommitFilesController( + common *controllerCommon, +) *CommitFilesController { + return &CommitFilesController{ + baseController: baseController{}, + controllerCommon: common, + } +} + +func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + bindings := []*types.Binding{ + { + Key: opts.GetKey(opts.Config.CommitFiles.CheckoutCommitFile), + Handler: self.checkSelected(self.handleCheckoutCommitFile), + Description: self.c.Tr.LcCheckoutCommitFile, + }, + { + Key: opts.GetKey(opts.Config.Universal.Remove), + Handler: self.checkSelected(self.handleDiscardOldFileChange), + Description: self.c.Tr.LcDiscardOldFileChange, + }, + { + Key: opts.GetKey(opts.Config.Universal.OpenFile), + Handler: self.checkSelected(self.handleOpenOldCommitFile), + Description: self.c.Tr.LcOpenFile, + }, + { + Key: opts.GetKey(opts.Config.Universal.Edit), + Handler: self.checkSelected(self.handleEditCommitFile), + Description: self.c.Tr.LcEditFile, + }, + { + Key: opts.GetKey(opts.Config.Universal.Select), + Handler: self.checkSelected(self.handleToggleFileForPatch), + Description: self.c.Tr.LcToggleAddToPatch, + }, + { + Key: opts.GetKey(opts.Config.Universal.GoInto), + Handler: self.checkSelected(self.handleEnterCommitFile), + Description: self.c.Tr.LcEnterFile, + }, + { + Key: opts.GetKey(opts.Config.Files.ToggleTreeView), + Handler: self.handleToggleCommitFileTreeView, + Description: self.c.Tr.LcToggleTreeView, + }, + } + + return bindings +} + +func (self *CommitFilesController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { + return []*gocui.ViewMouseBinding{ + { + ViewName: "main", + Key: gocui.MouseLeft, + Handler: self.onClickMain, + }, + } +} + +func (self *CommitFilesController) checkSelected(callback func(*filetree.CommitFileNode) error) func() error { + return func() error { + selected := self.context().GetSelectedFileNode() + if selected == nil { + return nil + } + + return callback(selected) + } +} + +func (self *CommitFilesController) Context() types.Context { + return self.context() +} + +func (self *CommitFilesController) context() *context.CommitFilesContext { + return self.contexts.CommitFiles +} + +func (self *CommitFilesController) onClickMain(opts gocui.ViewMouseBindingOpts) error { + clickedViewLineIdx := opts.Cy + opts.Oy + node := self.context().GetSelectedFileNode() + if node == nil { + return nil + } + return self.enterCommitFile(node, types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: clickedViewLineIdx}) +} + +func (self *CommitFilesController) handleCheckoutCommitFile(node *filetree.CommitFileNode) error { + self.c.LogAction(self.c.Tr.Actions.CheckoutFile) + if err := self.git.WorkingTree.CheckoutFile(self.context().GetRefName(), node.GetPath()); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) +} + +func (self *CommitFilesController) handleDiscardOldFileChange(node *filetree.CommitFileNode) error { + if ok, err := self.helpers.PatchBuilding.ValidateNormalWorkingTreeState(); !ok { + return err + } + + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.DiscardFileChangesTitle, + Prompt: self.c.Tr.DiscardFileChangesPrompt, + HandleConfirm: func() error { + return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.DiscardOldFileChange) + if err := self.git.Rebase.DiscardOldFileChanges(self.model.Commits, self.contexts.LocalCommits.GetSelectedLineIdx(), node.GetPath()); err != nil { + if err := self.helpers.MergeAndRebase.CheckMergeOrRebase(err); err != nil { + return err + } + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI}) + }) + }, + }) +} + +func (self *CommitFilesController) handleOpenOldCommitFile(node *filetree.CommitFileNode) error { + return self.helpers.Files.OpenFile(node.GetPath()) +} + +func (self *CommitFilesController) handleEditCommitFile(node *filetree.CommitFileNode) error { + if node.File == nil { + return self.c.ErrorMsg(self.c.Tr.ErrCannotEditDirectory) + } + + return self.helpers.Files.EditFile(node.GetPath()) +} + +func (self *CommitFilesController) handleToggleFileForPatch(node *filetree.CommitFileNode) error { + toggleTheFile := func() error { + if !self.git.Patch.PatchManager.Active() { + if err := self.startPatchManager(); err != nil { + return err + } + } + + // if there is any file that hasn't been fully added we'll fully add everything, + // otherwise we'll remove everything + adding := node.AnyFile(func(file *models.CommitFile) bool { + return self.git.Patch.PatchManager.GetFileStatus(file.Name, self.context().GetRefName()) != patch.WHOLE + }) + + err := node.ForEachFile(func(file *models.CommitFile) error { + if adding { + return self.git.Patch.PatchManager.AddFileWhole(file.Name) + } else { + return self.git.Patch.PatchManager.RemoveFile(file.Name) + } + }) + + if err != nil { + return self.c.Error(err) + } + + if self.git.Patch.PatchManager.IsEmpty() { + self.git.Patch.PatchManager.Reset() + } + + return self.c.PostRefreshUpdate(self.context()) + } + + if self.git.Patch.PatchManager.Active() && self.git.Patch.PatchManager.To != self.context().GetRefName() { + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.DiscardPatch, + Prompt: self.c.Tr.DiscardPatchConfirm, + HandleConfirm: func() error { + self.git.Patch.PatchManager.Reset() + return toggleTheFile() + }, + }) + } + + return toggleTheFile() +} + +func (self *CommitFilesController) startPatchManager() error { + commitFilesContext := self.context() + + canRebase := commitFilesContext.GetCanRebase() + to := commitFilesContext.GetRefName() + + from, reverse := self.modes.Diffing.GetFromAndReverseArgsForDiff(to) + + self.git.Patch.PatchManager.Start(from, to, reverse, canRebase) + return nil +} + +func (self *CommitFilesController) handleEnterCommitFile(node *filetree.CommitFileNode) error { + return self.enterCommitFile(node, types.OnFocusOpts{ClickedViewName: "", ClickedViewLineIdx: -1}) +} + +func (self *CommitFilesController) enterCommitFile(node *filetree.CommitFileNode, opts types.OnFocusOpts) error { + if node.File == nil { + return self.handleToggleCommitFileDirCollapsed(node) + } + + enterTheFile := func() error { + if !self.git.Patch.PatchManager.Active() { + if err := self.startPatchManager(); err != nil { + return err + } + } + + return self.c.PushContext(self.contexts.PatchBuilding, opts) + } + + if self.git.Patch.PatchManager.Active() && self.git.Patch.PatchManager.To != self.context().GetRefName() { + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.DiscardPatch, + Prompt: self.c.Tr.DiscardPatchConfirm, + HandleConfirm: func() error { + self.git.Patch.PatchManager.Reset() + return enterTheFile() + }, + }) + } + + return enterTheFile() +} + +func (self *CommitFilesController) handleToggleCommitFileDirCollapsed(node *filetree.CommitFileNode) error { + self.context().CommitFileTreeViewModel.ToggleCollapsed(node.GetPath()) + + if err := self.c.PostRefreshUpdate(self.context()); err != nil { + self.c.Log.Error(err) + } + + return nil +} + +// NOTE: this is very similar to handleToggleFileTreeView, could be DRY'd with generics +func (self *CommitFilesController) handleToggleCommitFileTreeView() error { + self.context().CommitFileTreeViewModel.ToggleShowTree() + + return self.c.PostRefreshUpdate(self.context()) +} diff --git a/pkg/gui/controllers/helpers/helpers.go b/pkg/gui/controllers/helpers/helpers.go index 2ca4fbd40..2a7c43ff0 100644 --- a/pkg/gui/controllers/helpers/helpers.go +++ b/pkg/gui/controllers/helpers/helpers.go @@ -10,6 +10,7 @@ type Helpers struct { MergeAndRebase *MergeAndRebaseHelper CherryPick *CherryPickHelper Host *HostHelper + PatchBuilding *PatchBuildingHelper } func NewStubHelpers() *Helpers { @@ -23,5 +24,6 @@ func NewStubHelpers() *Helpers { MergeAndRebase: &MergeAndRebaseHelper{}, CherryPick: &CherryPickHelper{}, Host: &HostHelper{}, + PatchBuilding: &PatchBuildingHelper{}, } } diff --git a/pkg/gui/controllers/helpers/patch_building_helper.go b/pkg/gui/controllers/helpers/patch_building_helper.go new file mode 100644 index 000000000..efb8ec671 --- /dev/null +++ b/pkg/gui/controllers/helpers/patch_building_helper.go @@ -0,0 +1,33 @@ +package helpers + +import ( + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/types/enums" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type IPatchBuildingHelper interface { + ValidateNormalWorkingTreeState() (bool, error) +} + +type PatchBuildingHelper struct { + c *types.HelperCommon + git *commands.GitCommand +} + +func NewPatchBuildingHelper( + c *types.HelperCommon, + git *commands.GitCommand, +) *PatchBuildingHelper { + return &PatchBuildingHelper{ + c: c, + git: git, + } +} + +func (self *PatchBuildingHelper) ValidateNormalWorkingTreeState() (bool, error) { + if self.git.Status.WorkingTreeState() != enums.REBASE_MODE_NONE { + return false, self.c.ErrorMsg(self.c.Tr.CantPatchWhileRebasingError) + } + return true, nil +} diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index 694d7396f..b905e948e 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -11,16 +11,14 @@ import ( ) type ( - SwitchToCommitFilesContextFn func(SwitchToCommitFilesContextOpts) error - PullFilesFn func() error + PullFilesFn func() error ) type LocalCommitsController struct { baseController *controllerCommon - pullFiles PullFilesFn - switchToCommitFilesContext SwitchToCommitFilesContextFn + pullFiles PullFilesFn } var _ types.IController = &LocalCommitsController{} @@ -28,13 +26,11 @@ var _ types.IController = &LocalCommitsController{} func NewLocalCommitsController( common *controllerCommon, pullFiles PullFilesFn, - switchToCommitFilesContext SwitchToCommitFilesContextFn, ) *LocalCommitsController { return &LocalCommitsController{ - baseController: baseController{}, - controllerCommon: common, - pullFiles: pullFiles, - switchToCommitFilesContext: switchToCommitFilesContext, + baseController: baseController{}, + controllerCommon: common, + pullFiles: pullFiles, } } diff --git a/pkg/gui/controllers/reflog_controller.go b/pkg/gui/controllers/reflog_controller.go index 43413a6ac..4085df635 100644 --- a/pkg/gui/controllers/reflog_controller.go +++ b/pkg/gui/controllers/reflog_controller.go @@ -9,20 +9,16 @@ import ( type ReflogController struct { baseController *controllerCommon - - switchToCommitFilesContext SwitchToCommitFilesContextFn } var _ types.IController = &ReflogController{} func NewReflogController( common *controllerCommon, - switchToCommitFilesContext SwitchToCommitFilesContextFn, ) *ReflogController { return &ReflogController{ - baseController: baseController{}, - controllerCommon: common, - switchToCommitFilesContext: switchToCommitFilesContext, + baseController: baseController{}, + controllerCommon: common, } } diff --git a/pkg/gui/controllers/sub_commits_controller.go b/pkg/gui/controllers/sub_commits_controller.go index 300f5b3fa..55b0795c1 100644 --- a/pkg/gui/controllers/sub_commits_controller.go +++ b/pkg/gui/controllers/sub_commits_controller.go @@ -9,20 +9,16 @@ import ( type SubCommitsController struct { baseController *controllerCommon - - switchToCommitFilesContext SwitchToCommitFilesContextFn } var _ types.IController = &SubCommitsController{} func NewSubCommitsController( common *controllerCommon, - switchToCommitFilesContext SwitchToCommitFilesContextFn, ) *SubCommitsController { return &SubCommitsController{ - baseController: baseController{}, - controllerCommon: common, - switchToCommitFilesContext: switchToCommitFilesContext, + baseController: baseController{}, + controllerCommon: common, } } diff --git a/pkg/gui/global_handlers.go b/pkg/gui/global_handlers.go index d03723743..e76c9f1a6 100644 --- a/pkg/gui/global_handlers.go +++ b/pkg/gui/global_handlers.go @@ -180,15 +180,6 @@ func (gui *Gui) handleRefresh() error { return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) } -func (gui *Gui) handleMouseDownMain() error { - switch gui.currentSideContext() { - case gui.State.Contexts.CommitFiles: - return gui.enterCommitFile(types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: gui.Views.Main.SelectedLineIdx()}) - } - - return nil -} - func (gui *Gui) backgroundFetch() (err error) { err = gui.git.Sync.Fetch(git_commands.FetchOptions{Background: true}) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 982ecae1e..93476636c 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -497,6 +497,7 @@ func (gui *Gui) resetControllers() { rebaseHelper := helpers.NewMergeAndRebaseHelper(controllerCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling, refsHelper) gui.helpers = &helpers.Helpers{ Refs: refsHelper, + PatchBuilding: helpers.NewPatchBuildingHelper(controllerCommon, gui.git), Bisect: helpers.NewBisectHelper(controllerCommon, gui.git), Suggestions: helpers.NewSuggestionsHelper(controllerCommon, model, gui.refreshSuggestions), Files: helpers.NewFilesHelper(controllerCommon, gui.git, osCommand), @@ -534,8 +535,8 @@ func (gui *Gui) resetControllers() { bisectController := controllers.NewBisectController(common) - reflogController := controllers.NewReflogController(common, gui.SwitchToCommitFilesContext) - subCommitsController := controllers.NewSubCommitsController(common, gui.SwitchToCommitFilesContext) + reflogController := controllers.NewReflogController(common) + subCommitsController := controllers.NewSubCommitsController(common) gui.Controllers = Controllers{ Submodules: submodulesController, @@ -548,12 +549,8 @@ func (gui *Gui) resetControllers() { func() string { return gui.State.failedCommitMessage }, gui.switchToMerge, ), - Tags: controllers.NewTagsController(common), - LocalCommits: controllers.NewLocalCommitsController( - common, - syncController.HandlePull, - gui.SwitchToCommitFilesContext, - ), + Tags: controllers.NewTagsController(common), + LocalCommits: controllers.NewLocalCommitsController(common, syncController.HandlePull), Remotes: controllers.NewRemotesController( common, func(branches []*models.RemoteBranch) { gui.State.Model.RemoteBranches = branches }, @@ -567,6 +564,7 @@ func (gui *Gui) resetControllers() { gitFlowController := controllers.NewGitFlowController(common) filesRemoveController := controllers.NewFilesRemoveController(common) stashController := controllers.NewStashController(common) + commitFilesController := controllers.NewCommitFilesController(common) switchToSubCommitsControllerFactory := controllers.NewSubCommitsSwitchControllerFactory( common, @@ -602,6 +600,7 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(gui.State.Contexts.LocalCommits, gui.Controllers.LocalCommits, bisectController) controllers.AttachControllers(gui.State.Contexts.ReflogCommits, reflogController) controllers.AttachControllers(gui.State.Contexts.SubCommits, subCommitsController) + controllers.AttachControllers(gui.State.Contexts.CommitFiles, commitFilesController) controllers.AttachControllers(gui.State.Contexts.Remotes, gui.Controllers.Remotes) controllers.AttachControllers(gui.State.Contexts.Stash, stashController) controllers.AttachControllers(gui.State.Contexts.Menu, gui.Controllers.Menu) diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index dfff8c9e1..fa0e893e0 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -472,48 +472,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Handler: self.handleCopySelectedSideContextItemToClipboard, Description: self.c.Tr.LcCopyCommitFileNameToClipboard, }, - { - ViewName: "commitFiles", - Key: opts.GetKey(opts.Config.CommitFiles.CheckoutCommitFile), - Handler: self.handleCheckoutCommitFile, - Description: self.c.Tr.LcCheckoutCommitFile, - }, - { - ViewName: "commitFiles", - Key: opts.GetKey(opts.Config.Universal.Remove), - Handler: self.handleDiscardOldFileChange, - Description: self.c.Tr.LcDiscardOldFileChange, - }, - { - ViewName: "commitFiles", - Key: opts.GetKey(opts.Config.Universal.OpenFile), - Handler: self.handleOpenOldCommitFile, - Description: self.c.Tr.LcOpenFile, - }, - { - ViewName: "commitFiles", - Key: opts.GetKey(opts.Config.Universal.Edit), - Handler: self.handleEditCommitFile, - Description: self.c.Tr.LcEditFile, - }, - { - ViewName: "commitFiles", - Key: opts.GetKey(opts.Config.Universal.Select), - Handler: self.handleToggleFileForPatch, - Description: self.c.Tr.LcToggleAddToPatch, - }, - { - ViewName: "commitFiles", - Key: opts.GetKey(opts.Config.Universal.GoInto), - Handler: self.handleEnterCommitFile, - Description: self.c.Tr.LcEnterFile, - }, - { - ViewName: "commitFiles", - Key: opts.GetKey(opts.Config.Files.ToggleTreeView), - Handler: self.handleToggleCommitFileTreeView, - Description: self.c.Tr.LcToggleTreeView, - }, { ViewName: "", Key: opts.GetKey(opts.Config.Universal.FilteringMenu), @@ -570,13 +528,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Description: self.c.Tr.ScrollUp, Alternative: "fn+down", }, - { - ViewName: "main", - Contexts: []string{string(context.MAIN_NORMAL_CONTEXT_KEY)}, - Key: gocui.MouseLeft, - Modifier: gocui.ModNone, - Handler: self.handleMouseDownMain, - }, { ViewName: "secondary", Contexts: []string{string(context.MAIN_STAGING_CONTEXT_KEY)}, diff --git a/pkg/gui/line_by_line_panel.go b/pkg/gui/line_by_line_panel.go index 7f423f115..56de72426 100644 --- a/pkg/gui/line_by_line_panel.go +++ b/pkg/gui/line_by_line_panel.go @@ -120,15 +120,6 @@ func (gui *Gui) handleMouseDrag() error { }) } -func (gui *Gui) getSelectedCommitFileName() string { - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() - if node == nil { - return "" - } - - return node.Path -} - func (gui *Gui) refreshMainViewForLineByLine(state *LblPanelState) error { var includedLineIndices []int // I'd prefer not to have knowledge of contexts using this file but I'm not sure diff --git a/pkg/gui/modes/diffing/diffing.go b/pkg/gui/modes/diffing/diffing.go index a5e103d62..b27662b72 100644 --- a/pkg/gui/modes/diffing/diffing.go +++ b/pkg/gui/modes/diffing/diffing.go @@ -10,6 +10,20 @@ func New() Diffing { return Diffing{} } -func (m *Diffing) Active() bool { - return m.Ref != "" +func (self *Diffing) Active() bool { + return self.Ref != "" +} + +// GetFromAndReverseArgsForDiff tells us the from and reverse args to be used in a diff command. +// If we're not in diff mode we'll end up with the equivalent of a `git show` i.e `git diff blah^..blah`. +func (self *Diffing) GetFromAndReverseArgsForDiff(to string) (string, bool) { + from := to + "^" + reverse := false + + if self.Active() { + reverse = self.Reverse + from = self.Ref + } + + return from, reverse } diff --git a/pkg/gui/patch_building_panel.go b/pkg/gui/patch_building_panel.go index 6b48d2bc2..d71b43e76 100644 --- a/pkg/gui/patch_building_panel.go +++ b/pkg/gui/patch_building_panel.go @@ -4,19 +4,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/utils" ) -// getFromAndReverseArgsForDiff tells us the from and reverse args to be used in a diff command. If we're not in diff mode we'll end up with the equivalent of a `git show` i.e `git diff blah^..blah`. -func (gui *Gui) getFromAndReverseArgsForDiff(to string) (string, bool) { - from := to + "^" - reverse := false - - if gui.State.Modes.Diffing.Active() { - reverse = gui.State.Modes.Diffing.Reverse - from = gui.State.Modes.Diffing.Ref - } - - return from, reverse -} - func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error { if !gui.git.Patch.PatchManager.Active() { return gui.handleEscapePatchBuildingPanel() @@ -32,7 +19,7 @@ func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error { } to := gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.GetRefName() - from, reverse := gui.getFromAndReverseArgsForDiff(to) + from, reverse := gui.State.Modes.Diffing.GetFromAndReverseArgsForDiff(to) diff, err := gui.git.WorkingTree.ShowFileDiff(from, to, reverse, node.GetPath(), true) if err != nil { return err From 120078f0112b64b201cf038b09f0cb00b8421d72 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Tue, 22 Feb 2022 20:17:26 +1100 Subject: [PATCH 074/385] use PopContext --- pkg/gui/commit_message_panel.go | 4 ++-- pkg/gui/confirmation_panel.go | 2 +- pkg/gui/credentials_panel.go | 4 ++-- pkg/gui/extras_panel.go | 2 +- pkg/gui/menu_panel.go | 2 +- pkg/gui/searching.go | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/gui/commit_message_panel.go b/pkg/gui/commit_message_panel.go index b59111fe2..071503a6b 100644 --- a/pkg/gui/commit_message_panel.go +++ b/pkg/gui/commit_message_panel.go @@ -18,7 +18,7 @@ func (gui *Gui) handleCommitConfirm() error { cmdObj := gui.git.Commit.CommitCmdObj(message) gui.c.LogAction(gui.c.Tr.Actions.Commit) - _ = gui.returnFromContext() + _ = gui.c.PopContext() return gui.withGpgHandling(cmdObj, gui.c.Tr.CommittingStatus, func() error { gui.Views.CommitMessage.ClearTextArea() gui.State.failedCommitMessage = "" @@ -27,7 +27,7 @@ func (gui *Gui) handleCommitConfirm() error { } func (gui *Gui) handleCommitClose() error { - return gui.returnFromContext() + return gui.c.PopContext() } func (gui *Gui) handleCommitMessageFocused() error { diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index b2cfabfab..15e5a8f45 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -50,7 +50,7 @@ func (gui *Gui) closeConfirmationPrompt(handlersManageFocus bool) error { } if !handlersManageFocus { - if err := gui.returnFromContext(); err != nil { + if err := gui.c.PopContext(); err != nil { return err } } diff --git a/pkg/gui/credentials_panel.go b/pkg/gui/credentials_panel.go index 796aa70c6..1277ac8ef 100644 --- a/pkg/gui/credentials_panel.go +++ b/pkg/gui/credentials_panel.go @@ -44,7 +44,7 @@ func (gui *Gui) handleSubmitCredential() error { message := strings.TrimSpace(credentialsView.TextArea.GetContent()) gui.credentials <- message credentialsView.ClearTextArea() - if err := gui.returnFromContext(); err != nil { + if err := gui.c.PopContext(); err != nil { return err } @@ -54,7 +54,7 @@ func (gui *Gui) handleSubmitCredential() error { func (gui *Gui) handleCloseCredentialsView() error { gui.Views.Credentials.ClearTextArea() gui.credentials <- "" - return gui.returnFromContext() + return gui.c.PopContext() } func (gui *Gui) handleAskFocused() error { diff --git a/pkg/gui/extras_panel.go b/pkg/gui/extras_panel.go index bb0eaf934..462a5118e 100644 --- a/pkg/gui/extras_panel.go +++ b/pkg/gui/extras_panel.go @@ -17,7 +17,7 @@ func (gui *Gui) handleCreateExtrasMenuPanel() error { OnPress: func() error { currentContext := gui.currentStaticContext() if gui.ShowExtrasWindow && currentContext.GetKey() == context.COMMAND_LOG_CONTEXT_KEY { - if err := gui.returnFromContext(); err != nil { + if err := gui.c.PopContext(); err != nil { return err } } diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go index 4afe931d1..e787162ed 100644 --- a/pkg/gui/menu_panel.go +++ b/pkg/gui/menu_panel.go @@ -19,7 +19,7 @@ func (gui *Gui) getMenuOptions() map[string]string { } func (gui *Gui) handleMenuClose() error { - return gui.returnFromContext() + return gui.c.PopContext() } // note: items option is mutated by this function diff --git a/pkg/gui/searching.go b/pkg/gui/searching.go index 25a3ff63a..c38c77e0a 100644 --- a/pkg/gui/searching.go +++ b/pkg/gui/searching.go @@ -26,7 +26,7 @@ func (gui *Gui) handleOpenSearch(viewName string) error { func (gui *Gui) handleSearch() error { gui.State.Searching.searchString = gui.Views.Search.TextArea.GetContent() - if err := gui.returnFromContext(); err != nil { + if err := gui.c.PopContext(); err != nil { return err } @@ -93,7 +93,7 @@ func (gui *Gui) handleSearchEscape() error { return err } - if err := gui.returnFromContext(); err != nil { + if err := gui.c.PopContext(); err != nil { return err } From d991d74b063c8bc8edf27321bf8a98d1a51e3a54 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Tue, 22 Feb 2022 21:16:00 +1100 Subject: [PATCH 075/385] add commit message controller --- pkg/commands/oscommands/cmd_obj_runner.go | 3 + pkg/gui/commit_message_panel.go | 33 ++------ .../controllers/commit_message_controller.go | 79 +++++++++++++++++++ pkg/gui/controllers/files_controller.go | 32 ++++---- pkg/gui/controllers/helpers/gpg_helper.go | 74 +++++++++++++++++ pkg/gui/controllers/helpers/helpers.go | 2 + pkg/gui/gpg.go | 66 ---------------- pkg/gui/gui.go | 37 +++++++-- pkg/gui/gui_common.go | 4 + pkg/gui/keybindings.go | 12 --- pkg/gui/types/common.go | 4 + 11 files changed, 217 insertions(+), 129 deletions(-) create mode 100644 pkg/gui/controllers/commit_message_controller.go create mode 100644 pkg/gui/controllers/helpers/gpg_helper.go delete mode 100644 pkg/gui/gpg.go diff --git a/pkg/commands/oscommands/cmd_obj_runner.go b/pkg/commands/oscommands/cmd_obj_runner.go index 9522bc627..92e024758 100644 --- a/pkg/commands/oscommands/cmd_obj_runner.go +++ b/pkg/commands/oscommands/cmd_obj_runner.go @@ -207,6 +207,9 @@ func (self *cmdObjRunner) runAndStreamAux( cmdObj ICmdObj, onRun func(*cmdHandler, io.Writer), ) error { + // if we're streaming this we don't want any fancy terminal stuff + cmdObj.AddEnvVars("TERM=dumb") + cmdWriter := self.guiIO.newCmdWriterFn() if cmdObj.ShouldLog() { diff --git a/pkg/gui/commit_message_panel.go b/pkg/gui/commit_message_panel.go index 071503a6b..35ffc822f 100644 --- a/pkg/gui/commit_message_panel.go +++ b/pkg/gui/commit_message_panel.go @@ -8,28 +8,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/utils" ) -func (gui *Gui) handleCommitConfirm() error { - message := strings.TrimSpace(gui.Views.CommitMessage.TextArea.GetContent()) - gui.State.failedCommitMessage = message - if message == "" { - return gui.c.ErrorMsg(gui.c.Tr.CommitWithoutMessageErr) - } - - cmdObj := gui.git.Commit.CommitCmdObj(message) - gui.c.LogAction(gui.c.Tr.Actions.Commit) - - _ = gui.c.PopContext() - return gui.withGpgHandling(cmdObj, gui.c.Tr.CommittingStatus, func() error { - gui.Views.CommitMessage.ClearTextArea() - gui.State.failedCommitMessage = "" - return nil - }) -} - -func (gui *Gui) handleCommitClose() error { - return gui.c.PopContext() -} - func (gui *Gui) handleCommitMessageFocused() error { message := utils.ResolvePlaceholderString( gui.c.Tr.CommitMessageConfirm, @@ -45,15 +23,14 @@ func (gui *Gui) handleCommitMessageFocused() error { return gui.renderString(gui.Views.Options, message) } -func (gui *Gui) getBufferLength(view *gocui.View) string { - return " " + strconv.Itoa(strings.Count(view.TextArea.GetContent(), "")-1) + " " -} - -// RenderCommitLength is a function. func (gui *Gui) RenderCommitLength() { if !gui.c.UserConfig.Gui.CommitLength.Show { return } - gui.Views.CommitMessage.Subtitle = gui.getBufferLength(gui.Views.CommitMessage) + gui.Views.CommitMessage.Subtitle = getBufferLength(gui.Views.CommitMessage) +} + +func getBufferLength(view *gocui.View) string { + return " " + strconv.Itoa(strings.Count(view.TextArea.GetContent(), "")-1) + " " } diff --git a/pkg/gui/controllers/commit_message_controller.go b/pkg/gui/controllers/commit_message_controller.go new file mode 100644 index 000000000..6992e1eee --- /dev/null +++ b/pkg/gui/controllers/commit_message_controller.go @@ -0,0 +1,79 @@ +package controllers + +import ( + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type CommitMessageController struct { + baseController + *controllerCommon + + getCommitMessage func() string + onCommitAttempt func(message string) + onCommitSuccess func() +} + +var _ types.IController = &CommitMessageController{} + +func NewCommitMessageController( + common *controllerCommon, + getCommitMessage func() string, + onCommitAttempt func(message string), + onCommitSuccess func(), +) *CommitMessageController { + return &CommitMessageController{ + baseController: baseController{}, + controllerCommon: common, + + getCommitMessage: getCommitMessage, + onCommitAttempt: onCommitAttempt, + onCommitSuccess: onCommitSuccess, + } +} + +func (self *CommitMessageController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + bindings := []*types.Binding{ + { + Key: opts.GetKey(opts.Config.Universal.SubmitEditorText), + Handler: self.handleCommitConfirm, + }, + { + Key: opts.GetKey(opts.Config.Universal.Return), + Handler: self.handleCommitClose, + }, + } + + return bindings +} + +func (self *CommitMessageController) Context() types.Context { + return self.context() +} + +// this method is pointless in this context but I'm keeping it consistent +// with other contexts so that when generics arrive it's easier to refactor +func (self *CommitMessageController) context() types.Context { + return self.contexts.CommitMessage +} + +func (self *CommitMessageController) handleCommitConfirm() error { + message := self.getCommitMessage() + self.onCommitAttempt(message) + + if message == "" { + return self.c.ErrorMsg(self.c.Tr.CommitWithoutMessageErr) + } + + cmdObj := self.git.Commit.CommitCmdObj(message) + self.c.LogAction(self.c.Tr.Actions.Commit) + + _ = self.c.PopContext() + return self.helpers.GPG.WithGpgHandling(cmdObj, self.c.Tr.CommittingStatus, func() error { + self.onCommitSuccess() + return nil + }) +} + +func (self *CommitMessageController) handleCommitClose() error { + return self.c.PopContext() +} diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index 018322f1a..e12554a3d 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -8,7 +8,6 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/filetree" @@ -20,11 +19,10 @@ type FilesController struct { baseController *controllerCommon - enterSubmodule func(submodule *models.SubmoduleConfig) error - setCommitMessage func(message string) - withGpgHandling func(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error - getFailedCommitMessage func() string - switchToMergeFn func(path string) error + enterSubmodule func(submodule *models.SubmoduleConfig) error + setCommitMessage func(message string) + getSavedCommitMessage func() string + switchToMergeFn func(path string) error } var _ types.IController = &FilesController{} @@ -33,17 +31,15 @@ func NewFilesController( common *controllerCommon, enterSubmodule func(submodule *models.SubmoduleConfig) error, setCommitMessage func(message string), - withGpgHandling func(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error, - getFailedCommitMessage func() string, + getSavedCommitMessage func() string, switchToMergeFn func(path string) error, ) *FilesController { return &FilesController{ - controllerCommon: common, - enterSubmodule: enterSubmodule, - setCommitMessage: setCommitMessage, - withGpgHandling: withGpgHandling, - getFailedCommitMessage: getFailedCommitMessage, - switchToMergeFn: switchToMergeFn, + controllerCommon: common, + enterSubmodule: enterSubmodule, + setCommitMessage: setCommitMessage, + getSavedCommitMessage: getSavedCommitMessage, + switchToMergeFn: switchToMergeFn, } } @@ -409,9 +405,9 @@ func (self *FilesController) HandleCommitPress() error { return self.promptToStageAllAndRetry(self.HandleCommitPress) } - failedCommitMessage := self.getFailedCommitMessage() - if len(failedCommitMessage) > 0 { - self.setCommitMessage(failedCommitMessage) + savedCommitMessage := self.getSavedCommitMessage() + if len(savedCommitMessage) > 0 { + self.setCommitMessage(savedCommitMessage) } else { commitPrefixConfig := self.commitPrefixConfigForRepo() if commitPrefixConfig != nil { @@ -470,7 +466,7 @@ func (self *FilesController) handleAmendCommitPress() error { HandleConfirm: func() error { cmdObj := self.git.Commit.AmendHeadCmdObj() self.c.LogAction(self.c.Tr.Actions.AmendCommit) - return self.withGpgHandling(cmdObj, self.c.Tr.AmendingStatus, nil) + return self.helpers.GPG.WithGpgHandling(cmdObj, self.c.Tr.AmendingStatus, nil) }, }) } diff --git a/pkg/gui/controllers/helpers/gpg_helper.go b/pkg/gui/controllers/helpers/gpg_helper.go new file mode 100644 index 000000000..2e287c2b4 --- /dev/null +++ b/pkg/gui/controllers/helpers/gpg_helper.go @@ -0,0 +1,74 @@ +package helpers + +import ( + "fmt" + + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type GpgHelper struct { + c *types.HelperCommon + os *oscommands.OSCommand + git *commands.GitCommand +} + +func NewGpgHelper( + c *types.HelperCommon, + os *oscommands.OSCommand, + git *commands.GitCommand, +) *GpgHelper { + return &GpgHelper{ + c: c, + os: os, + git: git, + } +} + +// Currently there is a bug where if we switch to a subprocess from within +// WithWaitingStatus we get stuck there and can't return to lazygit. We could +// fix this bug, or just stop running subprocesses from within there, given that +// we don't need to see a loading status if we're in a subprocess. +// TODO: we shouldn't need to use a shell here, but looks like that NewShell function contains some windows specific quoting stuff. We should centralise that. +func (self *GpgHelper) WithGpgHandling(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error { + useSubprocess := self.git.Config.UsingGpg() + if useSubprocess { + success, err := self.c.RunSubprocess(self.os.Cmd.NewShell(cmdObj.ToString())) + if success && onSuccess != nil { + if err := onSuccess(); err != nil { + return err + } + } + if err := self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil { + return err + } + + return err + } else { + return self.runAndStream(cmdObj, waitingStatus, onSuccess) + } +} + +func (self *GpgHelper) runAndStream(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error { + cmdObj = self.os.Cmd.NewShell(cmdObj.ToString()) + + return self.c.WithWaitingStatus(waitingStatus, func() error { + if err := cmdObj.StreamOutput().Run(); err != nil { + _ = self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + return self.c.Error( + fmt.Errorf( + self.c.Tr.GitCommandFailed, self.c.UserConfig.Keybinding.Universal.ExtrasMenu, + ), + ) + } + + if onSuccess != nil { + if err := onSuccess(); err != nil { + return err + } + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + }) +} diff --git a/pkg/gui/controllers/helpers/helpers.go b/pkg/gui/controllers/helpers/helpers.go index 2a7c43ff0..c45852e29 100644 --- a/pkg/gui/controllers/helpers/helpers.go +++ b/pkg/gui/controllers/helpers/helpers.go @@ -11,6 +11,7 @@ type Helpers struct { CherryPick *CherryPickHelper Host *HostHelper PatchBuilding *PatchBuildingHelper + GPG *GpgHelper } func NewStubHelpers() *Helpers { @@ -25,5 +26,6 @@ func NewStubHelpers() *Helpers { CherryPick: &CherryPickHelper{}, Host: &HostHelper{}, PatchBuilding: &PatchBuildingHelper{}, + GPG: &GpgHelper{}, } } diff --git a/pkg/gui/gpg.go b/pkg/gui/gpg.go deleted file mode 100644 index 60d728c42..000000000 --- a/pkg/gui/gpg.go +++ /dev/null @@ -1,66 +0,0 @@ -package gui - -import ( - "fmt" - - "github.com/jesseduffield/lazygit/pkg/commands/oscommands" - "github.com/jesseduffield/lazygit/pkg/gui/style" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - -// Currently there is a bug where if we switch to a subprocess from within -// WithWaitingStatus we get stuck there and can't return to lazygit. We could -// fix this bug, or just stop running subprocesses from within there, given that -// we don't need to see a loading status if we're in a subprocess. -// TODO: work out if we actually need to use a shell command here -func (gui *Gui) withGpgHandling(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error { - gui.LogCommand(cmdObj.ToString(), true) - - useSubprocess := gui.git.Config.UsingGpg() - if useSubprocess { - success, err := gui.runSubprocessWithSuspense(gui.os.Cmd.NewShell(cmdObj.ToString())) - if success && onSuccess != nil { - if err := onSuccess(); err != nil { - return err - } - } - if err := gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}); err != nil { - return err - } - - return err - } else { - return gui.RunAndStream(cmdObj, waitingStatus, onSuccess) - } -} - -func (gui *Gui) RunAndStream(cmdObj oscommands.ICmdObj, waitingStatus string, onSuccess func() error) error { - return gui.c.WithWaitingStatus(waitingStatus, func() error { - cmdObj := gui.os.Cmd.NewShell(cmdObj.ToString()) - cmdObj.AddEnvVars("TERM=dumb") - cmdWriter := gui.getCmdWriter() - cmd := cmdObj.GetCmd() - cmd.Stdout = cmdWriter - cmd.Stderr = cmdWriter - - if err := cmd.Run(); err != nil { - if _, err := cmd.Stdout.Write([]byte(fmt.Sprintf("%s\n", style.FgRed.Sprint(err.Error())))); err != nil { - gui.c.Log.Error(err) - } - _ = gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) - return gui.c.Error( - fmt.Errorf( - gui.c.Tr.GitCommandFailed, gui.c.UserConfig.Keybinding.Universal.ExtrasMenu, - ), - ) - } - - if onSuccess != nil { - if err := onSuccess(); err != nil { - return err - } - } - - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) - }) -} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 93476636c..511406e77 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -193,8 +193,9 @@ type GuiRepoState struct { // back in sync with the repo state ViewsSetup bool - // this is the message of the last failed commit attempt - failedCommitMessage string + // we store a commit message in this field if we've escaped the commit message + // panel without committing or if our commit failed + savedCommitMessage string ScreenMode WindowMaximisation } @@ -503,6 +504,7 @@ func (gui *Gui) resetControllers() { Files: helpers.NewFilesHelper(controllerCommon, gui.git, osCommand), WorkingTree: helpers.NewWorkingTreeHelper(model), Tags: helpers.NewTagsHelper(controllerCommon, gui.git), + GPG: helpers.NewGpgHelper(controllerCommon, gui.os, gui.git), MergeAndRebase: rebaseHelper, CherryPick: helpers.NewCherryPickHelper( controllerCommon, @@ -538,15 +540,39 @@ func (gui *Gui) resetControllers() { reflogController := controllers.NewReflogController(common) subCommitsController := controllers.NewSubCommitsController(common) + getSavedCommitMessage := func() string { + return gui.State.savedCommitMessage + } + + getCommitMessage := func() string { + return strings.TrimSpace(gui.Views.CommitMessage.TextArea.GetContent()) + } + + setCommitMessage := gui.getSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage }) + + onCommitAttempt := func(message string) { + gui.Views.CommitMessage.ClearTextArea() + } + + onCommitSuccess := func() { + gui.State.savedCommitMessage = "" + } + + commitMessageController := controllers.NewCommitMessageController( + common, + getCommitMessage, + onCommitAttempt, + onCommitSuccess, + ) + gui.Controllers = Controllers{ Submodules: submodulesController, Global: controllers.NewGlobalController(common), Files: controllers.NewFilesController( common, gui.enterSubmodule, - gui.getSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage }), - gui.withGpgHandling, - func() string { return gui.State.failedCommitMessage }, + setCommitMessage, + getSavedCommitMessage, gui.switchToMerge, ), Tags: controllers.NewTagsController(common), @@ -604,6 +630,7 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(gui.State.Contexts.Remotes, gui.Controllers.Remotes) controllers.AttachControllers(gui.State.Contexts.Stash, stashController) controllers.AttachControllers(gui.State.Contexts.Menu, gui.Controllers.Menu) + controllers.AttachControllers(gui.State.Contexts.CommitMessage, commitMessageController) controllers.AttachControllers(gui.State.Contexts.Global, gui.Controllers.Sync, gui.Controllers.Undo, gui.Controllers.Global) listControllerFactory := controllers.NewListControllerFactory(gui.c) diff --git a/pkg/gui/gui_common.go b/pkg/gui/gui_common.go index ba9540178..2f44ebbce 100644 --- a/pkg/gui/gui_common.go +++ b/pkg/gui/gui_common.go @@ -34,6 +34,10 @@ func (self *guiCommon) RunSubprocessAndRefresh(cmdObj oscommands.ICmdObj) error return self.gui.runSubprocessWithSuspenseAndRefresh(cmdObj) } +func (self *guiCommon) RunSubprocess(cmdObj oscommands.ICmdObj) (bool, error) { + return self.gui.runSubprocessWithSuspense(cmdObj) +} + func (self *guiCommon) PushContext(context types.Context, opts ...types.OnFocusOpts) error { return self.gui.pushContext(context, opts...) } diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index fa0e893e0..19eb86baf 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -430,18 +430,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Handler: self.handleCopySelectedSideContextItemToClipboard, Description: self.c.Tr.LcCopyCommitShaToClipboard, }, - { - ViewName: "commitMessage", - Key: opts.GetKey(opts.Config.Universal.SubmitEditorText), - Modifier: gocui.ModNone, - Handler: self.handleCommitConfirm, - }, - { - ViewName: "commitMessage", - Key: opts.GetKey(opts.Config.Universal.Return), - Modifier: gocui.ModNone, - Handler: self.handleCommitClose, - }, { ViewName: "credentials", Key: opts.GetKey(opts.Config.Universal.Confirm), diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 9c13dcd67..650aa51eb 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -27,7 +27,11 @@ type IGuiCommon interface { PostRefreshUpdate(Context) error // this just re-renders the screen Render() + + // returns true if command completed successfully + RunSubprocess(cmdObj oscommands.ICmdObj) (bool, error) RunSubprocessAndRefresh(oscommands.ICmdObj) error + PushContext(context Context, opts ...OnFocusOpts) error PopContext() error CurrentContext() Context From bff5351ab3203b8bcd25e69bd7e925e0e1deb674 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Tue, 22 Feb 2022 21:21:35 +1100 Subject: [PATCH 076/385] better naming --- .../controllers/commit_message_controller.go | 8 +++--- .../controllers/commits_files_controller.go | 28 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/pkg/gui/controllers/commit_message_controller.go b/pkg/gui/controllers/commit_message_controller.go index 6992e1eee..e5cdb866d 100644 --- a/pkg/gui/controllers/commit_message_controller.go +++ b/pkg/gui/controllers/commit_message_controller.go @@ -35,11 +35,11 @@ func (self *CommitMessageController) GetKeybindings(opts types.KeybindingsOpts) bindings := []*types.Binding{ { Key: opts.GetKey(opts.Config.Universal.SubmitEditorText), - Handler: self.handleCommitConfirm, + Handler: self.confirm, }, { Key: opts.GetKey(opts.Config.Universal.Return), - Handler: self.handleCommitClose, + Handler: self.close, }, } @@ -56,7 +56,7 @@ func (self *CommitMessageController) context() types.Context { return self.contexts.CommitMessage } -func (self *CommitMessageController) handleCommitConfirm() error { +func (self *CommitMessageController) confirm() error { message := self.getCommitMessage() self.onCommitAttempt(message) @@ -74,6 +74,6 @@ func (self *CommitMessageController) handleCommitConfirm() error { }) } -func (self *CommitMessageController) handleCommitClose() error { +func (self *CommitMessageController) close() error { return self.c.PopContext() } diff --git a/pkg/gui/controllers/commits_files_controller.go b/pkg/gui/controllers/commits_files_controller.go index 33d4ff4c1..5eed10883 100644 --- a/pkg/gui/controllers/commits_files_controller.go +++ b/pkg/gui/controllers/commits_files_controller.go @@ -29,37 +29,37 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) [] bindings := []*types.Binding{ { Key: opts.GetKey(opts.Config.CommitFiles.CheckoutCommitFile), - Handler: self.checkSelected(self.handleCheckoutCommitFile), + Handler: self.checkSelected(self.checkout), Description: self.c.Tr.LcCheckoutCommitFile, }, { Key: opts.GetKey(opts.Config.Universal.Remove), - Handler: self.checkSelected(self.handleDiscardOldFileChange), + Handler: self.checkSelected(self.discard), Description: self.c.Tr.LcDiscardOldFileChange, }, { Key: opts.GetKey(opts.Config.Universal.OpenFile), - Handler: self.checkSelected(self.handleOpenOldCommitFile), + Handler: self.checkSelected(self.open), Description: self.c.Tr.LcOpenFile, }, { Key: opts.GetKey(opts.Config.Universal.Edit), - Handler: self.checkSelected(self.handleEditCommitFile), + Handler: self.checkSelected(self.edit), Description: self.c.Tr.LcEditFile, }, { Key: opts.GetKey(opts.Config.Universal.Select), - Handler: self.checkSelected(self.handleToggleFileForPatch), + Handler: self.checkSelected(self.toggleForPatch), Description: self.c.Tr.LcToggleAddToPatch, }, { Key: opts.GetKey(opts.Config.Universal.GoInto), - Handler: self.checkSelected(self.handleEnterCommitFile), + Handler: self.checkSelected(self.enter), Description: self.c.Tr.LcEnterFile, }, { Key: opts.GetKey(opts.Config.Files.ToggleTreeView), - Handler: self.handleToggleCommitFileTreeView, + Handler: self.toggleTreeView, Description: self.c.Tr.LcToggleTreeView, }, } @@ -105,7 +105,7 @@ func (self *CommitFilesController) onClickMain(opts gocui.ViewMouseBindingOpts) return self.enterCommitFile(node, types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: clickedViewLineIdx}) } -func (self *CommitFilesController) handleCheckoutCommitFile(node *filetree.CommitFileNode) error { +func (self *CommitFilesController) checkout(node *filetree.CommitFileNode) error { self.c.LogAction(self.c.Tr.Actions.CheckoutFile) if err := self.git.WorkingTree.CheckoutFile(self.context().GetRefName(), node.GetPath()); err != nil { return self.c.Error(err) @@ -114,7 +114,7 @@ func (self *CommitFilesController) handleCheckoutCommitFile(node *filetree.Commi return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) } -func (self *CommitFilesController) handleDiscardOldFileChange(node *filetree.CommitFileNode) error { +func (self *CommitFilesController) discard(node *filetree.CommitFileNode) error { if ok, err := self.helpers.PatchBuilding.ValidateNormalWorkingTreeState(); !ok { return err } @@ -137,11 +137,11 @@ func (self *CommitFilesController) handleDiscardOldFileChange(node *filetree.Com }) } -func (self *CommitFilesController) handleOpenOldCommitFile(node *filetree.CommitFileNode) error { +func (self *CommitFilesController) open(node *filetree.CommitFileNode) error { return self.helpers.Files.OpenFile(node.GetPath()) } -func (self *CommitFilesController) handleEditCommitFile(node *filetree.CommitFileNode) error { +func (self *CommitFilesController) edit(node *filetree.CommitFileNode) error { if node.File == nil { return self.c.ErrorMsg(self.c.Tr.ErrCannotEditDirectory) } @@ -149,7 +149,7 @@ func (self *CommitFilesController) handleEditCommitFile(node *filetree.CommitFil return self.helpers.Files.EditFile(node.GetPath()) } -func (self *CommitFilesController) handleToggleFileForPatch(node *filetree.CommitFileNode) error { +func (self *CommitFilesController) toggleForPatch(node *filetree.CommitFileNode) error { toggleTheFile := func() error { if !self.git.Patch.PatchManager.Active() { if err := self.startPatchManager(); err != nil { @@ -208,7 +208,7 @@ func (self *CommitFilesController) startPatchManager() error { return nil } -func (self *CommitFilesController) handleEnterCommitFile(node *filetree.CommitFileNode) error { +func (self *CommitFilesController) enter(node *filetree.CommitFileNode) error { return self.enterCommitFile(node, types.OnFocusOpts{ClickedViewName: "", ClickedViewLineIdx: -1}) } @@ -252,7 +252,7 @@ func (self *CommitFilesController) handleToggleCommitFileDirCollapsed(node *file } // NOTE: this is very similar to handleToggleFileTreeView, could be DRY'd with generics -func (self *CommitFilesController) handleToggleCommitFileTreeView() error { +func (self *CommitFilesController) toggleTreeView() error { self.context().CommitFileTreeViewModel.ToggleShowTree() return self.c.PostRefreshUpdate(self.context()) From 1a7fe2835c8eadd1303770fafe665f98aca47114 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Wed, 23 Feb 2022 18:47:51 +1100 Subject: [PATCH 077/385] integration test for multiline commit message --- .../expected/.git_keep/COMMIT_EDITMSG | 3 +++ .../expected/.git_keep/FETCH_HEAD | 0 .../commitMultiline/expected/.git_keep/HEAD | 1 + .../commitMultiline/expected/.git_keep/config | 10 ++++++++ .../expected/.git_keep/description | 1 + .../commitMultiline/expected/.git_keep/index | Bin 0 -> 425 bytes .../expected/.git_keep/info/exclude | 7 +++++ .../expected/.git_keep/logs/HEAD | 5 ++++ .../expected/.git_keep/logs/refs/heads/master | 5 ++++ .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin 0 -> 52 bytes .../17/6069f0ded1db43eecb3b629a6077dba6c68295 | 2 ++ .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin 0 -> 21 bytes .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin 0 -> 103 bytes .../2f/6174050380438f14b16658a356e762435ca591 | Bin 0 -> 128 bytes .../30/a1ca3481fdec3245b02aeacfb72ddfe2a433be | Bin 0 -> 154 bytes .../37/128a3020849daa0847462d14c384cc74c42ae0 | Bin 0 -> 149 bytes .../39/33a268c502712421b7bfa04888319d6f108574 | Bin 0 -> 149 bytes .../4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f | Bin 0 -> 21 bytes .../57/4013716a7f007a27b647b90cdbc78d006d792b | 2 ++ .../9f/1b5440546da24daad7014ccf3e1f4d81f9414b | Bin 0 -> 148 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin 0 -> 21 bytes .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin 0 -> 77 bytes .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin 0 -> 21 bytes .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin 0 -> 21 bytes .../expected/.git_keep/refs/heads/master | 1 + .../commitMultiline/expected/myfile1 | 1 + .../commitMultiline/expected/myfile2 | 1 + .../commitMultiline/expected/myfile3 | 1 + .../commitMultiline/expected/myfile4 | 1 + .../commitMultiline/expected/myfile5 | 1 + .../commitMultiline/recording.json | 1 + test/integration/commitMultiline/setup.sh | 24 ++++++++++++++++++ test/integration/commitMultiline/test.json | 4 +++ 33 files changed, 71 insertions(+) create mode 100644 test/integration/commitMultiline/expected/.git_keep/COMMIT_EDITMSG create mode 100644 test/integration/commitMultiline/expected/.git_keep/FETCH_HEAD create mode 100644 test/integration/commitMultiline/expected/.git_keep/HEAD create mode 100644 test/integration/commitMultiline/expected/.git_keep/config create mode 100644 test/integration/commitMultiline/expected/.git_keep/description create mode 100644 test/integration/commitMultiline/expected/.git_keep/index create mode 100644 test/integration/commitMultiline/expected/.git_keep/info/exclude create mode 100644 test/integration/commitMultiline/expected/.git_keep/logs/HEAD create mode 100644 test/integration/commitMultiline/expected/.git_keep/logs/refs/heads/master create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/17/6069f0ded1db43eecb3b629a6077dba6c68295 create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/37/128a3020849daa0847462d14c384cc74c42ae0 create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/39/33a268c502712421b7bfa04888319d6f108574 create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/57/4013716a7f007a27b647b90cdbc78d006d792b create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/9f/1b5440546da24daad7014ccf3e1f4d81f9414b create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 create mode 100644 test/integration/commitMultiline/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b create mode 100644 test/integration/commitMultiline/expected/.git_keep/refs/heads/master create mode 100644 test/integration/commitMultiline/expected/myfile1 create mode 100644 test/integration/commitMultiline/expected/myfile2 create mode 100644 test/integration/commitMultiline/expected/myfile3 create mode 100644 test/integration/commitMultiline/expected/myfile4 create mode 100644 test/integration/commitMultiline/expected/myfile5 create mode 100644 test/integration/commitMultiline/recording.json create mode 100644 test/integration/commitMultiline/setup.sh create mode 100644 test/integration/commitMultiline/test.json diff --git a/test/integration/commitMultiline/expected/.git_keep/COMMIT_EDITMSG b/test/integration/commitMultiline/expected/.git_keep/COMMIT_EDITMSG new file mode 100644 index 000000000..bf8858b06 --- /dev/null +++ b/test/integration/commitMultiline/expected/.git_keep/COMMIT_EDITMSG @@ -0,0 +1,3 @@ +first line + +third line diff --git a/test/integration/commitMultiline/expected/.git_keep/FETCH_HEAD b/test/integration/commitMultiline/expected/.git_keep/FETCH_HEAD new file mode 100644 index 000000000..e69de29bb diff --git a/test/integration/commitMultiline/expected/.git_keep/HEAD b/test/integration/commitMultiline/expected/.git_keep/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/test/integration/commitMultiline/expected/.git_keep/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/test/integration/commitMultiline/expected/.git_keep/config b/test/integration/commitMultiline/expected/.git_keep/config new file mode 100644 index 000000000..8ae104545 --- /dev/null +++ b/test/integration/commitMultiline/expected/.git_keep/config @@ -0,0 +1,10 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true +[user] + email = CI@example.com + name = CI diff --git a/test/integration/commitMultiline/expected/.git_keep/description b/test/integration/commitMultiline/expected/.git_keep/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/test/integration/commitMultiline/expected/.git_keep/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/test/integration/commitMultiline/expected/.git_keep/index b/test/integration/commitMultiline/expected/.git_keep/index new file mode 100644 index 0000000000000000000000000000000000000000..a08b4116ed82b32096ee3fb2e1be7b23fe2eb599 GIT binary patch literal 425 zcmZ?q402{*U|<4b)+EtqW&D8}f-ss9D8>|R&(6TmxP*a$@heb`2oSR^-ShabYU+(I z5us5$`A!!Cyjr@iGO*`Xre)@&8Uhu7^b5rE=D}#FIdbUcNbvkHYEasD?&YdQ;Z^-D zue9e|sKd-Lf|?`PaPud~91smPM<3ms``NtOXUd+v;XkEtNL|3oUt`x1X_z_2P;-Q4 zEK>)W1EQhkIG~$z$>ivR@P9_f%3h_vIBoGIDfZUu5STe8P;-P=7_))Q0nt!%0@2O! zH_4Z}x=U01mLlh)SBpN~-`)0+A7+jz(43GUS63h<$zZBrz-6%Tlu6^?H%6`-v|gRx gu6zH{661a4-2Q_5a=%XHJ)>KEYI;eh3X8;a0Nc-oga7~l literal 0 HcmV?d00001 diff --git a/test/integration/commitMultiline/expected/.git_keep/info/exclude b/test/integration/commitMultiline/expected/.git_keep/info/exclude new file mode 100644 index 000000000..8e9f2071f --- /dev/null +++ b/test/integration/commitMultiline/expected/.git_keep/info/exclude @@ -0,0 +1,7 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ +.DS_Store diff --git a/test/integration/commitMultiline/expected/.git_keep/logs/HEAD b/test/integration/commitMultiline/expected/.git_keep/logs/HEAD new file mode 100644 index 000000000..88b99d1ab --- /dev/null +++ b/test/integration/commitMultiline/expected/.git_keep/logs/HEAD @@ -0,0 +1,5 @@ +0000000000000000000000000000000000000000 176069f0ded1db43eecb3b629a6077dba6c68295 CI 1645602422 +1100 commit (initial): myfile1 +176069f0ded1db43eecb3b629a6077dba6c68295 9f1b5440546da24daad7014ccf3e1f4d81f9414b CI 1645602422 +1100 commit: myfile2 +9f1b5440546da24daad7014ccf3e1f4d81f9414b 3933a268c502712421b7bfa04888319d6f108574 CI 1645602422 +1100 commit: myfile3 +3933a268c502712421b7bfa04888319d6f108574 37128a3020849daa0847462d14c384cc74c42ae0 CI 1645602422 +1100 commit: myfile4 +37128a3020849daa0847462d14c384cc74c42ae0 574013716a7f007a27b647b90cdbc78d006d792b CI 1645602427 +1100 commit: first line diff --git a/test/integration/commitMultiline/expected/.git_keep/logs/refs/heads/master b/test/integration/commitMultiline/expected/.git_keep/logs/refs/heads/master new file mode 100644 index 000000000..88b99d1ab --- /dev/null +++ b/test/integration/commitMultiline/expected/.git_keep/logs/refs/heads/master @@ -0,0 +1,5 @@ +0000000000000000000000000000000000000000 176069f0ded1db43eecb3b629a6077dba6c68295 CI 1645602422 +1100 commit (initial): myfile1 +176069f0ded1db43eecb3b629a6077dba6c68295 9f1b5440546da24daad7014ccf3e1f4d81f9414b CI 1645602422 +1100 commit: myfile2 +9f1b5440546da24daad7014ccf3e1f4d81f9414b 3933a268c502712421b7bfa04888319d6f108574 CI 1645602422 +1100 commit: myfile3 +3933a268c502712421b7bfa04888319d6f108574 37128a3020849daa0847462d14c384cc74c42ae0 CI 1645602422 +1100 commit: myfile4 +37128a3020849daa0847462d14c384cc74c42ae0 574013716a7f007a27b647b90cdbc78d006d792b CI 1645602427 +1100 commit: first line diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/commitMultiline/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 new file mode 100644 index 0000000000000000000000000000000000000000..7f2ebf4eeb6ad6875bcc2a2b91ca3345ee06b45e GIT binary patch literal 52 zcmb ~ZE#08nZNMgRZ+ literal 0 HcmV?d00001 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/commitMultiline/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce new file mode 100644 index 0000000000000000000000000000000000000000..0a734f98100d24e67455a3cfa8497adaccc7a422 GIT binary patch literal 103 zcmV-t0GR)H0V^p=O;s>7Fl8__FfcPQQOK=K%gjkNWLUcA@n6-{8($(qqj>V2E(CbB zbYDeLV#FZ9^TVh?Y2Ue*s}_Y<^|!pzo^PR!qQsctem1Z6nX+eZ_)jSuQWx;@*VuJL J8UTCqE3ZN5G4lWb literal 0 HcmV?d00001 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 b/test/integration/commitMultiline/expected/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 new file mode 100644 index 0000000000000000000000000000000000000000..31ae3f5ba89b96ad2e268134913bd913a0bc46d9 GIT binary patch literal 128 zcmV-`0Du2@0V^p=O;s>7F<>w>FfcPQQOK=K%gjkNWLUcA@n6-{8($(qqj>V2E(CbB zbYDeLV#FZ9^TVh?Y2Ue*s}_Y<^|!pzo^PR!qQsctem1Z6nX+eZ_)jSuQWx;@*VuJL i8byf-!zGiW55oT$9V>g4{^GR7m!#NRuR{Q5NjxpS$UUzB literal 0 HcmV?d00001 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be b/test/integration/commitMultiline/expected/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be new file mode 100644 index 0000000000000000000000000000000000000000..aca754d63288ea16d4cd69754eac3b0cba133abe GIT binary patch literal 154 zcmV;L0A>Gp0V^p=O;s>7H)Sw1FfcPQQOK=K%gjkNWLUcA@n6-{8($(qqj>V2E(CbB zbYDeLV#FZ9^TVh?Y2Ue*s}_Y<^|!pzo^PR!qQsctem1Z6nX+eZ_)jSuQWx;@*VuJL z8byf-!zGiW55oT$9V>g4{^GR7m!#NRuR~Cjm@@dA ~0be5qjz~(zwAwV@rvkzqe2DI?TY7wY9lh zOmynIs&!Q`5HR=% d-=aM<0+48QhZhi7TJBfwC1$5+a3RBHMF-DK+ zAr&EVAd}zyx$brt?R6OM`pIou^itM#vna#@N9*hv5x^YunCkkcZrZobi<0>PFtRse DAMi_! literal 0 HcmV?d00001 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/39/33a268c502712421b7bfa04888319d6f108574 b/test/integration/commitMultiline/expected/.git_keep/objects/39/33a268c502712421b7bfa04888319d6f108574 new file mode 100644 index 0000000000000000000000000000000000000000..4195b00e1096723a64cb6d9c0a23e72ca2ec816d GIT binary patch literal 149 zcmV;G0BZku0gaA93c@fD06pgwxeJm_HfahXLQj3hX0wY0V@rvkzqe2DG%(Czcx`Rz z7DhbvUBvnVL*SgCDu$qhL6s^5&5m;k;5i;-F&pjj>ULBp5z$3Vl{{9WIygXP4FZZa zgN_JT488kf-R(5n>onixLv4G?h1YhokT53a(R+IaaLyd|nCkLpZrWFurv&o@FSD Dq})TL literal 0 HcmV?d00001 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f b/test/integration/commitMultiline/expected/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f new file mode 100644 index 0000000000000000000000000000000000000000..953241815cfa19b4d357807bedcbb2277b2e3ba8 GIT binary patch literal 21 ccmb {;fo08o?%QUCw| literal 0 HcmV?d00001 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/57/4013716a7f007a27b647b90cdbc78d006d792b b/test/integration/commitMultiline/expected/.git_keep/objects/57/4013716a7f007a27b647b90cdbc78d006d792b new file mode 100644 index 000000000..d675c1840 --- /dev/null +++ b/test/integration/commitMultiline/expected/.git_keep/objects/57/4013716a7f007a27b647b90cdbc78d006d792b @@ -0,0 +1,2 @@ +x崕K +0D祸)/YVbJ)d昪(睟盒7t5胏岇霘獷.胆Z靹=E7%徳寑,0懮鸔土E穓}pB.1ㄅ銱|$慇B嗊u迡{飮x=缴>琸﹊ 兘:`Nz灙躄辜猐颚圃9楐隷!? \ No newline at end of file diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/9f/1b5440546da24daad7014ccf3e1f4d81f9414b b/test/integration/commitMultiline/expected/.git_keep/objects/9f/1b5440546da24daad7014ccf3e1f4d81f9414b new file mode 100644 index 0000000000000000000000000000000000000000..9ea933b39bf38475d9bc5ace7c9fda421a30164d GIT binary patch literal 148 zcmV;F0Biqv0gaAJ3c@fDKwak)*$Xl=NhbzGgsyswd?r|EOeqoc_T~s~AMe3St=6?` z^!C&b5gnYd7$#pJXOZIB3;Pn;@RgV|QG`MkS?%GF*9aZM5Fks&9IX*a(L^R67@W&7 za2lnbRCxDiJM_Hh+q^vF6Y9RnCAE6j$aZ2NOQg?;0BX=N)#XoJ)o)ohA@u{{XgWsx CE<|zw literal 0 HcmV?d00001 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/commitMultiline/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 new file mode 100644 index 0000000000000000000000000000000000000000..285df3e5fbab12262e28d85e78af8a31cd0024c1 GIT binary patch literal 21 ccmb `~^A08nuUMF0Q* literal 0 HcmV?d00001 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 b/test/integration/commitMultiline/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 new file mode 100644 index 0000000000000000000000000000000000000000..96d2e71a6af75cdd27ac5d9628a27faecc40fb66 GIT binary patch literal 77 zcmV-T0J8sh0V^p=O;s>AU@$Z=Ff%bx$gNDv%t B=N-?^8o7KK;!x4hDxZ=ntVWIZ01*pecg literal 0 HcmV?d00001 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/commitMultiline/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 new file mode 100644 index 0000000000000000000000000000000000000000..d39fa7d2fecf1c45a132dfe3a8758952f3c8d968 GIT binary patch literal 21 ccmb }lpN08nuUO8@`> literal 0 HcmV?d00001 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/commitMultiline/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b new file mode 100644 index 0000000000000000000000000000000000000000..9b771fc2f6f41f91b00976b4ff3f8f9935f7931e GIT binary patch literal 21 ccmb >`CU&08otwO#lD@ literal 0 HcmV?d00001 diff --git a/test/integration/commitMultiline/expected/.git_keep/refs/heads/master b/test/integration/commitMultiline/expected/.git_keep/refs/heads/master new file mode 100644 index 000000000..c44ada3dd --- /dev/null +++ b/test/integration/commitMultiline/expected/.git_keep/refs/heads/master @@ -0,0 +1 @@ +574013716a7f007a27b647b90cdbc78d006d792b diff --git a/test/integration/commitMultiline/expected/myfile1 b/test/integration/commitMultiline/expected/myfile1 new file mode 100644 index 000000000..a5bce3fd2 --- /dev/null +++ b/test/integration/commitMultiline/expected/myfile1 @@ -0,0 +1 @@ +test1 diff --git a/test/integration/commitMultiline/expected/myfile2 b/test/integration/commitMultiline/expected/myfile2 new file mode 100644 index 000000000..180cf8328 --- /dev/null +++ b/test/integration/commitMultiline/expected/myfile2 @@ -0,0 +1 @@ +test2 diff --git a/test/integration/commitMultiline/expected/myfile3 b/test/integration/commitMultiline/expected/myfile3 new file mode 100644 index 000000000..df6b0d2bc --- /dev/null +++ b/test/integration/commitMultiline/expected/myfile3 @@ -0,0 +1 @@ +test3 diff --git a/test/integration/commitMultiline/expected/myfile4 b/test/integration/commitMultiline/expected/myfile4 new file mode 100644 index 000000000..d234c5e05 --- /dev/null +++ b/test/integration/commitMultiline/expected/myfile4 @@ -0,0 +1 @@ +test4 diff --git a/test/integration/commitMultiline/expected/myfile5 b/test/integration/commitMultiline/expected/myfile5 new file mode 100644 index 000000000..4f346f1ad --- /dev/null +++ b/test/integration/commitMultiline/expected/myfile5 @@ -0,0 +1 @@ +test5 diff --git a/test/integration/commitMultiline/recording.json b/test/integration/commitMultiline/recording.json new file mode 100644 index 000000000..bb0d16af6 --- /dev/null +++ b/test/integration/commitMultiline/recording.json @@ -0,0 +1 @@ +{"KeyEvents":[{"Timestamp":931,"Mod":0,"Key":256,"Ch":32},{"Timestamp":1467,"Mod":0,"Key":256,"Ch":99},{"Timestamp":2035,"Mod":0,"Key":256,"Ch":102},{"Timestamp":2090,"Mod":0,"Key":256,"Ch":105},{"Timestamp":2162,"Mod":0,"Key":256,"Ch":114},{"Timestamp":2259,"Mod":0,"Key":256,"Ch":115},{"Timestamp":2314,"Mod":0,"Key":256,"Ch":116},{"Timestamp":2411,"Mod":0,"Key":256,"Ch":32},{"Timestamp":2546,"Mod":0,"Key":256,"Ch":108},{"Timestamp":2578,"Mod":0,"Key":256,"Ch":105},{"Timestamp":2627,"Mod":0,"Key":256,"Ch":110},{"Timestamp":2691,"Mod":0,"Key":256,"Ch":101},{"Timestamp":3358,"Mod":4,"Key":13,"Ch":13},{"Timestamp":3577,"Mod":4,"Key":13,"Ch":13},{"Timestamp":3810,"Mod":0,"Key":256,"Ch":116},{"Timestamp":3874,"Mod":0,"Key":256,"Ch":104},{"Timestamp":3914,"Mod":0,"Key":256,"Ch":105},{"Timestamp":3986,"Mod":0,"Key":256,"Ch":114},{"Timestamp":4107,"Mod":0,"Key":256,"Ch":100},{"Timestamp":4195,"Mod":0,"Key":256,"Ch":32},{"Timestamp":4291,"Mod":0,"Key":256,"Ch":108},{"Timestamp":4322,"Mod":0,"Key":256,"Ch":105},{"Timestamp":4370,"Mod":0,"Key":256,"Ch":110},{"Timestamp":4426,"Mod":0,"Key":256,"Ch":101},{"Timestamp":4603,"Mod":0,"Key":13,"Ch":13},{"Timestamp":5267,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":272,"Height":74}]} \ No newline at end of file diff --git a/test/integration/commitMultiline/setup.sh b/test/integration/commitMultiline/setup.sh new file mode 100644 index 000000000..c6c6a9271 --- /dev/null +++ b/test/integration/commitMultiline/setup.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +set -e + +cd $1 + +git init + +git config user.email "CI@example.com" +git config user.name "CI" + +echo test1 > myfile1 +git add . +git commit -am "myfile1" +echo test2 > myfile2 +git add . +git commit -am "myfile2" +echo test3 > myfile3 +git add . +git commit -am "myfile3" +echo test4 > myfile4 +git add . +git commit -am "myfile4" +echo test5 > myfile5 diff --git a/test/integration/commitMultiline/test.json b/test/integration/commitMultiline/test.json new file mode 100644 index 000000000..5ac0bb1f5 --- /dev/null +++ b/test/integration/commitMultiline/test.json @@ -0,0 +1,4 @@ +{ + "description": "stage a file and commit the change with a multiline commit message", + "speed": 15 +} From d0805616e410bdf37f42737782cdc309ef1dd17a Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Wed, 23 Feb 2022 18:48:50 +1100 Subject: [PATCH 078/385] move function --- pkg/gui/confirmation_panel.go | 14 ++++++++++++++ pkg/gui/credentials_panel.go | 15 --------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index 15e5a8f45..f1eff4849 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -295,3 +295,17 @@ func (gui *Gui) refreshSuggestions() { return func() { gui.setSuggestions(suggestions) } }) } + +func (gui *Gui) handleAskFocused() error { + keybindingConfig := gui.c.UserConfig.Keybinding + + message := utils.ResolvePlaceholderString( + gui.c.Tr.CloseConfirm, + map[string]string{ + "keyBindClose": gui.getKeyDisplay(keybindingConfig.Universal.Return), + "keyBindConfirm": gui.getKeyDisplay(keybindingConfig.Universal.Confirm), + }, + ) + + return gui.renderString(gui.Views.Options, message) +} diff --git a/pkg/gui/credentials_panel.go b/pkg/gui/credentials_panel.go index 1277ac8ef..ba654e0eb 100644 --- a/pkg/gui/credentials_panel.go +++ b/pkg/gui/credentials_panel.go @@ -5,7 +5,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/jesseduffield/lazygit/pkg/utils" ) type credentials chan string @@ -56,17 +55,3 @@ func (gui *Gui) handleCloseCredentialsView() error { gui.credentials <- "" return gui.c.PopContext() } - -func (gui *Gui) handleAskFocused() error { - keybindingConfig := gui.c.UserConfig.Keybinding - - message := utils.ResolvePlaceholderString( - gui.c.Tr.CloseConfirm, - map[string]string{ - "keyBindClose": gui.getKeyDisplay(keybindingConfig.Universal.Return), - "keyBindConfirm": gui.getKeyDisplay(keybindingConfig.Universal.Confirm), - }, - ) - - return gui.renderString(gui.Views.Options, message) -} From 46e9946854086f170ec01f12daf075e197e420f7 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Wed, 23 Feb 2022 19:44:48 +1100 Subject: [PATCH 079/385] refactor credential handling --- pkg/cheatsheet/generate.go | 1 - pkg/gui/confirmation_panel.go | 21 ++++++ pkg/gui/context/context.go | 4 -- pkg/gui/context_config.go | 12 ---- .../controllers/helpers/credentials_helper.go | 68 +++++++++++++++++++ pkg/gui/credentials_panel.go | 57 ---------------- pkg/gui/gui.go | 33 ++++----- pkg/gui/gui_common.go | 4 ++ pkg/gui/keybindings.go | 12 ---- pkg/gui/layout.go | 1 - pkg/gui/popup/popup_handler.go | 2 + pkg/gui/types/common.go | 9 +++ pkg/gui/view_helpers.go | 2 +- pkg/i18n/chinese.go | 1 - pkg/i18n/dutch.go | 1 - pkg/i18n/english.go | 2 - 16 files changed, 118 insertions(+), 112 deletions(-) create mode 100644 pkg/gui/controllers/helpers/credentials_helper.go delete mode 100644 pkg/gui/credentials_panel.go diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index 47de22a40..804cb6b45 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -87,7 +87,6 @@ func localisedTitle(mApp *app.App, str string) string { "commitMessage": tr.CommitMessageTitle, "commits": tr.CommitsTitle, "confirmation": tr.ConfirmationTitle, - "credentials": tr.CredentialsTitle, "information": tr.InformationTitle, "main": tr.MainTitle, "patchBuilding": tr.PatchBuildingTitle, diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index f1eff4849..0a61c50b5 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -120,6 +120,7 @@ func (gui *Gui) prepareConfirmationPanel( hasLoader bool, findSuggestionsFunc func(string) []*types.Suggestion, editable bool, + mask bool, ) error { x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(true, prompt) // calling SetView on an existing view returns the same view, so I'm not bothering @@ -136,6 +137,7 @@ func (gui *Gui) prepareConfirmationPanel( // for now we do not support wrapping in our editor gui.Views.Confirmation.Wrap = !editable gui.Views.Confirmation.FgColor = theme.GocuiDefaultTextColor + gui.Views.Confirmation.Mask = runeForMask(mask) gui.findSuggestions = findSuggestionsFunc if findSuggestionsFunc != nil { @@ -154,7 +156,25 @@ func (gui *Gui) prepareConfirmationPanel( return nil } +func runeForMask(mask bool) rune { + if mask { + return '*' + } + return 0 +} + func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error { + // if a popup panel already appears we must ignore this current one. This is + // not great but it prevents lost state. The proper solution is to have a stack of + // popups. We could have a queue of types.CreatePopupPanelOpts so that if you + // close a popup and there's another one in the queue we show that. + // One important popup we don't want to interrupt is the credentials popup + // or a process might get stuck waiting on user input. + if gui.currentContext().GetKey() == context.CONFIRMATION_CONTEXT_KEY { + gui.Log.Error("ignoring create popup panel because a popup panel is already open") + return nil + } + // remove any previous keybindings gui.clearConfirmationViewKeyBindings() @@ -164,6 +184,7 @@ func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error { opts.HasLoader, opts.FindSuggestionsFunc, opts.Editable, + opts.Mask, ) if err != nil { return err diff --git a/pkg/gui/context/context.go b/pkg/gui/context/context.go index f57cb507d..add336cfd 100644 --- a/pkg/gui/context/context.go +++ b/pkg/gui/context/context.go @@ -24,7 +24,6 @@ const ( MAIN_PATCH_BUILDING_CONTEXT_KEY types.ContextKey = "patchBuilding" MAIN_STAGING_CONTEXT_KEY types.ContextKey = "staging" MENU_CONTEXT_KEY types.ContextKey = "menu" - CREDENTIALS_CONTEXT_KEY types.ContextKey = "credentials" CONFIRMATION_CONTEXT_KEY types.ContextKey = "confirmation" SEARCH_CONTEXT_KEY types.ContextKey = "search" COMMIT_MESSAGE_CONTEXT_KEY types.ContextKey = "commitMessage" @@ -51,7 +50,6 @@ var AllContextKeys = []types.ContextKey{ MAIN_PATCH_BUILDING_CONTEXT_KEY, MAIN_STAGING_CONTEXT_KEY, // not focusable for secondary view MENU_CONTEXT_KEY, - CREDENTIALS_CONTEXT_KEY, CONFIRMATION_CONTEXT_KEY, SEARCH_CONTEXT_KEY, COMMIT_MESSAGE_CONTEXT_KEY, @@ -80,7 +78,6 @@ type ContextTree struct { Staging types.Context PatchBuilding types.Context Merging types.Context - Credentials types.Context Confirmation types.Context CommitMessage types.Context Search types.Context @@ -103,7 +100,6 @@ func (self *ContextTree) Flatten() []types.Context { self.Stash, self.Menu, self.Confirmation, - self.Credentials, self.CommitMessage, self.Normal, self.Staging, diff --git a/pkg/gui/context_config.go b/pkg/gui/context_config.go index 348c5b21b..bc9df8ba4 100644 --- a/pkg/gui/context_config.go +++ b/pkg/gui/context_config.go @@ -114,18 +114,6 @@ func (gui *Gui) contextTree() *context.ContextTree { OnFocus: OnFocusWrapper(func() error { return gui.renderConflictsWithLock(true) }), }, ), - Credentials: context.NewSimpleContext( - context.NewBaseContext(context.NewBaseContextOpts{ - Kind: types.PERSISTENT_POPUP, - ViewName: "credentials", - WindowName: "credentials", - Key: context.CREDENTIALS_CONTEXT_KEY, - Focusable: true, - }), - context.ContextCallbackOpts{ - OnFocus: OnFocusWrapper(gui.handleAskFocused), - }, - ), Confirmation: context.NewSimpleContext( context.NewBaseContext(context.NewBaseContextOpts{ Kind: types.TEMPORARY_POPUP, diff --git a/pkg/gui/controllers/helpers/credentials_helper.go b/pkg/gui/controllers/helpers/credentials_helper.go new file mode 100644 index 000000000..9da3a46a2 --- /dev/null +++ b/pkg/gui/controllers/helpers/credentials_helper.go @@ -0,0 +1,68 @@ +package helpers + +import ( + "sync" + + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type CredentialsHelper struct { + c *types.HelperCommon +} + +func NewCredentialsHelper( + c *types.HelperCommon, +) *CredentialsHelper { + return &CredentialsHelper{ + c: c, + } +} + +// promptUserForCredential wait for a username, password or passphrase input from the credentials popup +func (self *CredentialsHelper) PromptUserForCredential(passOrUname oscommands.CredentialType) string { + waitGroup := sync.WaitGroup{} + waitGroup.Add(1) + + userInput := "" + + self.c.OnUIThread(func() error { + title, mask := self.getTitleAndMask(passOrUname) + + return self.c.Prompt(types.PromptOpts{ + Title: title, + Mask: mask, + HandleConfirm: func(input string) error { + userInput = input + + waitGroup.Done() + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) + }, + HandleClose: func() error { + waitGroup.Done() + + return nil + }, + }) + }) + + // wait for username/passwords/passphrase input + waitGroup.Wait() + + return userInput + "\n" +} + +func (self *CredentialsHelper) getTitleAndMask(passOrUname oscommands.CredentialType) (string, bool) { + switch passOrUname { + case oscommands.Username: + return self.c.Tr.CredentialsUsername, false + case oscommands.Password: + return self.c.Tr.CredentialsPassword, true + case oscommands.Passphrase: + return self.c.Tr.CredentialsPassphrase, true + } + + // should never land here + panic("unexpected credential request") +} diff --git a/pkg/gui/credentials_panel.go b/pkg/gui/credentials_panel.go deleted file mode 100644 index ba654e0eb..000000000 --- a/pkg/gui/credentials_panel.go +++ /dev/null @@ -1,57 +0,0 @@ -package gui - -import ( - "strings" - - "github.com/jesseduffield/lazygit/pkg/commands/oscommands" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - -type credentials chan string - -// promptUserForCredential wait for a username, password or passphrase input from the credentials popup -func (gui *Gui) promptUserForCredential(passOrUname oscommands.CredentialType) string { - gui.credentials = make(chan string) - gui.OnUIThread(func() error { - credentialsView := gui.Views.Credentials - switch passOrUname { - case oscommands.Username: - credentialsView.Title = gui.c.Tr.CredentialsUsername - credentialsView.Mask = 0 - case oscommands.Password: - credentialsView.Title = gui.c.Tr.CredentialsPassword - credentialsView.Mask = '*' - case oscommands.Passphrase: - credentialsView.Title = gui.c.Tr.CredentialsPassphrase - credentialsView.Mask = '*' - } - - if err := gui.c.PushContext(gui.State.Contexts.Credentials); err != nil { - return err - } - - return nil - }) - - // wait for username/passwords/passphrase input - userInput := <-gui.credentials - return userInput + "\n" -} - -func (gui *Gui) handleSubmitCredential() error { - credentialsView := gui.Views.Credentials - message := strings.TrimSpace(credentialsView.TextArea.GetContent()) - gui.credentials <- message - credentialsView.ClearTextArea() - if err := gui.c.PopContext(); err != nil { - return err - } - - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) -} - -func (gui *Gui) handleCloseCredentialsView() error { - gui.Views.Credentials.ClearTextArea() - gui.credentials <- "" - return gui.c.PopContext() -} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 511406e77..061c6e7ec 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -86,7 +86,6 @@ type Gui struct { Config config.AppConfigurer Updater *updates.Updater statusManager *statusManager - credentials credentials waitForIntro sync.WaitGroup fileWatcher *fileWatcher viewBufferManagerMap map[string]*tasks.ViewBufferManager @@ -247,7 +246,6 @@ type Views struct { Options *gocui.View Confirmation *gocui.View Menu *gocui.View - Credentials *gocui.View CommitMessage *gocui.View CommitFiles *gocui.View Information *gocui.View @@ -403,7 +401,6 @@ func initialViewContextMapping(contextTree *context.ContextTree) map[string]type "stash": contextTree.Stash, "menu": contextTree.Menu, "confirmation": contextTree.Confirmation, - "credentials": contextTree.Credentials, "commitMessage": contextTree.CommitMessage, "main": contextTree.Normal, "secondary": contextTree.Normal, @@ -448,17 +445,6 @@ func NewGui( InitialDir: initialDir, } - guiIO := oscommands.NewGuiIO( - cmn.Log, - gui.LogCommand, - gui.getCmdWriter, - gui.promptUserForCredential, - ) - - osCommand := oscommands.NewOSCommand(cmn, oscommands.GetPlatform(), guiIO) - - gui.os = osCommand - gui.watchFilesForChanges() gui.PopupHandler = popup.NewPopupHandler( @@ -475,6 +461,19 @@ func NewGui( guiCommon := &guiCommon{gui: gui, IPopupHandler: gui.PopupHandler} helperCommon := &types.HelperCommon{IGuiCommon: guiCommon, Common: cmn} + credentialsHelper := helpers.NewCredentialsHelper(helperCommon) + + guiIO := oscommands.NewGuiIO( + cmn.Log, + gui.LogCommand, + gui.getCmdWriter, + credentialsHelper.PromptUserForCredential, + ) + + osCommand := oscommands.NewOSCommand(cmn, oscommands.GetPlatform(), guiIO) + + gui.os = osCommand + // storing this stuff on the gui for now to ease refactoring // TODO: reset these controllers upon changing repos due to state changing gui.c = helperCommon @@ -751,7 +750,6 @@ func (gui *Gui) createAllViews() error { {viewPtr: &gui.Views.Search, name: "search"}, {viewPtr: &gui.Views.SearchPrefix, name: "searchPrefix"}, {viewPtr: &gui.Views.CommitMessage, name: "commitMessage"}, - {viewPtr: &gui.Views.Credentials, name: "credentials"}, {viewPtr: &gui.Views.Menu, name: "menu"}, {viewPtr: &gui.Views.Suggestions, name: "suggestions"}, {viewPtr: &gui.Views.Confirmation, name: "confirmation"}, @@ -825,11 +823,6 @@ func (gui *Gui) createAllViews() error { gui.Views.Confirmation.Visible = false - gui.Views.Credentials.Visible = false - gui.Views.Credentials.Title = gui.c.Tr.CredentialsUsername - gui.Views.Credentials.FgColor = theme.GocuiDefaultTextColor - gui.Views.Credentials.Editable = true - gui.Views.Suggestions.Visible = false gui.Views.Menu.Visible = false diff --git a/pkg/gui/gui_common.go b/pkg/gui/gui_common.go index 2f44ebbce..7d8354bf6 100644 --- a/pkg/gui/gui_common.go +++ b/pkg/gui/gui_common.go @@ -65,3 +65,7 @@ func (self *guiCommon) Render() { func (self *guiCommon) OpenSearch() { _ = self.gui.handleOpenSearch(self.gui.currentViewName()) } + +func (self *guiCommon) OnUIThread(f func() error) { + self.gui.OnUIThread(f) +} diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 19eb86baf..7401f3416 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -430,18 +430,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Handler: self.handleCopySelectedSideContextItemToClipboard, Description: self.c.Tr.LcCopyCommitShaToClipboard, }, - { - ViewName: "credentials", - Key: opts.GetKey(opts.Config.Universal.Confirm), - Modifier: gocui.ModNone, - Handler: self.handleSubmitCredential, - }, - { - ViewName: "credentials", - Key: opts.GetKey(opts.Config.Universal.Return), - Modifier: gocui.ModNone, - Handler: self.handleCloseCredentialsView, - }, { ViewName: "menu", Key: opts.GetKey(opts.Config.Universal.Return), diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index 097625f4c..350549311 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -224,7 +224,6 @@ func (gui *Gui) onInitialViewsCreation() error { gui.Views.Menu, gui.Views.Suggestions, gui.Views.Confirmation, - gui.Views.Credentials, // this guy will cover everything else when it appears gui.Views.Limit, diff --git a/pkg/gui/popup/popup_handler.go b/pkg/gui/popup/popup_handler.go index 20a7c8d80..c3681fbe6 100644 --- a/pkg/gui/popup/popup_handler.go +++ b/pkg/gui/popup/popup_handler.go @@ -109,7 +109,9 @@ func (self *RealPopupHandler) Prompt(opts types.PromptOpts) error { Prompt: opts.InitialContent, Editable: true, HandleConfirmPrompt: opts.HandleConfirm, + HandleClose: opts.HandleClose, FindSuggestionsFunc: opts.FindSuggestionsFunc, + Mask: opts.Mask, }) } diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 650aa51eb..cb39c87b5 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -40,6 +40,11 @@ type IGuiCommon interface { GetAppState() *config.AppState SaveAppState() error + + // Runs the given function on the UI thread (this is for things like showing a popup asking a user for input). + // Only necessary to call if you're not already on the UI thread i.e. you're inside a goroutine. + // All controller handlers are executed on the UI thread. + OnUIThread(f func() error) } type IPopupHandler interface { @@ -73,6 +78,7 @@ type CreatePopupPanelOpts struct { HandlersManageFocus bool FindSuggestionsFunc func(string) []*Suggestion + Mask bool } type AskOpts struct { @@ -88,6 +94,9 @@ type PromptOpts struct { InitialContent string FindSuggestionsFunc func(string) []*Suggestion HandleConfirm func(string) error + // CAPTURE THIS + HandleClose func() error + Mask bool } type MenuItem struct { diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index 234be7a4c..496b99e7f 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -80,7 +80,7 @@ func (gui *Gui) globalOptionsMap() map[string]string { } func (gui *Gui) isPopupPanel(viewName string) bool { - return viewName == "commitMessage" || viewName == "credentials" || viewName == "confirmation" || viewName == "menu" + return viewName == "commitMessage" || viewName == "confirmation" || viewName == "menu" } func (gui *Gui) popupPanelFocused() bool { diff --git a/pkg/i18n/chinese.go b/pkg/i18n/chinese.go index 551f55750..9fa455d73 100644 --- a/pkg/i18n/chinese.go +++ b/pkg/i18n/chinese.go @@ -191,7 +191,6 @@ func chineseTranslationSet() TranslationSet { TagsTitle: "鏍囩椤甸潰", MenuTitle: "鑿滃崟", RemotesTitle: "杩滅▼椤甸潰", - CredentialsTitle: "璇佷功", RemoteBranchesTitle: "杩滅▼鍒嗘敮锛堝湪杩滅▼椤甸潰涓級", PatchBuildingTitle: "鏋勫缓琛ヤ竵涓", InformationTitle: "淇℃伅", diff --git a/pkg/i18n/dutch.go b/pkg/i18n/dutch.go index 147cf3c6e..c77321ae2 100644 --- a/pkg/i18n/dutch.go +++ b/pkg/i18n/dutch.go @@ -161,7 +161,6 @@ func dutchTranslationSet() TranslationSet { TagsTitle: "Tags Tabblad", MenuTitle: "Menu", RemotesTitle: "Remotes Tabblad", - CredentialsTitle: "Credentials", RemoteBranchesTitle: "Remote Branches (in Remotes tabblad)", PatchBuildingTitle: "Patch Bouwen", InformationTitle: "Informatie", diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 649b04fd9..aba4e9368 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -177,7 +177,6 @@ type TranslationSet struct { TagsTitle string MenuTitle string RemotesTitle string - CredentialsTitle string RemoteBranchesTitle string PatchBuildingTitle string InformationTitle string @@ -748,7 +747,6 @@ func EnglishTranslationSet() TranslationSet { TagsTitle: "Tags Tab", MenuTitle: "Menu", RemotesTitle: "Remotes Tab", - CredentialsTitle: "Credentials", RemoteBranchesTitle: "Remote Branches (in Remotes tab)", PatchBuildingTitle: "Patch Building", InformationTitle: "Information", From 952a4f3f2388da4ab88005b02f264aca0172afe7 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Wed, 23 Feb 2022 20:02:40 +1100 Subject: [PATCH 080/385] prevent interrupting confirmation panel --- pkg/gui/confirmation_panel.go | 21 ++++++++++++++------- pkg/gui/gui.go | 11 +++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index 0a61c50b5..a7050aba0 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -44,6 +44,10 @@ func (gui *Gui) wrappedPromptConfirmationFunction(handlersManageFocus bool, func } func (gui *Gui) closeConfirmationPrompt(handlersManageFocus bool) error { + gui.Mutexes.PopupMutex.Lock() + gui.State.CurrentPopupOpts = nil + gui.Mutexes.PopupMutex.Unlock() + // we've already closed it so we can just return if !gui.Views.Confirmation.Visible { return nil @@ -164,13 +168,14 @@ func runeForMask(mask bool) rune { } func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error { - // if a popup panel already appears we must ignore this current one. This is - // not great but it prevents lost state. The proper solution is to have a stack of - // popups. We could have a queue of types.CreatePopupPanelOpts so that if you - // close a popup and there's another one in the queue we show that. - // One important popup we don't want to interrupt is the credentials popup - // or a process might get stuck waiting on user input. - if gui.currentContext().GetKey() == context.CONFIRMATION_CONTEXT_KEY { + gui.Mutexes.PopupMutex.Lock() + defer gui.Mutexes.PopupMutex.Unlock() + + // we don't allow interruptions of non-loader popups in case we get stuck somehow + // e.g. a credentials popup never gets its required user input so a process hangs + // forever. + // The proper solution is to have a queue of popup options + if gui.State.CurrentPopupOpts != nil && !gui.State.CurrentPopupOpts.HasLoader { gui.Log.Error("ignoring create popup panel because a popup panel is already open") return nil } @@ -208,6 +213,8 @@ func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error { return err } + gui.State.CurrentPopupOpts = &opts + return gui.c.PushContext(gui.State.Contexts.Confirmation) } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 061c6e7ec..6b371699a 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -197,6 +197,8 @@ type GuiRepoState struct { savedCommitMessage string ScreenMode WindowMaximisation + + CurrentPopupOpts *types.CreatePopupPanelOpts } type Controllers struct { @@ -280,6 +282,7 @@ type guiMutexes struct { LocalCommitsMutex *sync.Mutex LineByLinePanelMutex *sync.Mutex SubprocessMutex *sync.Mutex + PopupMutex *sync.Mutex } func (gui *Gui) onNewRepo(filterPath string, reuseState bool) error { @@ -322,6 +325,13 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { if state := gui.RepoStateMap[Repo(currentDir)]; state != nil { gui.State = state gui.State.ViewsSetup = false + + // setting this to nil so we don't get stuck based on a popup that was + // previously opened + gui.Mutexes.PopupMutex.Lock() + gui.State.CurrentPopupOpts = nil + gui.Mutexes.PopupMutex.Unlock() + gui.syncViewContexts() return } @@ -441,6 +451,7 @@ func NewGui( LocalCommitsMutex: &sync.Mutex{}, LineByLinePanelMutex: &sync.Mutex{}, SubprocessMutex: &sync.Mutex{}, + PopupMutex: &sync.Mutex{}, }, InitialDir: initialDir, } From ef7c4c9ca93ec15db4886d8d6f78c85a1db7edef Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Thu, 24 Feb 2022 13:29:48 +1100 Subject: [PATCH 081/385] refactor custom commands more custom command refactoring --- pkg/gui/custom_commands.go | 371 ------------------ .../filetree/commit_file_tree_view_model.go | 18 + pkg/gui/filetree/file_tree_view_model.go | 18 + pkg/gui/gui.go | 35 +- pkg/gui/keybindings.go | 6 +- pkg/gui/options_menu_panel.go | 7 +- pkg/gui/services/custom_commands/client.go | 52 +++ .../custom_commands/handler_creator.go | 187 +++++++++ .../custom_commands/keybinding_creator.go | 91 +++++ .../custom_commands/menu_generator.go | 138 +++++++ .../custom_commands/menu_generator_test.go} | 15 +- pkg/gui/services/custom_commands/resolver.go | 98 +++++ .../custom_commands/session_state_loader.go | 56 +++ 13 files changed, 701 insertions(+), 391 deletions(-) delete mode 100644 pkg/gui/custom_commands.go create mode 100644 pkg/gui/services/custom_commands/client.go create mode 100644 pkg/gui/services/custom_commands/handler_creator.go create mode 100644 pkg/gui/services/custom_commands/keybinding_creator.go create mode 100644 pkg/gui/services/custom_commands/menu_generator.go rename pkg/gui/{custom_commands_test.go => services/custom_commands/menu_generator_test.go} (75%) create mode 100644 pkg/gui/services/custom_commands/resolver.go create mode 100644 pkg/gui/services/custom_commands/session_state_loader.go diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go deleted file mode 100644 index b4c977f3b..000000000 --- a/pkg/gui/custom_commands.go +++ /dev/null @@ -1,371 +0,0 @@ -package gui - -import ( - "bytes" - "errors" - "log" - "regexp" - "strconv" - "strings" - "text/template" - - "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/config" - "github.com/jesseduffield/lazygit/pkg/gui/context" - "github.com/jesseduffield/lazygit/pkg/gui/style" - "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/jesseduffield/lazygit/pkg/utils" -) - -type CustomCommandObjects struct { - SelectedLocalCommit *models.Commit - SelectedReflogCommit *models.Commit - SelectedSubCommit *models.Commit - SelectedFile *models.File - SelectedPath string - SelectedLocalBranch *models.Branch - SelectedRemoteBranch *models.RemoteBranch - SelectedRemote *models.Remote - SelectedTag *models.Tag - SelectedStashEntry *models.StashEntry - SelectedCommitFile *models.CommitFile - SelectedCommitFilePath string - CheckedOutBranch *models.Branch - PromptResponses []string -} - -type commandMenuEntry struct { - label string - value string -} - -func (gui *Gui) getResolveTemplateFn(promptResponses []string) func(string) (string, error) { - objects := CustomCommandObjects{ - SelectedFile: gui.getSelectedFile(), - SelectedPath: gui.getSelectedPath(), - SelectedLocalCommit: gui.State.Contexts.LocalCommits.GetSelected(), - SelectedReflogCommit: gui.State.Contexts.ReflogCommits.GetSelected(), - SelectedLocalBranch: gui.State.Contexts.Branches.GetSelected(), - SelectedRemoteBranch: gui.State.Contexts.RemoteBranches.GetSelected(), - SelectedRemote: gui.State.Contexts.Remotes.GetSelected(), - SelectedTag: gui.State.Contexts.Tags.GetSelected(), - SelectedStashEntry: gui.State.Contexts.Stash.GetSelected(), - SelectedCommitFile: gui.getSelectedCommitFile(), - SelectedCommitFilePath: gui.getSelectedCommitFilePath(), - SelectedSubCommit: gui.State.Contexts.SubCommits.GetSelected(), - CheckedOutBranch: gui.helpers.Refs.GetCheckedOutRef(), - PromptResponses: promptResponses, - } - - return func(templateStr string) (string, error) { return utils.ResolveTemplate(templateStr, objects) } -} - -func resolveCustomCommandPrompt(prompt *config.CustomCommandPrompt, resolveTemplate func(string) (string, error)) (*config.CustomCommandPrompt, error) { - var err error - result := &config.CustomCommandPrompt{} - - result.Title, err = resolveTemplate(prompt.Title) - if err != nil { - return nil, err - } - - result.InitialValue, err = resolveTemplate(prompt.InitialValue) - if err != nil { - return nil, err - } - - result.Command, err = resolveTemplate(prompt.Command) - if err != nil { - return nil, err - } - - result.Filter, err = resolveTemplate(prompt.Filter) - if err != nil { - return nil, err - } - - if len(prompt.Options) > 0 { - newOptions := make([]config.CustomCommandMenuOption, len(prompt.Options)) - for _, option := range prompt.Options { - option := option - newOption, err := resolveMenuOption(&option, resolveTemplate) - if err != nil { - return nil, err - } - newOptions = append(newOptions, *newOption) - } - prompt.Options = newOptions - } - - return result, nil -} - -func resolveMenuOption(option *config.CustomCommandMenuOption, resolveTemplate func(string) (string, error)) (*config.CustomCommandMenuOption, error) { - nameTemplate := option.Name - if nameTemplate == "" { - // this allows you to only pass values rather than bother with names/descriptions - nameTemplate = option.Value - } - - name, err := resolveTemplate(nameTemplate) - if err != nil { - return nil, err - } - - description, err := resolveTemplate(option.Description) - if err != nil { - return nil, err - } - - value, err := resolveTemplate(option.Value) - if err != nil { - return nil, err - } - - return &config.CustomCommandMenuOption{ - Name: name, - Description: description, - Value: value, - }, nil -} - -func (gui *Gui) inputPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error { - return gui.c.Prompt(types.PromptOpts{ - Title: prompt.Title, - InitialContent: prompt.InitialValue, - HandleConfirm: func(str string) error { - return wrappedF(str) - }, - }) -} - -func (gui *Gui) menuPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error { - menuItems := make([]*types.MenuItem, len(prompt.Options)) - for i, option := range prompt.Options { - option := option - menuItems[i] = &types.MenuItem{ - DisplayStrings: []string{option.Name, style.FgYellow.Sprint(option.Description)}, - OnPress: func() error { - return wrappedF(option.Value) - }, - } - } - - return gui.c.Menu(types.CreateMenuOptions{Title: prompt.Title, Items: menuItems}) -} - -func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, labelFormat string) ([]commandMenuEntry, error) { - reg, err := regexp.Compile(filter) - if err != nil { - return nil, gui.c.Error(errors.New("unable to parse filter regex, error: " + err.Error())) - } - - buff := bytes.NewBuffer(nil) - - valueTemp, err := template.New("format").Parse(valueFormat) - if err != nil { - return nil, gui.c.Error(errors.New("unable to parse value format, error: " + err.Error())) - } - - colorFuncMap := style.TemplateFuncMapAddColors(template.FuncMap{}) - - descTemp, err := template.New("format").Funcs(colorFuncMap).Parse(labelFormat) - if err != nil { - return nil, gui.c.Error(errors.New("unable to parse label format, error: " + err.Error())) - } - - candidates := []commandMenuEntry{} - for _, str := range strings.Split(commandOutput, "\n") { - if str == "" { - continue - } - - tmplData := map[string]string{} - out := reg.FindAllStringSubmatch(str, -1) - if len(out) > 0 { - for groupIdx, group := range reg.SubexpNames() { - // Record matched group with group ids - matchName := "group_" + strconv.Itoa(groupIdx) - tmplData[matchName] = out[0][groupIdx] - // Record last named group non-empty matches as group matches - if group != "" { - tmplData[group] = out[0][groupIdx] - } - } - } - - err = valueTemp.Execute(buff, tmplData) - if err != nil { - return candidates, gui.c.Error(err) - } - entry := commandMenuEntry{ - value: strings.TrimSpace(buff.String()), - } - - if labelFormat != "" { - buff.Reset() - err = descTemp.Execute(buff, tmplData) - if err != nil { - return candidates, gui.c.Error(err) - } - entry.label = strings.TrimSpace(buff.String()) - } else { - entry.label = entry.value - } - - candidates = append(candidates, entry) - - buff.Reset() - } - return candidates, err -} - -func (gui *Gui) menuPromptFromCommand(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error { - // Run and save output - message, err := gui.git.Custom.RunWithOutput(prompt.Command) - if err != nil { - return gui.c.Error(err) - } - - // Need to make a menu out of what the cmd has displayed - candidates, err := gui.GenerateMenuCandidates(message, prompt.Filter, prompt.ValueFormat, prompt.LabelFormat) - if err != nil { - return gui.c.Error(err) - } - - menuItems := make([]*types.MenuItem, len(candidates)) - for i := range candidates { - i := i - menuItems[i] = &types.MenuItem{ - DisplayStrings: []string{candidates[i].label}, - OnPress: func() error { - return wrappedF(candidates[i].value) - }, - } - } - - return gui.c.Menu(types.CreateMenuOptions{Title: prompt.Title, Items: menuItems}) -} - -func (gui *Gui) handleCustomCommandKeybinding(customCommand config.CustomCommand) func() error { - return func() error { - promptResponses := make([]string, len(customCommand.Prompts)) - - f := func() error { - resolveTemplate := gui.getResolveTemplateFn(promptResponses) - cmdStr, err := resolveTemplate(customCommand.Command) - if err != nil { - return gui.c.Error(err) - } - - if customCommand.Subprocess { - return gui.runSubprocessWithSuspenseAndRefresh(gui.os.Cmd.NewShell(cmdStr)) - } - - loadingText := customCommand.LoadingText - if loadingText == "" { - loadingText = gui.c.Tr.LcRunningCustomCommandStatus - } - - return gui.c.WithWaitingStatus(loadingText, func() error { - gui.c.LogAction(gui.c.Tr.Actions.CustomCommand) - cmdObj := gui.os.Cmd.NewShell(cmdStr) - if customCommand.Stream { - cmdObj.StreamOutput() - } - err := cmdObj.Run() - if err != nil { - return gui.c.Error(err) - } - return gui.c.Refresh(types.RefreshOptions{}) - }) - } - - // if we have prompts we'll recursively wrap our confirm handlers with more prompts - // until we reach the actual command - for reverseIdx := range customCommand.Prompts { - idx := len(customCommand.Prompts) - 1 - reverseIdx - - // going backwards so the outermost prompt is the first one - prompt := customCommand.Prompts[idx] - - wrappedF := func(response string) error { - promptResponses[idx] = response - return f() - } - - resolveTemplate := gui.getResolveTemplateFn(promptResponses) - resolvedPrompt, err := resolveCustomCommandPrompt(&prompt, resolveTemplate) - if err != nil { - return gui.c.Error(err) - } - - switch prompt.Type { - case "input": - f = func() error { - return gui.inputPrompt(resolvedPrompt, wrappedF) - } - case "menu": - f = func() error { - return gui.menuPrompt(resolvedPrompt, wrappedF) - } - case "menuFromCommand": - f = func() error { - return gui.menuPromptFromCommand(resolvedPrompt, wrappedF) - } - default: - return gui.c.ErrorMsg("custom command prompt must have a type of 'input', 'menu' or 'menuFromCommand'") - } - } - - return f() - } -} - -func (gui *Gui) GetCustomCommandKeybindings() []*types.Binding { - bindings := []*types.Binding{} - customCommands := gui.c.UserConfig.CustomCommands - - for _, customCommand := range customCommands { - var viewName string - var contexts []string - switch customCommand.Context { - case "global": - viewName = "" - case "": - log.Fatalf("Error parsing custom command keybindings: context not provided (use context: 'global' for the global context). Key: %s, Command: %s", customCommand.Key, customCommand.Command) - default: - ctx, ok := gui.contextForContextKey(types.ContextKey(customCommand.Context)) - // stupid golang making me build an array of strings for this. - allContextKeyStrings := make([]string, len(context.AllContextKeys)) - for i := range context.AllContextKeys { - allContextKeyStrings[i] = string(context.AllContextKeys[i]) - } - if !ok { - log.Fatalf("Error when setting custom command keybindings: unknown context: %s. Key: %s, Command: %s.\nPermitted contexts: %s", customCommand.Context, customCommand.Key, customCommand.Command, strings.Join(allContextKeyStrings, ", ")) - } - // here we assume that a given context will always belong to the same view. - // Currently this is a safe bet but it's by no means guaranteed in the long term - // and we might need to make some changes in the future to support it. - viewName = ctx.GetViewName() - contexts = []string{customCommand.Context} - } - - description := customCommand.Description - if description == "" { - description = customCommand.Command - } - - bindings = append(bindings, &types.Binding{ - ViewName: viewName, - Contexts: contexts, - Key: gui.getKey(customCommand.Key), - Modifier: gocui.ModNone, - Handler: gui.handleCustomCommandKeybinding(customCommand), - Description: description, - }) - } - - return bindings -} diff --git a/pkg/gui/filetree/commit_file_tree_view_model.go b/pkg/gui/filetree/commit_file_tree_view_model.go index 86e7e864e..e80003d28 100644 --- a/pkg/gui/filetree/commit_file_tree_view_model.go +++ b/pkg/gui/filetree/commit_file_tree_view_model.go @@ -69,6 +69,24 @@ func (self *CommitFileTreeViewModel) GetSelectedFileNode() *CommitFileNode { return self.GetItemAtIndex(self.GetSelectedLineIdx()) } +func (self *CommitFileTreeViewModel) GetSelectedFile() *models.CommitFile { + node := self.GetSelectedFileNode() + if node == nil { + return nil + } + + return node.File +} + +func (self *CommitFileTreeViewModel) GetSelectedPath() string { + node := self.GetSelectedFileNode() + if node == nil { + return "" + } + + return node.GetPath() +} + // duplicated from file_tree_view_model.go. Generics will help here func (self *CommitFileTreeViewModel) ToggleShowTree() { selectedNode := self.GetSelectedFileNode() diff --git a/pkg/gui/filetree/file_tree_view_model.go b/pkg/gui/filetree/file_tree_view_model.go index 814d6eaac..9adb04cf1 100644 --- a/pkg/gui/filetree/file_tree_view_model.go +++ b/pkg/gui/filetree/file_tree_view_model.go @@ -43,6 +43,24 @@ func (self *FileTreeViewModel) GetSelectedFileNode() *FileNode { return self.GetItemAtIndex(self.GetSelectedLineIdx()) } +func (self *FileTreeViewModel) GetSelectedFile() *models.File { + node := self.GetSelectedFileNode() + if node == nil { + return nil + } + + return node.File +} + +func (self *FileTreeViewModel) GetSelectedPath() string { + node := self.GetSelectedFileNode() + if node == nil { + return "" + } + + return node.GetPath() +} + func (self *FileTreeViewModel) SetTree() { newFiles := self.GetAllFiles() selectedNode := self.GetSelectedFileNode() diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 6b371699a..edcabba7f 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -30,6 +30,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/presentation/authors" "github.com/jesseduffield/lazygit/pkg/gui/presentation/graph" + "github.com/jesseduffield/lazygit/pkg/gui/services/custom_commands" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/tasks" @@ -80,6 +81,8 @@ type Gui struct { // this is the state of the GUI for the current repo State *GuiRepoState + CustomCommandsClient *custom_commands.Client + // this is a mapping of repos to gui states, so that we can restore the original // gui state when returning from a subrepo RepoStateMap map[Repo]*GuiRepoState @@ -496,28 +499,29 @@ func NewGui( } func (gui *Gui) resetControllers() { - controllerCommon := gui.c + helperCommon := gui.c osCommand := gui.os model := gui.State.Model refsHelper := helpers.NewRefsHelper( - controllerCommon, + helperCommon, gui.git, gui.State.Contexts, model, ) - rebaseHelper := helpers.NewMergeAndRebaseHelper(controllerCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling, refsHelper) + + rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling, refsHelper) gui.helpers = &helpers.Helpers{ Refs: refsHelper, - PatchBuilding: helpers.NewPatchBuildingHelper(controllerCommon, gui.git), - Bisect: helpers.NewBisectHelper(controllerCommon, gui.git), - Suggestions: helpers.NewSuggestionsHelper(controllerCommon, model, gui.refreshSuggestions), - Files: helpers.NewFilesHelper(controllerCommon, gui.git, osCommand), + PatchBuilding: helpers.NewPatchBuildingHelper(helperCommon, gui.git), + Bisect: helpers.NewBisectHelper(helperCommon, gui.git), + Suggestions: helpers.NewSuggestionsHelper(helperCommon, model, gui.refreshSuggestions), + Files: helpers.NewFilesHelper(helperCommon, gui.git, osCommand), WorkingTree: helpers.NewWorkingTreeHelper(model), - Tags: helpers.NewTagsHelper(controllerCommon, gui.git), - GPG: helpers.NewGpgHelper(controllerCommon, gui.os, gui.git), + Tags: helpers.NewTagsHelper(helperCommon, gui.git), + GPG: helpers.NewGpgHelper(helperCommon, gui.os, gui.git), MergeAndRebase: rebaseHelper, CherryPick: helpers.NewCherryPickHelper( - controllerCommon, + helperCommon, gui.git, gui.State.Contexts, func() *cherrypicking.CherryPicking { return gui.State.Modes.CherryPicking }, @@ -525,8 +529,17 @@ func (gui *Gui) resetControllers() { ), } + gui.CustomCommandsClient = custom_commands.NewClient( + helperCommon, + gui.os, + gui.git, + gui.State.Contexts, + gui.helpers, + gui.getKey, + ) + common := controllers.NewControllerCommon( - controllerCommon, + helperCommon, osCommand, gui.git, gui.helpers, diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 7401f3416..7c5e0be25 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -1116,7 +1116,11 @@ func (gui *Gui) resetKeybindings() error { bindings, mouseBindings := gui.GetInitialKeybindings() // prepending because we want to give our custom keybindings precedence over default keybindings - bindings = append(gui.GetCustomCommandKeybindings(), bindings...) + customBindings, err := gui.CustomCommandsClient.GetCustomCommandKeybindings() + if err != nil { + log.Fatal(err) + } + bindings = append(customBindings, bindings...) for _, binding := range bindings { if err := gui.SetKeybinding(binding); err != nil { diff --git a/pkg/gui/options_menu_panel.go b/pkg/gui/options_menu_panel.go index 3ca6ea388..17ced988e 100644 --- a/pkg/gui/options_menu_panel.go +++ b/pkg/gui/options_menu_panel.go @@ -1,6 +1,7 @@ package gui import ( + "log" "strings" "github.com/jesseduffield/lazygit/pkg/gui/presentation" @@ -15,7 +16,11 @@ func (gui *Gui) getBindings(context types.Context) []*types.Binding { ) bindings, _ := gui.GetInitialKeybindings() - bindings = append(gui.GetCustomCommandKeybindings(), bindings...) + customBindings, err := gui.CustomCommandsClient.GetCustomCommandKeybindings() + if err != nil { + log.Fatal(err) + } + bindings = append(customBindings, bindings...) for _, binding := range bindings { if GetKeyDisplay(binding.Key) != "" && binding.Description != "" { diff --git a/pkg/gui/services/custom_commands/client.go b/pkg/gui/services/custom_commands/client.go new file mode 100644 index 000000000..fc36405c1 --- /dev/null +++ b/pkg/gui/services/custom_commands/client.go @@ -0,0 +1,52 @@ +package custom_commands + +import ( + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +// Client is the entry point to this package. It reutrns a list of keybindings based on the config's user-defined custom commands. +// See https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Command_Keybindings.md for more info. +type Client struct { + customCommands []config.CustomCommand + handlerCreator *HandlerCreator + keybindingCreator *KeybindingCreator +} + +func NewClient( + c *types.HelperCommon, + os *oscommands.OSCommand, + git *commands.GitCommand, + contexts *context.ContextTree, + helpers *helpers.Helpers, + getKey func(string) interface{}, +) *Client { + sessionStateLoader := NewSessionStateLoader(contexts, helpers) + handlerCreator := NewHandlerCreator(c, os, git, sessionStateLoader) + keybindingCreator := NewKeybindingCreator(contexts, getKey) + customCommands := c.UserConfig.CustomCommands + + return &Client{ + customCommands: customCommands, + keybindingCreator: keybindingCreator, + handlerCreator: handlerCreator, + } +} + +func (self *Client) GetCustomCommandKeybindings() ([]*types.Binding, error) { + bindings := []*types.Binding{} + for _, customCommand := range self.customCommands { + handler := self.handlerCreator.call(customCommand) + binding, err := self.keybindingCreator.call(customCommand, handler) + if err != nil { + return nil, err + } + bindings = append(bindings, binding) + } + + return bindings, nil +} diff --git a/pkg/gui/services/custom_commands/handler_creator.go b/pkg/gui/services/custom_commands/handler_creator.go new file mode 100644 index 000000000..04e6cb644 --- /dev/null +++ b/pkg/gui/services/custom_commands/handler_creator.go @@ -0,0 +1,187 @@ +package custom_commands + +import ( + "github.com/jesseduffield/lazygit/pkg/commands" + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/style" + "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +// takes a custom command and returns a function that will be called when the corresponding user-defined keybinding is pressed +type HandlerCreator struct { + c *types.HelperCommon + os *oscommands.OSCommand + git *commands.GitCommand + sessionStateLoader *SessionStateLoader + resolver *Resolver + menuGenerator *MenuGenerator +} + +func NewHandlerCreator( + c *types.HelperCommon, + os *oscommands.OSCommand, + git *commands.GitCommand, + sessionStateLoader *SessionStateLoader, +) *HandlerCreator { + resolver := NewResolver(c.Common) + menuGenerator := NewMenuGenerator(c.Common) + + return &HandlerCreator{ + c: c, + os: os, + git: git, + sessionStateLoader: sessionStateLoader, + resolver: resolver, + menuGenerator: menuGenerator, + } +} + +func (self *HandlerCreator) call(customCommand config.CustomCommand) func() error { + return func() error { + sessionState := self.sessionStateLoader.call() + promptResponses := make([]string, len(customCommand.Prompts)) + + f := func() error { return self.finalHandler(customCommand, sessionState, promptResponses) } + + // if we have prompts we'll recursively wrap our confirm handlers with more prompts + // until we reach the actual command + for reverseIdx := range customCommand.Prompts { + // reassigning so that we don't end up with an infinite recursion + g := f + idx := len(customCommand.Prompts) - 1 - reverseIdx + + // going backwards so the outermost prompt is the first one + prompt := customCommand.Prompts[idx] + + wrappedF := func(response string) error { + promptResponses[idx] = response + return g() + } + + resolveTemplate := self.getResolveTemplateFn(promptResponses, sessionState) + resolvedPrompt, err := self.resolver.resolvePrompt(&prompt, resolveTemplate) + if err != nil { + return self.c.Error(err) + } + + switch prompt.Type { + case "input": + f = func() error { + return self.inputPrompt(resolvedPrompt, wrappedF) + } + case "menu": + f = func() error { + return self.menuPrompt(resolvedPrompt, wrappedF) + } + case "menuFromCommand": + f = func() error { + return self.menuPromptFromCommand(resolvedPrompt, wrappedF) + } + default: + return self.c.ErrorMsg("custom command prompt must have a type of 'input', 'menu' or 'menuFromCommand'") + } + } + + return f() + } +} + +func (self *HandlerCreator) inputPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error { + return self.c.Prompt(types.PromptOpts{ + Title: prompt.Title, + InitialContent: prompt.InitialValue, + HandleConfirm: func(str string) error { + return wrappedF(str) + }, + }) +} + +func (self *HandlerCreator) menuPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error { + menuItems := make([]*types.MenuItem, len(prompt.Options)) + for i, option := range prompt.Options { + option := option + menuItems[i] = &types.MenuItem{ + DisplayStrings: []string{option.Name, style.FgYellow.Sprint(option.Description)}, + OnPress: func() error { + return wrappedF(option.Value) + }, + } + } + + return self.c.Menu(types.CreateMenuOptions{Title: prompt.Title, Items: menuItems}) +} + +func (self *HandlerCreator) menuPromptFromCommand(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error { + // Run and save output + message, err := self.git.Custom.RunWithOutput(prompt.Command) + if err != nil { + return self.c.Error(err) + } + + // Need to make a menu out of what the cmd has displayed + candidates, err := self.menuGenerator.call(message, prompt.Filter, prompt.ValueFormat, prompt.LabelFormat) + if err != nil { + return self.c.Error(err) + } + + menuItems := make([]*types.MenuItem, len(candidates)) + for i := range candidates { + i := i + menuItems[i] = &types.MenuItem{ + DisplayStrings: []string{candidates[i].label}, + OnPress: func() error { + return wrappedF(candidates[i].value) + }, + } + } + + return self.c.Menu(types.CreateMenuOptions{Title: prompt.Title, Items: menuItems}) +} + +type CustomCommandObjects struct { + *SessionState + PromptResponses []string +} + +func (self *HandlerCreator) getResolveTemplateFn(promptResponses []string, sessionState *SessionState) func(string) (string, error) { + objects := CustomCommandObjects{ + SessionState: sessionState, + PromptResponses: promptResponses, + } + + return func(templateStr string) (string, error) { return utils.ResolveTemplate(templateStr, objects) } +} + +func (self *HandlerCreator) finalHandler(customCommand config.CustomCommand, sessionState *SessionState, promptResponses []string) error { + resolveTemplate := self.getResolveTemplateFn(promptResponses, sessionState) + cmdStr, err := resolveTemplate(customCommand.Command) + if err != nil { + return self.c.Error(err) + } + + cmdObj := self.os.Cmd.NewShell(cmdStr) + + if customCommand.Subprocess { + return self.c.RunSubprocessAndRefresh(cmdObj) + } + + loadingText := customCommand.LoadingText + if loadingText == "" { + loadingText = self.c.Tr.LcRunningCustomCommandStatus + } + + return self.c.WithWaitingStatus(loadingText, func() error { + self.c.LogAction(self.c.Tr.Actions.CustomCommand) + + if customCommand.Stream { + cmdObj.StreamOutput() + } + err := cmdObj.Run() + if err != nil { + return self.c.Error(err) + } + return self.c.Refresh(types.RefreshOptions{}) + }) +} diff --git a/pkg/gui/services/custom_commands/keybinding_creator.go b/pkg/gui/services/custom_commands/keybinding_creator.go new file mode 100644 index 000000000..e3c233951 --- /dev/null +++ b/pkg/gui/services/custom_commands/keybinding_creator.go @@ -0,0 +1,91 @@ +package custom_commands + +import ( + "fmt" + "strings" + + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/config" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +// KeybindingCreator takes a custom command along with its handler and returns a corresponding keybinding +type KeybindingCreator struct { + contexts *context.ContextTree + getKey func(string) interface{} +} + +func NewKeybindingCreator(contexts *context.ContextTree, getKey func(string) interface{}) *KeybindingCreator { + return &KeybindingCreator{ + contexts: contexts, + getKey: getKey, + } +} + +func (self *KeybindingCreator) call(customCommand config.CustomCommand, handler func() error) (*types.Binding, error) { + if customCommand.Context == "" { + return nil, formatContextNotProvidedError(customCommand) + } + + viewName, contexts, err := self.getViewNameAndContexts(customCommand) + if err != nil { + return nil, err + } + + description := customCommand.Description + if description == "" { + description = customCommand.Command + } + + return &types.Binding{ + ViewName: viewName, + Contexts: contexts, + Key: self.getKey(customCommand.Key), + Modifier: gocui.ModNone, + Handler: handler, + Description: description, + }, nil +} + +func (self *KeybindingCreator) getViewNameAndContexts(customCommand config.CustomCommand) (string, []string, error) { + if customCommand.Context == "global" { + return "", nil, nil + } + + ctx, ok := self.contextForContextKey(types.ContextKey(customCommand.Context)) + if !ok { + return "", nil, formatUnknownContextError(customCommand) + } + + // here we assume that a given context will always belong to the same view. + // Currently this is a safe bet but it's by no means guaranteed in the long term + // and we might need to make some changes in the future to support it. + viewName := ctx.GetViewName() + contexts := []string{customCommand.Context} + return viewName, contexts, nil +} + +func (self *KeybindingCreator) contextForContextKey(contextKey types.ContextKey) (types.Context, bool) { + for _, context := range self.contexts.Flatten() { + if context.GetKey() == contextKey { + return context, true + } + } + + return nil, false +} + +func formatUnknownContextError(customCommand config.CustomCommand) error { + // stupid golang making me build an array of strings for this. + allContextKeyStrings := make([]string, len(context.AllContextKeys)) + for i := range context.AllContextKeys { + allContextKeyStrings[i] = string(context.AllContextKeys[i]) + } + + return fmt.Errorf("Error when setting custom command keybindings: unknown context: %s. Key: %s, Command: %s.\nPermitted contexts: %s", customCommand.Context, customCommand.Key, customCommand.Command, strings.Join(allContextKeyStrings, ", ")) +} + +func formatContextNotProvidedError(customCommand config.CustomCommand) error { + return fmt.Errorf("Error parsing custom command keybindings: context not provided (use context: 'global' for the global context). Key: %s, Command: %s", customCommand.Key, customCommand.Command) +} diff --git a/pkg/gui/services/custom_commands/menu_generator.go b/pkg/gui/services/custom_commands/menu_generator.go new file mode 100644 index 000000000..5bec1db91 --- /dev/null +++ b/pkg/gui/services/custom_commands/menu_generator.go @@ -0,0 +1,138 @@ +package custom_commands + +import ( + "bytes" + "errors" + "regexp" + "strconv" + "strings" + "text/template" + + "github.com/jesseduffield/lazygit/pkg/common" + "github.com/jesseduffield/lazygit/pkg/gui/style" +) + +type MenuGenerator struct { + c *common.Common +} + +// takes the output of a command and returns a list of menu entries based on a filter +// and value/label format templates provided by the user +func NewMenuGenerator(c *common.Common) *MenuGenerator { + return &MenuGenerator{c: c} +} + +type commandMenuEntry struct { + label string + value string +} + +func (self *MenuGenerator) call(commandOutput, filter, valueFormat, labelFormat string) ([]*commandMenuEntry, error) { + regex, err := regexp.Compile(filter) + if err != nil { + return nil, errors.New("unable to parse filter regex, error: " + err.Error()) + } + + valueTemplateAux, err := template.New("format").Parse(valueFormat) + if err != nil { + return nil, errors.New("unable to parse value format, error: " + err.Error()) + } + valueTemplate := NewTrimmerTemplate(valueTemplateAux) + + var labelTemplate *TrimmerTemplate + if labelFormat != "" { + colorFuncMap := style.TemplateFuncMapAddColors(template.FuncMap{}) + labelTemplateAux, err := template.New("format").Funcs(colorFuncMap).Parse(labelFormat) + if err != nil { + return nil, errors.New("unable to parse label format, error: " + err.Error()) + } + labelTemplate = NewTrimmerTemplate(labelTemplateAux) + } else { + labelTemplate = valueTemplate + } + + candidates := []*commandMenuEntry{} + for _, line := range strings.Split(commandOutput, "\n") { + if line == "" { + continue + } + + candidate, err := self.generateMenuCandidate( + line, + regex, + valueTemplate, + labelTemplate, + ) + if err != nil { + return nil, err + } + + candidates = append(candidates, candidate) + } + + return candidates, err +} + +func (self *MenuGenerator) generateMenuCandidate( + line string, + regex *regexp.Regexp, + valueTemplate *TrimmerTemplate, + labelTemplate *TrimmerTemplate, +) (*commandMenuEntry, error) { + tmplData := self.parseLine(line, regex) + + entry := &commandMenuEntry{} + + var err error + entry.value, err = valueTemplate.execute(tmplData) + if err != nil { + return nil, err + } + + entry.label, err = labelTemplate.execute(tmplData) + if err != nil { + return nil, err + } + + return entry, nil +} + +func (self *MenuGenerator) parseLine(line string, regex *regexp.Regexp) map[string]string { + tmplData := map[string]string{} + out := regex.FindAllStringSubmatch(line, -1) + if len(out) > 0 { + for groupIdx, group := range regex.SubexpNames() { + // Record matched group with group ids + matchName := "group_" + strconv.Itoa(groupIdx) + tmplData[matchName] = out[0][groupIdx] + // Record last named group non-empty matches as group matches + if group != "" { + tmplData[group] = out[0][groupIdx] + } + } + } + + return tmplData +} + +// wrapper around a template which trims the output +type TrimmerTemplate struct { + template *template.Template + buffer *bytes.Buffer +} + +func NewTrimmerTemplate(template *template.Template) *TrimmerTemplate { + return &TrimmerTemplate{ + template: template, + buffer: bytes.NewBuffer(nil), + } +} + +func (self *TrimmerTemplate) execute(tmplData map[string]string) (string, error) { + self.buffer.Reset() + err := self.template.Execute(self.buffer, tmplData) + if err != nil { + return "", err + } + return strings.TrimSpace(self.buffer.String()), nil +} diff --git a/pkg/gui/custom_commands_test.go b/pkg/gui/services/custom_commands/menu_generator_test.go similarity index 75% rename from pkg/gui/custom_commands_test.go rename to pkg/gui/services/custom_commands/menu_generator_test.go index d31bcf291..7dd3e58e8 100644 --- a/pkg/gui/custom_commands_test.go +++ b/pkg/gui/services/custom_commands/menu_generator_test.go @@ -1,19 +1,20 @@ -package gui +package custom_commands import ( "testing" + "github.com/jesseduffield/lazygit/pkg/utils" "github.com/stretchr/testify/assert" ) -func TestGuiGenerateMenuCandidates(t *testing.T) { +func TestMenuGenerator(t *testing.T) { type scenario struct { testName string cmdOut string filter string valueFormat string labelFormat string - test func([]commandMenuEntry, error) + test func([]*commandMenuEntry, error) } scenarios := []scenario{ @@ -23,7 +24,7 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { "(?P [a-z_]+)/(?P .*)", "{{ .branch }}", "Remote: {{ .remote }}", - func(actualEntry []commandMenuEntry, err error) { + func(actualEntry []*commandMenuEntry, err error) { assert.NoError(t, err) assert.EqualValues(t, "pr-1", actualEntry[0].value) assert.EqualValues(t, "Remote: upstream", actualEntry[0].label) @@ -35,7 +36,7 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { "(?P [a-z]*)/(?P .*)", "{{ .branch }}|{{ .remote }}", "", - func(actualEntry []commandMenuEntry, err error) { + func(actualEntry []*commandMenuEntry, err error) { assert.NoError(t, err) assert.EqualValues(t, "pr-1|upstream", actualEntry[0].value) assert.EqualValues(t, "pr-1|upstream", actualEntry[0].label) @@ -47,7 +48,7 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { "(?P [a-z]*)/(?P .*)", "{{ .group_2 }}|{{ .group_1 }}", "Remote: {{ .group_1 }}", - func(actualEntry []commandMenuEntry, err error) { + func(actualEntry []*commandMenuEntry, err error) { assert.NoError(t, err) assert.EqualValues(t, "pr-1|upstream", actualEntry[0].value) assert.EqualValues(t, "Remote: upstream", actualEntry[0].label) @@ -58,7 +59,7 @@ func TestGuiGenerateMenuCandidates(t *testing.T) { for _, s := range scenarios { s := s t.Run(s.testName, func(t *testing.T) { - s.test(NewDummyGui().GenerateMenuCandidates(s.cmdOut, s.filter, s.valueFormat, s.labelFormat)) + s.test(NewMenuGenerator(utils.NewDummyCommon()).call(s.cmdOut, s.filter, s.valueFormat, s.labelFormat)) }) } } diff --git a/pkg/gui/services/custom_commands/resolver.go b/pkg/gui/services/custom_commands/resolver.go new file mode 100644 index 000000000..ee965e5cd --- /dev/null +++ b/pkg/gui/services/custom_commands/resolver.go @@ -0,0 +1,98 @@ +package custom_commands + +import ( + "github.com/jesseduffield/lazygit/pkg/common" + "github.com/jesseduffield/lazygit/pkg/config" +) + +// takes a prompt that is defined in terms of template strings and resolves the templates to contain actual values +type Resolver struct { + c *common.Common +} + +func NewResolver(c *common.Common) *Resolver { + return &Resolver{c: c} +} + +func (self *Resolver) resolvePrompt( + prompt *config.CustomCommandPrompt, + resolveTemplate func(string) (string, error), +) (*config.CustomCommandPrompt, error) { + var err error + result := &config.CustomCommandPrompt{ + ValueFormat: prompt.ValueFormat, + LabelFormat: prompt.LabelFormat, + } + + result.Title, err = resolveTemplate(prompt.Title) + if err != nil { + return nil, err + } + + result.InitialValue, err = resolveTemplate(prompt.InitialValue) + if err != nil { + return nil, err + } + + result.Command, err = resolveTemplate(prompt.Command) + if err != nil { + return nil, err + } + + result.Filter, err = resolveTemplate(prompt.Filter) + if err != nil { + return nil, err + } + + if prompt.Type == "menu" { + result.Options, err = self.resolveMenuOptions(prompt, resolveTemplate) + if err != nil { + return nil, err + } + } + + return result, nil +} + +func (self *Resolver) resolveMenuOptions(prompt *config.CustomCommandPrompt, resolveTemplate func(string) (string, error)) ([]config.CustomCommandMenuOption, error) { + newOptions := make([]config.CustomCommandMenuOption, 0, len(prompt.Options)) + for _, option := range prompt.Options { + option := option + newOption, err := self.resolveMenuOption(&option, resolveTemplate) + if err != nil { + return nil, err + } + newOptions = append(newOptions, *newOption) + } + + return newOptions, nil +} + +func (self *Resolver) resolveMenuOption(option *config.CustomCommandMenuOption, resolveTemplate func(string) (string, error)) (*config.CustomCommandMenuOption, error) { + nameTemplate := option.Name + if nameTemplate == "" { + // this allows you to only pass values rather than bother with names/descriptions + nameTemplate = option.Value + } + + name, err := resolveTemplate(nameTemplate) + if err != nil { + return nil, err + } + + description, err := resolveTemplate(option.Description) + if err != nil { + return nil, err + } + + value, err := resolveTemplate(option.Value) + if err != nil { + return nil, err + } + + return &config.CustomCommandMenuOption{ + Name: name, + Description: description, + Value: value, + }, nil +} diff --git a/pkg/gui/services/custom_commands/session_state_loader.go b/pkg/gui/services/custom_commands/session_state_loader.go new file mode 100644 index 000000000..42f3403ec --- /dev/null +++ b/pkg/gui/services/custom_commands/session_state_loader.go @@ -0,0 +1,56 @@ +package custom_commands + +import ( + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" +) + +// loads the session state at the time that a custom command is invoked, for use +// in the custom command's template strings +type SessionStateLoader struct { + contexts *context.ContextTree + helpers *helpers.Helpers +} + +func NewSessionStateLoader(contexts *context.ContextTree, helpers *helpers.Helpers) *SessionStateLoader { + return &SessionStateLoader{ + contexts: contexts, + helpers: helpers, + } +} + +// SessionState captures the current state of the application for use in custom commands +type SessionState struct { + SelectedLocalCommit *models.Commit + SelectedReflogCommit *models.Commit + SelectedSubCommit *models.Commit + SelectedFile *models.File + SelectedPath string + SelectedLocalBranch *models.Branch + SelectedRemoteBranch *models.RemoteBranch + SelectedRemote *models.Remote + SelectedTag *models.Tag + SelectedStashEntry *models.StashEntry + SelectedCommitFile *models.CommitFile + SelectedCommitFilePath string + CheckedOutBranch *models.Branch +} + +func (self *SessionStateLoader) call() *SessionState { + return &SessionState{ + SelectedFile: self.contexts.Files.GetSelectedFile(), + SelectedPath: self.contexts.Files.GetSelectedPath(), + SelectedLocalCommit: self.contexts.LocalCommits.GetSelected(), + SelectedReflogCommit: self.contexts.ReflogCommits.GetSelected(), + SelectedLocalBranch: self.contexts.Branches.GetSelected(), + SelectedRemoteBranch: self.contexts.RemoteBranches.GetSelected(), + SelectedRemote: self.contexts.Remotes.GetSelected(), + SelectedTag: self.contexts.Tags.GetSelected(), + SelectedStashEntry: self.contexts.Stash.GetSelected(), + SelectedCommitFile: self.contexts.CommitFiles.GetSelectedFile(), + SelectedCommitFilePath: self.contexts.CommitFiles.GetSelectedPath(), + SelectedSubCommit: self.contexts.SubCommits.GetSelected(), + CheckedOutBranch: self.helpers.Refs.GetCheckedOutRef(), + } +} From 3e26f39deed48dbe133e076ab7ab7fffded52cf4 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 26 Feb 2022 15:02:28 +1100 Subject: [PATCH 082/385] remove dead code --- pkg/test/test.go | 32 ------------------------- pkg/test/utils.go | 59 ----------------------------------------------- 2 files changed, 91 deletions(-) delete mode 100644 pkg/test/test.go delete mode 100644 pkg/test/utils.go diff --git a/pkg/test/test.go b/pkg/test/test.go deleted file mode 100644 index da476b95c..000000000 --- a/pkg/test/test.go +++ /dev/null @@ -1,32 +0,0 @@ -package test - -import ( - "os" - "path/filepath" - - "github.com/go-errors/errors" - - "github.com/jesseduffield/lazygit/pkg/secureexec" - "github.com/jesseduffield/lazygit/pkg/utils" -) - -// GenerateRepo generates a repo from test/repos and changes the directory to be -// inside the newly made repo -func GenerateRepo(filename string) error { - reposDir := "/test/repos/" - testPath := utils.GetProjectRoot() + reposDir - - // workaround for debian packaging - if _, err := os.Stat(testPath); os.IsNotExist(err) { - cwd, _ := os.Getwd() - testPath = filepath.Dir(filepath.Dir(cwd)) + reposDir - } - if err := os.Chdir(testPath); err != nil { - return err - } - if output, err := secureexec.Command("bash", filename).CombinedOutput(); err != nil { - return errors.New(string(output)) - } - - return os.Chdir(testPath + "repo") -} diff --git a/pkg/test/utils.go b/pkg/test/utils.go deleted file mode 100644 index 47f2c1146..000000000 --- a/pkg/test/utils.go +++ /dev/null @@ -1,59 +0,0 @@ -package test - -import ( - "fmt" - "os/exec" - "regexp" - "strings" - "testing" - - "github.com/jesseduffield/lazygit/pkg/secureexec" - "github.com/mgutz/str" - "github.com/stretchr/testify/assert" -) - -// CommandSwapper takes a command, verifies that it is what it's expected to be -// and then returns a replacement command that will actually be called by the os -type CommandSwapper struct { - Expect string - Replace string -} - -// SwapCommand verifies the command is what we expected, and swaps it out for a different command -func (i *CommandSwapper) SwapCommand(t *testing.T, cmd string, args []string) *exec.Cmd { - splitCmd := str.ToArgv(i.Expect) - assert.EqualValues(t, splitCmd[0], cmd, fmt.Sprintf("received command: %s %s", cmd, strings.Join(args, " "))) - if len(splitCmd) > 1 { - assert.EqualValues(t, splitCmd[1:], args, fmt.Sprintf("received command: %s %s", cmd, strings.Join(args, " "))) - } - - splitCmd = str.ToArgv(i.Replace) - return secureexec.Command(splitCmd[0], splitCmd[1:]...) -} - -// CreateMockCommand creates a command function that will verify its receiving the right sequence of commands from lazygit -func CreateMockCommand(t *testing.T, swappers []*CommandSwapper) func(cmd string, args ...string) *exec.Cmd { - commandIndex := 0 - - return func(cmd string, args ...string) *exec.Cmd { - var command *exec.Cmd - if commandIndex > len(swappers)-1 { - assert.Fail(t, fmt.Sprintf("too many commands run. This command was (%s %s)", cmd, strings.Join(args, " "))) - } - command = swappers[commandIndex].SwapCommand(t, cmd, args) - commandIndex++ - return command - } -} - -func AssertContainsMatch(t *testing.T, strs []string, pattern *regexp.Regexp, message string) { - t.Helper() - - for _, str := range strs { - if pattern.Match([]byte(str)) { - return - } - } - - assert.Fail(t, message) -} From 4805db7d976af59efe97e1e3cc13ad0fc581c9c0 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 26 Feb 2022 15:28:50 +1100 Subject: [PATCH 083/385] use correct context --- pkg/gui/controllers/sub_commits_controller.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/gui/controllers/sub_commits_controller.go b/pkg/gui/controllers/sub_commits_controller.go index 55b0795c1..36d8b2315 100644 --- a/pkg/gui/controllers/sub_commits_controller.go +++ b/pkg/gui/controllers/sub_commits_controller.go @@ -75,8 +75,8 @@ func (self *SubCommitsController) Context() types.Context { return self.context() } -func (self *SubCommitsController) context() *context.ReflogCommitsContext { - return self.contexts.ReflogCommits +func (self *SubCommitsController) context() *context.SubCommitsContext { + return self.contexts.SubCommits } func (self *SubCommitsController) checkout(commit *models.Commit) error { From a3885e8ea34b44322234e2b2645b51994a1a73fb Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 26 Feb 2022 16:09:18 +1100 Subject: [PATCH 084/385] abbrev all commits to length 40 for consistency --- pkg/commands/loaders/commits.go | 2 +- pkg/commands/loaders/commits_test.go | 4 ++-- pkg/commands/loaders/reflog_commits.go | 2 +- pkg/commands/loaders/reflog_commits_test.go | 10 +++++----- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/commands/loaders/commits.go b/pkg/commands/loaders/commits.go index ea54a4e76..187a13bb0 100644 --- a/pkg/commands/loaders/commits.go +++ b/pkg/commands/loaders/commits.go @@ -435,7 +435,7 @@ func (self *CommitLoader) getLogCmd(opts GetCommitsOptions) oscommands.ICmdObj { allFlag, prettyFormat, limitFlag, - 20, + 40, filterFlag, ), ).DontLog() diff --git a/pkg/commands/loaders/commits_test.go b/pkg/commands/loaders/commits_test.go index 23406abcc..ff406abaf 100644 --- a/pkg/commands/loaders/commits_test.go +++ b/pkg/commands/loaders/commits_test.go @@ -57,7 +57,7 @@ func TestGetCommits(t *testing.T) { opts: GetCommitsOptions{RefName: "HEAD", IncludeRebaseCommits: false}, runner: oscommands.NewFakeRunner(t). Expect(`git merge-base "HEAD" "HEAD"@{u}`, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil). - Expect(`git log "HEAD" --topo-order --oneline --pretty=format:"%H|%at|%aN|%d|%p|%s" --abbrev=20`, "", nil), + Expect(`git log "HEAD" --topo-order --oneline --pretty=format:"%H|%at|%aN|%d|%p|%s" --abbrev=40`, "", nil), expectedCommits: []*models.Commit{}, expectedError: nil, @@ -71,7 +71,7 @@ func TestGetCommits(t *testing.T) { // here it's seeing which commits are yet to be pushed Expect(`git merge-base "HEAD" "HEAD"@{u}`, "b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164", nil). // here it's actually getting all the commits in a formatted form, one per line - Expect(`git log "HEAD" --topo-order --oneline --pretty=format:"%H|%at|%aN|%d|%p|%s" --abbrev=20`, commitsOutput, nil). + Expect(`git log "HEAD" --topo-order --oneline --pretty=format:"%H|%at|%aN|%d|%p|%s" --abbrev=40`, commitsOutput, nil). // here it's seeing where our branch diverged from the master branch so that we can mark that commit and parent commits as 'merged' Expect(`git merge-base "HEAD" "master"`, "26c07b1ab33860a1a7591a0638f9925ccf497ffa", nil), diff --git a/pkg/commands/loaders/reflog_commits.go b/pkg/commands/loaders/reflog_commits.go index dc1a4ac15..849c96f50 100644 --- a/pkg/commands/loaders/reflog_commits.go +++ b/pkg/commands/loaders/reflog_commits.go @@ -32,7 +32,7 @@ func (self *ReflogCommitLoader) GetReflogCommits(lastReflogCommit *models.Commit filterPathArg = fmt.Sprintf(" --follow -- %s", self.cmd.Quote(filterPath)) } - cmdObj := self.cmd.New(fmt.Sprintf(`git log -g --abbrev=20 --format="%%h %%ct %%gs"%s`, filterPathArg)).DontLog() + cmdObj := self.cmd.New(fmt.Sprintf(`git log -g --abbrev=40 --format="%%h %%ct %%gs"%s`, filterPathArg)).DontLog() onlyObtainedNewReflogCommits := false err := cmdObj.RunAndProcessLines(func(line string) (bool, error) { fields := strings.SplitN(line, " ", 3) diff --git a/pkg/commands/loaders/reflog_commits_test.go b/pkg/commands/loaders/reflog_commits_test.go index 0e00ca3e5..e3f1cbeb8 100644 --- a/pkg/commands/loaders/reflog_commits_test.go +++ b/pkg/commands/loaders/reflog_commits_test.go @@ -33,7 +33,7 @@ func TestGetReflogCommits(t *testing.T) { { testName: "no reflog entries", runner: oscommands.NewFakeRunner(t). - Expect(`git log -g --abbrev=20 --format="%h %ct %gs"`, "", nil), + Expect(`git log -g --abbrev=40 --format="%h %ct %gs"`, "", nil), lastReflogCommit: nil, expectedCommits: []*models.Commit{}, @@ -43,7 +43,7 @@ func TestGetReflogCommits(t *testing.T) { { testName: "some reflog entries", runner: oscommands.NewFakeRunner(t). - Expect(`git log -g --abbrev=20 --format="%h %ct %gs"`, reflogOutput, nil), + Expect(`git log -g --abbrev=40 --format="%h %ct %gs"`, reflogOutput, nil), lastReflogCommit: nil, expectedCommits: []*models.Commit{ @@ -84,7 +84,7 @@ func TestGetReflogCommits(t *testing.T) { { testName: "some reflog entries where last commit is given", runner: oscommands.NewFakeRunner(t). - Expect(`git log -g --abbrev=20 --format="%h %ct %gs"`, reflogOutput, nil), + Expect(`git log -g --abbrev=40 --format="%h %ct %gs"`, reflogOutput, nil), lastReflogCommit: &models.Commit{ Sha: "c3c4b66b64c97ffeecde", @@ -106,7 +106,7 @@ func TestGetReflogCommits(t *testing.T) { { testName: "when passing filterPath", runner: oscommands.NewFakeRunner(t). - Expect(`git log -g --abbrev=20 --format="%h %ct %gs" --follow -- "path"`, reflogOutput, nil), + Expect(`git log -g --abbrev=40 --format="%h %ct %gs" --follow -- "path"`, reflogOutput, nil), lastReflogCommit: &models.Commit{ Sha: "c3c4b66b64c97ffeecde", @@ -129,7 +129,7 @@ func TestGetReflogCommits(t *testing.T) { { testName: "when command returns error", runner: oscommands.NewFakeRunner(t). - Expect(`git log -g --abbrev=20 --format="%h %ct %gs"`, "", errors.New("haha")), + Expect(`git log -g --abbrev=40 --format="%h %ct %gs"`, "", errors.New("haha")), lastReflogCommit: nil, filterPath: "", From 675510ba53e3541a3b49f95f8ac1f8eb7b32a7d4 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 26 Feb 2022 16:22:46 +1100 Subject: [PATCH 085/385] fix integration test --- pkg/gui/gui.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index edcabba7f..9f83f0b74 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -574,6 +574,7 @@ func (gui *Gui) resetControllers() { setCommitMessage := gui.getSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage }) onCommitAttempt := func(message string) { + gui.State.savedCommitMessage = message gui.Views.CommitMessage.ClearTextArea() } From d59c0e27251f73f6928f3f4cf459b206d24271e7 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 26 Feb 2022 16:29:15 +1100 Subject: [PATCH 086/385] remove dead code --- pkg/gui/commit_files_panel.go | 17 ----------------- pkg/gui/context.go | 10 ---------- 2 files changed, 27 deletions(-) diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index be8ec1a53..0ada68090 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -1,27 +1,10 @@ package gui import ( - "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/controllers" ) -func (gui *Gui) getSelectedCommitFile() *models.CommitFile { - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() - if node == nil { - return nil - } - return node.File -} - -func (gui *Gui) getSelectedCommitFilePath() string { - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() - if node == nil { - return "" - } - return node.GetPath() -} - // TODO: do we need this? func (gui *Gui) onCommitFileFocus() error { gui.escapeLineByLinePanel() diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 748354c3d..b4b274092 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -448,16 +448,6 @@ func (gui *Gui) setViewTabForContext(c types.Context) { } } -func (gui *Gui) contextForContextKey(contextKey types.ContextKey) (types.Context, bool) { - for _, context := range gui.State.Contexts.Flatten() { - if context.GetKey() == contextKey { - return context, true - } - } - - return nil, false -} - func (gui *Gui) rerenderView(view *gocui.View) error { return gui.State.ViewContextMap.Get(view.Name()).HandleRender() } From d543e767d4b856e975de67a4c10e64e0a656b329 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 26 Feb 2022 16:29:18 +1100 Subject: [PATCH 087/385] update cheatsheets --- docs/keybindings/Keybindings_en.md | 23 ++++++++++++++--------- docs/keybindings/Keybindings_nl.md | 22 +++++++++++++--------- docs/keybindings/Keybindings_pl.md | 23 ++++++++++++++--------- docs/keybindings/Keybindings_zh.md | 23 ++++++++++++++--------- 4 files changed, 55 insertions(+), 36 deletions(-) diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index cee94e0a3..542d94516 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -42,8 +42,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Branches Panel (Branches Tab) - i: show git-flow options ctrl+o: copy branch name to clipboard + i: show git-flow options space: checkout o: create pull request O: create pull request options @@ -86,14 +86,14 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Branches Panel (Sub-commits)-## Stash Panel +## Stash Panel (Stash)- enter: view commit's files + ctrl+o: copy commit SHA to clipboard space: checkout commit g: view reset options n: new branch c: copy commit (cherry-pick) C: copy commit range (cherry-pick) ctrl+r: reset cherry-picked (copied) commits selection - ctrl+o: copy commit SHA to clipboard + enter: view selected item's files## Branches Panel (Tags Tab) @@ -111,6 +111,11 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directctrl+o: copy the committed file name to the clipboard ++ +## Commit Files Panel (Commit Files) + +c: checkout file d: discard this commit's changes to this file o: open file @@ -145,23 +150,23 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct v: paste commits (cherry-pick) ctrl+l: open log menu g: reset to this commit - enter: view commit's files space: checkout commit T: tag commit ctrl+y: copy commit message to clipboard o: open commit in browser + enter: view selected item's files## Commits Panel (Reflog Tab)- enter: view commit's files + ctrl+o: copy commit SHA to clipboard space: checkout commit g: view reset options c: copy commit (cherry-pick) C: copy commit range (cherry-pick) ctrl+r: reset cherry-picked (copied) commits selection - ctrl+o: copy commit SHA to clipboard + enter: view selected item's files## Extras Panel @@ -176,6 +181,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct D: view reset options ctrl+o: copy the file name to the clipboard ctrl+w: Toggle whether or not whitespace changes are shown in the diff view + d: view 'discard changes' options space: toggle staged ctrl+b: Filter files (staged/unstaged) c: commit changes @@ -185,7 +191,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct e: edit file o: open file i: add to .gitignore - d: view 'discard changes' options r: refresh files s: stash changes S: view stash options @@ -282,14 +287,14 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct esc: close menu- enter: view stash entry's files space: apply g: pop d: drop n: new branch + enter: view selected item's files## Status Panel diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index dde2d47a4..a1216b853 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -43,8 +43,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Branches Paneel (Branches Tabblad)- i: laat git-flow opties zien ctrl+o: kopieer branch name naar klembord + i: laat git-flow opties zien space: uitchecken o: maak een pull-request O: bekijk opties voor pull-aanvraag @@ -87,14 +87,14 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Branches Paneel (Sub-commits)-## Stash Paneel +## Stash Paneel (Stash)- enter: bekijk gecommite bestanden + ctrl+o: kopieer commit SHA naar klembord space: checkout commit g: bekijk reset opties n: nieuwe branch c: kopieer commit (cherry-pick) C: kopieer commit reeks (cherry-pick) ctrl+r: reset cherry-picked (gekopieerde) commits selectie - ctrl+o: kopieer commit SHA naar klembord + enter: bekijk gecommite bestanden## Branches Paneel (Tags Tabblad) @@ -112,6 +112,11 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directctrl+o: kopieer de vastgelegde bestandsnaam naar het klembord ++ +## Commit bestanden Paneel (Commit bestanden) + +c: bestand uitchecken d: uitsluit deze commit zijn veranderingen aan dit bestand o: open bestand @@ -146,23 +151,23 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct v: plak commits (cherry-pick) ctrl+l: open log menu g: reset naar deze commit - enter: bekijk gecommite bestanden space: checkout commit T: tag commit ctrl+y: kopieer commit bericht naar klembord o: open commit in browser + enter: bekijk gecommite bestanden## Commits Paneel (Reflog Tabblad)- enter: bekijk gecommite bestanden + ctrl+o: kopieer commit SHA naar klembord space: checkout commit g: bekijk reset opties c: kopieer commit (cherry-pick) C: kopieer commit reeks (cherry-pick) ctrl+r: reset cherry-picked (gekopieerde) commits selectie - ctrl+o: kopieer commit SHA naar klembord + enter: bekijk gecommite bestanden## Extras Paneel @@ -181,7 +186,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct e: verander bestand o: open bestand i: voeg toe aan .gitignore - d: bekijk 'veranderingen ongedaan maken' opties r: refresh bestanden s: stash-bestanden S: bekijk stash opties @@ -278,14 +282,14 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct esc: sluit menu- enter: bekijk bestanden van stash entry space: toepassen g: pop d: laten vallen n: nieuwe branch + enter: bekijk gecommite bestanden## Status Paneel diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index cb6192968..8d877f282 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -42,8 +42,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Ga艂臋zie Panel (Branches Tab)- i: show git-flow options ctrl+o: copy branch name to clipboard + i: show git-flow options space: prze艂膮cz o: utw贸rz 偶膮danie pobrania O: utw贸rz opcje 偶膮dania 艣ci膮gni臋cia @@ -86,14 +86,14 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Ga艂臋zie Panel (Sub-commits)-## Schowek Panel +## Schowek Panel (Schowek)- enter: przegl膮daj pliki commita + ctrl+o: copy commit SHA to clipboard space: checkout commit g: wy艣wietl opcje resetu n: nowa ga艂膮藕 c: kopiuj commit (przebieranie) C: kopiuj zakres commit贸w (przebieranie) ctrl+r: reset cherry-picked (copied) commits selection - ctrl+o: copy commit SHA to clipboard + enter: przegl膮daj pliki commita## Ga艂臋zie Panel (Tags Tab) @@ -111,6 +111,11 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directctrl+o: copy the committed file name to the clipboard ++ +## Pliki commita Panel (Pliki commita) + +c: plik wybierania d: porzu膰 zmiany commita dla tego pliku o: otw贸rz plik @@ -145,23 +150,23 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct v: wklej commity (przebieranie) ctrl+l: open log menu g: zresetuj do tego commita - enter: przegl膮daj pliki commita space: checkout commit T: tag commit ctrl+y: copy commit message to clipboard o: open commit in browser + enter: przegl膮daj pliki commita## Commity Panel (Reflog Tab)- enter: przegl膮daj pliki commita + ctrl+o: copy commit SHA to clipboard space: checkout commit g: wy艣wietl opcje resetu c: kopiuj commit (przebieranie) C: kopiuj zakres commit贸w (przebieranie) ctrl+r: reset cherry-picked (copied) commits selection - ctrl+o: copy commit SHA to clipboard + enter: przegl膮daj pliki commita## Extras Panel @@ -176,6 +181,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct D: wy艣wietl opcje resetu ctrl+o: copy the file name to the clipboard ctrl+w: Toggle whether or not whitespace changes are shown in the diff view + d: poka偶 opcje porzucania zmian space: prze艂膮cz stan poczekalni ctrl+b: Filter files (staged/unstaged) c: Zatwierd藕 zmiany @@ -185,7 +191,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct e: edytuj plik o: otw贸rz plik i: dodaj do .gitignore - d: poka偶 opcje porzucania zmian r: od艣wie偶 pliki s: przechowaj zmiany S: wy艣wietl opcje schowka @@ -282,14 +287,14 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct esc: close menu- enter: view stash entry's files space: zastosuj g: wyci膮gnij d: porzu膰 n: nowa ga艂膮藕 + enter: przegl膮daj pliki commita## Status Panel diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index de1915ba1..f718aa89f 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -42,8 +42,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## 鍒嗘敮 闈㈡澘 (鍒嗘敮鏍囩)- i: 鏄剧ず git-flow 閫夐」 ctrl+o: 灏嗗垎鏀悕绉板鍒跺埌鍓创鏉 + i: 鏄剧ず git-flow 閫夐」 space: 妫鍑 o: 鍒涘缓鎶撳彇璇锋眰 O: 鍒涘缓鎶撳彇璇锋眰閫夐」 @@ -86,14 +86,14 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## 鍒嗘敮 闈㈡澘 (瀛愭彁浜)-## 璐棌 闈㈡澘 +## 璐棌 闈㈡澘 (璐棌)- enter: 鏌ョ湅鎻愪氦鐨勬枃浠 + ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 space: 妫鍑烘彁浜 g: 鏌ョ湅閲嶇疆閫夐」 n: 鏂板垎鏀 c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 - ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 + enter: 鏌ョ湅鎻愪氦鐨勬枃浠## 鍒嗘敮 闈㈡澘 (鏍囩椤甸潰) @@ -111,6 +111,11 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directctrl+o: 灏嗘彁浜ょ殑鏂囦欢鍚嶅鍒跺埌鍓创鏉 ++ +## 鎻愪氦鏂囦欢 闈㈡澘 (鎻愪氦鏂囦欢) + +c: 妫鍑烘枃浠 d: 鏀惧純瀵规鏂囦欢鐨勬彁浜ゆ洿鏀 o: 鎵撳紑鏂囦欢 @@ -145,23 +150,23 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct v: 绮樿创鎻愪氦锛堟嫞閫夛級 ctrl+l: open log menu g: 閲嶇疆涓烘鎻愪氦 - enter: 鏌ョ湅鎻愪氦鐨勬枃浠 space: 妫鍑烘彁浜 T: 鏍囩鎻愪氦 ctrl+y: 灏嗘彁浜ゆ秷鎭鍒跺埌鍓创鏉 o: open commit in browser + enter: 鏌ョ湅鎻愪氦鐨勬枃浠## 鎻愪氦 闈㈡澘 (Reflog)- enter: 鏌ョ湅鎻愪氦鐨勬枃浠 + ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 space: 妫鍑烘彁浜 g: 鏌ョ湅閲嶇疆閫夐」 c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 - ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 + enter: 鏌ョ湅鎻愪氦鐨勬枃浠## Extras 闈㈡澘 @@ -176,6 +181,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct D: 鏌ョ湅閲嶇疆閫夐」 ctrl+o: 灏嗘枃浠跺悕澶嶅埗鍒板壀璐存澘 ctrl+w: 鍒囨崲鏄惁鍦ㄥ樊寮傝鍥句腑鏄剧ず绌虹櫧鏇存敼 + d: 鏌ョ湅'鏀惧純鏇存敼鈥橀夐」 space: 鍒囨崲鏆傚瓨鐘舵 ctrl+b: Filter files (staged/unstaged) c: 鎻愪氦鏇存敼 @@ -185,7 +191,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct e: 缂栬緫鏂囦欢 o: 鎵撳紑鏂囦欢 i: 娣诲姞鍒 .gitignore - d: 鏌ョ湅'鏀惧純鏇存敼鈥橀夐」 r: 鍒锋柊鏂囦欢 s: 灏嗘墍鏈夋洿鏀瑰姞鍏ヨ串钘 S: 鏌ョ湅闅愯棌閫夐」 @@ -282,14 +287,14 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct esc: 鍏抽棴鑿滃崟- enter: 鏌ョ湅璐棌鏉$洰涓殑鏂囦欢 space: 搴旂敤 g: 搴旂敤骞跺垹闄 d: 鍒犻櫎 n: 鏂板垎鏀 + enter: 鏌ョ湅鎻愪氦鐨勬枃浠## 鐘舵 闈㈡澘 From ee1337b93190d7354b64ce84bf5c9bccba48fe4e Mon Sep 17 00:00:00 2001 From: Jesse DuffieldDate: Sat, 26 Feb 2022 19:06:22 +1100 Subject: [PATCH 088/385] add remote branches controller --- pkg/gui/controllers/branches_controller.go | 96 ++++------- .../controllers/remote_branches_controller.go | 161 ++++++++++++++++++ pkg/gui/gui.go | 3 + pkg/gui/keybindings.go | 58 ------- pkg/gui/remote_branches_panel.go | 95 ----------- 5 files changed, 194 insertions(+), 219 deletions(-) create mode 100644 pkg/gui/controllers/remote_branches_controller.go diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index ff5989656..a151d4bcc 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -31,96 +31,70 @@ func NewBranchesController( func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Universal.Select), - Handler: self.handleBranchPress, + Handler: self.checkSelected(self.press), Description: self.c.Tr.LcCheckout, }, { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Branches.CreatePullRequest), - Handler: self.handleCreatePullRequestPress, + Handler: self.checkSelected(self.handleCreatePullRequest), Description: self.c.Tr.LcCreatePullRequest, }, { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Branches.ViewPullRequestOptions), Handler: self.checkSelected(self.handleCreatePullRequestMenu), Description: self.c.Tr.LcCreatePullRequestOptions, OpensMenu: true, }, { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Branches.CopyPullRequestURL), - Handler: self.handleCopyPullRequestURLPress, + Handler: self.copyPullRequestURL, Description: self.c.Tr.LcCopyPullRequestURL, }, { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Branches.CheckoutBranchByName), - Handler: self.handleCheckoutByName, + Handler: self.checkoutByName, Description: self.c.Tr.LcCheckoutByName, }, { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Branches.ForceCheckoutBranch), - Handler: self.handleForceCheckout, + Handler: self.forceCheckout, Description: self.c.Tr.LcForceCheckout, }, { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Universal.New), - Handler: self.checkSelected(self.handleNewBranchOffBranch), + Handler: self.checkSelected(self.newBranch), Description: self.c.Tr.LcNewBranch, }, { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Universal.Remove), - Handler: self.checkSelectedAndReal(self.handleDeleteBranch), + Handler: self.checkSelectedAndReal(self.delete), Description: self.c.Tr.LcDeleteBranch, }, { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Branches.RebaseBranch), - Handler: opts.Guards.OutsideFilterMode(self.handleRebaseOntoLocalBranch), + Handler: opts.Guards.OutsideFilterMode(self.rebase), Description: self.c.Tr.LcRebaseBranch, }, { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch), - Handler: opts.Guards.OutsideFilterMode(self.handleMerge), + Handler: opts.Guards.OutsideFilterMode(self.merge), Description: self.c.Tr.LcMergeIntoCurrentBranch, }, { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Branches.FastForward), - Handler: self.checkSelectedAndReal(self.handleFastForward), + Handler: self.checkSelectedAndReal(self.fastForward), Description: self.c.Tr.FastForward, }, { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), - Handler: self.checkSelected(self.handleCreateResetToBranchMenu), + Handler: self.checkSelected(self.createResetMenu), Description: self.c.Tr.LcViewResetOptions, OpensMenu: true, }, { - ViewName: "branches", - Contexts: []string{string(context.LOCAL_BRANCHES_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Branches.RenameBranch), - Handler: self.checkSelectedAndReal(self.handleRenameBranch), + Handler: self.checkSelectedAndReal(self.rename), Description: self.c.Tr.LcRenameBranch, }, } @@ -134,23 +108,17 @@ func (self *BranchesController) context() *context.BranchesContext { return self.contexts.Branches } -func (self *BranchesController) handleBranchPress() error { - branch := self.context().GetSelected() - if branch == nil { - return nil - } - - if branch == self.helpers.Refs.GetCheckedOutRef() { +func (self *BranchesController) press(selectedBranch *models.Branch) error { + if selectedBranch == self.helpers.Refs.GetCheckedOutRef() { return self.c.ErrorMsg(self.c.Tr.AlreadyCheckedOutBranch) } self.c.LogAction(self.c.Tr.Actions.CheckoutBranch) - return self.helpers.Refs.CheckoutRef(branch.Name, types.CheckoutRefOptions{}) + return self.helpers.Refs.CheckoutRef(selectedBranch.Name, types.CheckoutRefOptions{}) } -func (self *BranchesController) handleCreatePullRequestPress() error { - branch := self.context().GetSelected() - return self.createPullRequest(branch.Name, "") +func (self *BranchesController) handleCreatePullRequest(selectedBranch *models.Branch) error { + return self.createPullRequest(selectedBranch.Name, "") } func (self *BranchesController) handleCreatePullRequestMenu(selectedBranch *models.Branch) error { @@ -159,7 +127,7 @@ func (self *BranchesController) handleCreatePullRequestMenu(selectedBranch *mode return self.createPullRequestMenu(selectedBranch, checkedOutBranch) } -func (self *BranchesController) handleCopyPullRequestURLPress() error { +func (self *BranchesController) copyPullRequestURL() error { branch := self.context().GetSelected() branchExistsOnRemote := self.git.Remote.CheckRemoteBranchExists(branch.Name) @@ -182,7 +150,7 @@ func (self *BranchesController) handleCopyPullRequestURLPress() error { return nil } -func (self *BranchesController) handleForceCheckout() error { +func (self *BranchesController) forceCheckout() error { branch := self.context().GetSelected() message := self.c.Tr.SureForceCheckout title := self.c.Tr.ForceCheckoutBranch @@ -200,7 +168,7 @@ func (self *BranchesController) handleForceCheckout() error { }) } -func (self *BranchesController) handleCheckoutByName() error { +func (self *BranchesController) checkoutByName() error { return self.c.Prompt(types.PromptOpts{ Title: self.c.Tr.BranchName + ":", FindSuggestionsFunc: self.helpers.Suggestions.GetRefsSuggestionsFunc(), @@ -235,19 +203,15 @@ func (self *BranchesController) createNewBranchWithName(newBranchName string) er return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) } -func (self *BranchesController) handleDeleteBranch(branch *models.Branch) error { - return self.deleteBranch(branch, false) -} - -func (self *BranchesController) deleteBranch(branch *models.Branch, force bool) error { +func (self *BranchesController) delete(branch *models.Branch) error { checkedOutBranch := self.helpers.Refs.GetCheckedOutRef() if checkedOutBranch.Name == branch.Name { return self.c.ErrorMsg(self.c.Tr.CantDeleteCheckOutBranch) } - return self.deleteNamedBranch(branch, force) + return self.deleteWithForce(branch, false) } -func (self *BranchesController) deleteNamedBranch(selectedBranch *models.Branch, force bool) error { +func (self *BranchesController) deleteWithForce(selectedBranch *models.Branch, force bool) error { title := self.c.Tr.DeleteBranch var templateStr string if force { @@ -270,7 +234,7 @@ func (self *BranchesController) deleteNamedBranch(selectedBranch *models.Branch, if err := self.git.Branch.Delete(selectedBranch.Name, force); err != nil { errMessage := err.Error() if !force && strings.Contains(errMessage, "git branch -D ") { - return self.deleteNamedBranch(selectedBranch, true) + return self.deleteWithForce(selectedBranch, true) } return self.c.ErrorMsg(errMessage) } @@ -279,17 +243,17 @@ func (self *BranchesController) deleteNamedBranch(selectedBranch *models.Branch, }) } -func (self *BranchesController) handleMerge() error { +func (self *BranchesController) merge() error { selectedBranchName := self.context().GetSelected().Name return self.helpers.MergeAndRebase.MergeRefIntoCheckedOutBranch(selectedBranchName) } -func (self *BranchesController) handleRebaseOntoLocalBranch() error { +func (self *BranchesController) rebase() error { selectedBranchName := self.context().GetSelected().Name return self.helpers.MergeAndRebase.RebaseOntoRef(selectedBranchName) } -func (self *BranchesController) handleFastForward(branch *models.Branch) error { +func (self *BranchesController) fastForward(branch *models.Branch) error { if !branch.IsTrackingRemote() { return self.c.ErrorMsg(self.c.Tr.FwdNoUpstream) } @@ -339,11 +303,11 @@ func (self *BranchesController) handleFastForward(branch *models.Branch) error { }) } -func (self *BranchesController) handleCreateResetToBranchMenu(selectedBranch *models.Branch) error { +func (self *BranchesController) createResetMenu(selectedBranch *models.Branch) error { return self.helpers.Refs.CreateGitResetMenu(selectedBranch.Name) } -func (self *BranchesController) handleRenameBranch(branch *models.Branch) error { +func (self *BranchesController) rename(branch *models.Branch) error { promptForNewName := func() error { return self.c.Prompt(types.PromptOpts{ Title: self.c.Tr.NewBranchNamePrompt + " " + branch.Name + ":", @@ -386,7 +350,7 @@ func (self *BranchesController) handleRenameBranch(branch *models.Branch) error }) } -func (self *BranchesController) handleNewBranchOffBranch(selectedBranch *models.Branch) error { +func (self *BranchesController) newBranch(selectedBranch *models.Branch) error { return self.helpers.Refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), "") } diff --git a/pkg/gui/controllers/remote_branches_controller.go b/pkg/gui/controllers/remote_branches_controller.go new file mode 100644 index 000000000..d469f5657 --- /dev/null +++ b/pkg/gui/controllers/remote_branches_controller.go @@ -0,0 +1,161 @@ +package controllers + +import ( + "fmt" + "strings" + + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +type RemoteBranchesController struct { + baseController + *controllerCommon +} + +var _ types.IController = &RemoteBranchesController{} + +func NewRemoteBranchesController( + common *controllerCommon, +) *RemoteBranchesController { + return &RemoteBranchesController{ + baseController: baseController{}, + controllerCommon: common, + } +} + +func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + return []*types.Binding{ + { + Key: opts.GetKey(opts.Config.Universal.Select), + // gonna use the exact same handler as the 'n' keybinding because everybody wants this to happen when they checkout a remote branch + Handler: self.checkSelected(self.newLocalBranch), + Description: self.c.Tr.LcCheckout, + }, + { + Key: opts.GetKey(opts.Config.Universal.New), + Handler: self.checkSelected(self.newLocalBranch), + Description: self.c.Tr.LcNewBranch, + }, + { + Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch), + Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.merge)), + Description: self.c.Tr.LcMergeIntoCurrentBranch, + }, + { + Key: opts.GetKey(opts.Config.Branches.RebaseBranch), + Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.rebase)), + Description: self.c.Tr.LcRebaseBranch, + }, + { + Key: opts.GetKey(opts.Config.Universal.Remove), + Handler: self.checkSelected(self.delete), + Description: self.c.Tr.LcDeleteBranch, + }, + { + Key: opts.GetKey(opts.Config.Branches.SetUpstream), + Handler: self.checkSelected(self.setAsUpstream), + Description: self.c.Tr.LcSetUpstream, + }, + { + Key: opts.GetKey(opts.Config.Universal.Return), + Handler: self.escape, + Description: self.c.Tr.ReturnToRemotesList, + }, + { + Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), + Handler: self.checkSelected(self.createResetMenu), + Description: self.c.Tr.LcViewResetOptions, + OpensMenu: true, + }, + } +} + +func (self *RemoteBranchesController) Context() types.Context { + return self.context() +} + +func (self *RemoteBranchesController) context() *context.RemoteBranchesContext { + return self.contexts.RemoteBranches +} + +func (self *RemoteBranchesController) checkSelected(callback func(*models.RemoteBranch) error) func() error { + return func() error { + selectedItem := self.context().GetSelected() + if selectedItem == nil { + return nil + } + + return callback(selectedItem) + } +} + +func (self *RemoteBranchesController) escape() error { + return self.c.PushContext(self.contexts.Remotes) +} + +func (self *RemoteBranchesController) delete(selectedBranch *models.RemoteBranch) error { + message := fmt.Sprintf("%s '%s'?", self.c.Tr.DeleteRemoteBranchMessage, selectedBranch.FullName()) + + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.DeleteRemoteBranch, + Prompt: message, + HandleConfirm: func() error { + return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func() error { + self.c.LogAction(self.c.Tr.Actions.DeleteRemoteBranch) + err := self.git.Remote.DeleteRemoteBranch(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 { + return self.helpers.MergeAndRebase.MergeRefIntoCheckedOutBranch(selectedBranch.FullName()) +} + +func (self *RemoteBranchesController) rebase(selectedBranch *models.RemoteBranch) error { + return self.helpers.MergeAndRebase.RebaseOntoRef(selectedBranch.FullName()) +} + +func (self *RemoteBranchesController) createResetMenu(selectedBranch *models.RemoteBranch) error { + return self.helpers.Refs.CreateGitResetMenu(selectedBranch.FullName()) +} + +func (self *RemoteBranchesController) setAsUpstream(selectedBranch *models.RemoteBranch) error { + checkedOutBranch := self.helpers.Refs.GetCheckedOutRef() + + message := utils.ResolvePlaceholderString( + self.c.Tr.SetUpstreamMessage, + map[string]string{ + "checkedOut": checkedOutBranch.Name, + "selected": selectedBranch.FullName(), + }, + ) + + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.SetUpstreamTitle, + Prompt: message, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.SetBranchUpstream) + if err := self.git.Branch.SetUpstream(selectedBranch.RemoteName, selectedBranch.Name, checkedOutBranch.Name); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) + }, + }) +} + +func (self *RemoteBranchesController) newLocalBranch(selectedBranch *models.RemoteBranch) error { + // will set to the remote's branch name without the remote name + nameSuggestion := strings.SplitAfterN(selectedBranch.RefName(), "/", 2)[1] + + return self.helpers.Refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), nameSuggestion) +} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 9f83f0b74..1cd2229f5 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -589,6 +589,8 @@ func (gui *Gui) resetControllers() { onCommitSuccess, ) + remoteBranchesController := controllers.NewRemoteBranchesController(common) + gui.Controllers = Controllers{ Submodules: submodulesController, Global: controllers.NewGlobalController(common), @@ -655,6 +657,7 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(gui.State.Contexts.Stash, stashController) controllers.AttachControllers(gui.State.Contexts.Menu, gui.Controllers.Menu) controllers.AttachControllers(gui.State.Contexts.CommitMessage, commitMessageController) + controllers.AttachControllers(gui.State.Contexts.RemoteBranches, remoteBranchesController) controllers.AttachControllers(gui.State.Contexts.Global, gui.Controllers.Sync, gui.Controllers.Undo, gui.Controllers.Global) listControllerFactory := controllers.NewListControllerFactory(gui.c) diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 7c5e0be25..4b0fcd99a 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -387,21 +387,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Handler: self.handleCopySelectedSideContextItemToClipboard, Description: self.c.Tr.LcCopyBranchNameToClipboard, }, - { - ViewName: "branches", - Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Universal.Return), - Handler: self.handleRemoteBranchesEscape, - Description: self.c.Tr.ReturnToRemotesList, - }, - { - ViewName: "branches", - Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), - Handler: self.handleCreateResetToRemoteBranchMenu, - Description: self.c.Tr.LcViewResetOptions, - OpensMenu: true, - }, { ViewName: "commits", Contexts: []string{string(context.LOCAL_COMMITS_CONTEXT_KEY)}, @@ -872,49 +857,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Handler: self.handleMergeConflictUndo, Description: self.c.Tr.LcUndo, }, - { - ViewName: "branches", - Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Universal.Select), - // gonna use the exact same handler as the 'n' keybinding because everybody wants this to happen when they checkout a remote branch - Handler: self.handleNewBranchOffRemoteBranch, - Description: self.c.Tr.LcCheckout, - }, - { - ViewName: "branches", - Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Universal.New), - Handler: self.handleNewBranchOffRemoteBranch, - Description: self.c.Tr.LcNewBranch, - }, - { - ViewName: "branches", - Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Branches.MergeIntoCurrentBranch), - Handler: opts.Guards.OutsideFilterMode(self.handleMergeRemoteBranch), - Description: self.c.Tr.LcMergeIntoCurrentBranch, - }, - { - ViewName: "branches", - Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Universal.Remove), - Handler: self.handleDeleteRemoteBranch, - Description: self.c.Tr.LcDeleteBranch, - }, - { - ViewName: "branches", - Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Branches.RebaseBranch), - Handler: opts.Guards.OutsideFilterMode(self.handleRebaseOntoRemoteBranch), - Description: self.c.Tr.LcRebaseBranch, - }, - { - ViewName: "branches", - Contexts: []string{string(context.REMOTE_BRANCHES_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Branches.SetUpstream), - Handler: self.handleSetBranchUpstream, - Description: self.c.Tr.LcSetUpstream, - }, { ViewName: "status", Key: gocui.MouseLeft, diff --git a/pkg/gui/remote_branches_panel.go b/pkg/gui/remote_branches_panel.go index eeed4cd13..3f23f0646 100644 --- a/pkg/gui/remote_branches_panel.go +++ b/pkg/gui/remote_branches_panel.go @@ -1,15 +1,5 @@ package gui -import ( - "fmt" - "strings" - - "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/jesseduffield/lazygit/pkg/utils" -) - -// list panel functions - func (gui *Gui) remoteBranchesRenderToMain() error { var task updateTask remoteBranch := gui.State.Contexts.RemoteBranches.GetSelected() @@ -27,88 +17,3 @@ func (gui *Gui) remoteBranchesRenderToMain() error { }, }) } - -func (gui *Gui) handleRemoteBranchesEscape() error { - return gui.c.PushContext(gui.State.Contexts.Remotes) -} - -func (gui *Gui) handleMergeRemoteBranch() error { - selectedBranchName := gui.State.Contexts.RemoteBranches.GetSelected().FullName() - return gui.helpers.MergeAndRebase.MergeRefIntoCheckedOutBranch(selectedBranchName) -} - -func (gui *Gui) handleDeleteRemoteBranch() error { - remoteBranch := gui.State.Contexts.RemoteBranches.GetSelected() - if remoteBranch == nil { - return nil - } - message := fmt.Sprintf("%s '%s'?", gui.c.Tr.DeleteRemoteBranchMessage, remoteBranch.FullName()) - - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.DeleteRemoteBranch, - Prompt: message, - HandleConfirm: func() error { - return gui.c.WithWaitingStatus(gui.c.Tr.DeletingStatus, func() error { - gui.c.LogAction(gui.c.Tr.Actions.DeleteRemoteBranch) - err := gui.git.Remote.DeleteRemoteBranch(remoteBranch.RemoteName, remoteBranch.Name) - if err != nil { - _ = gui.c.Error(err) - } - - return gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) - }) - }, - }) -} - -func (gui *Gui) handleRebaseOntoRemoteBranch() error { - selectedBranchName := gui.State.Contexts.RemoteBranches.GetSelected().FullName() - return gui.helpers.MergeAndRebase.RebaseOntoRef(selectedBranchName) -} - -func (gui *Gui) handleSetBranchUpstream() error { - selectedBranch := gui.State.Contexts.RemoteBranches.GetSelected() - checkedOutBranch := gui.helpers.Refs.GetCheckedOutRef() - - message := utils.ResolvePlaceholderString( - gui.c.Tr.SetUpstreamMessage, - map[string]string{ - "checkedOut": checkedOutBranch.Name, - "selected": selectedBranch.FullName(), - }, - ) - - return gui.c.Ask(types.AskOpts{ - Title: gui.c.Tr.SetUpstreamTitle, - Prompt: message, - HandleConfirm: func() error { - gui.c.LogAction(gui.c.Tr.Actions.SetBranchUpstream) - if err := gui.git.Branch.SetUpstream(selectedBranch.RemoteName, selectedBranch.Name, checkedOutBranch.Name); err != nil { - return gui.c.Error(err) - } - - return gui.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}}) - }, - }) -} - -func (gui *Gui) handleCreateResetToRemoteBranchMenu() error { - selectedBranch := gui.State.Contexts.RemoteBranches.GetSelected() - if selectedBranch == nil { - return nil - } - - return gui.helpers.Refs.CreateGitResetMenu(selectedBranch.FullName()) -} - -func (gui *Gui) handleNewBranchOffRemoteBranch() error { - selectedBranch := gui.State.Contexts.RemoteBranches.GetSelected() - if selectedBranch == nil { - return nil - } - - // will set to the remote's branch name without the remote name - nameSuggestion := strings.SplitAfterN(selectedBranch.RefName(), "/", 2)[1] - - return gui.helpers.Refs.NewBranch(selectedBranch.RefName(), selectedBranch.RefName(), nameSuggestion) -} From 8fd6338527dff7ca3e5a9c5b55309d74d14615ef Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 26 Feb 2022 19:26:39 +1100 Subject: [PATCH 089/385] move workspace reset menu into controller --- pkg/gui/controllers.go | 180 ++++++++++++++++++ pkg/gui/controllers/files_controller.go | 11 +- .../controllers/workspace_reset_controller.go | 108 +++++++++++ pkg/gui/gui.go | 168 ---------------- pkg/gui/keybindings.go | 8 - pkg/gui/workspace_reset_options_panel.go | 106 ----------- 6 files changed, 296 insertions(+), 285 deletions(-) create mode 100644 pkg/gui/controllers.go create mode 100644 pkg/gui/controllers/workspace_reset_controller.go delete mode 100644 pkg/gui/workspace_reset_options_panel.go diff --git a/pkg/gui/controllers.go b/pkg/gui/controllers.go new file mode 100644 index 000000000..0755bbe8e --- /dev/null +++ b/pkg/gui/controllers.go @@ -0,0 +1,180 @@ +package gui + +import ( + "strings" + + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/controllers" + "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" + "github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking" + "github.com/jesseduffield/lazygit/pkg/gui/services/custom_commands" +) + +func (gui *Gui) resetControllers() { + helperCommon := gui.c + osCommand := gui.os + model := gui.State.Model + refsHelper := helpers.NewRefsHelper( + helperCommon, + gui.git, + gui.State.Contexts, + model, + ) + + rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling, refsHelper) + gui.helpers = &helpers.Helpers{ + Refs: refsHelper, + PatchBuilding: helpers.NewPatchBuildingHelper(helperCommon, gui.git), + Bisect: helpers.NewBisectHelper(helperCommon, gui.git), + Suggestions: helpers.NewSuggestionsHelper(helperCommon, model, gui.refreshSuggestions), + Files: helpers.NewFilesHelper(helperCommon, gui.git, osCommand), + WorkingTree: helpers.NewWorkingTreeHelper(model), + Tags: helpers.NewTagsHelper(helperCommon, gui.git), + GPG: helpers.NewGpgHelper(helperCommon, gui.os, gui.git), + MergeAndRebase: rebaseHelper, + CherryPick: helpers.NewCherryPickHelper( + helperCommon, + gui.git, + gui.State.Contexts, + func() *cherrypicking.CherryPicking { return gui.State.Modes.CherryPicking }, + rebaseHelper, + ), + } + + gui.CustomCommandsClient = custom_commands.NewClient( + helperCommon, + gui.os, + gui.git, + gui.State.Contexts, + gui.helpers, + gui.getKey, + ) + + common := controllers.NewControllerCommon( + helperCommon, + osCommand, + gui.git, + gui.helpers, + model, + gui.State.Contexts, + gui.State.Modes, + ) + + syncController := controllers.NewSyncController( + common, + gui.getSuggestedRemote, + ) + + submodulesController := controllers.NewSubmodulesController( + common, + gui.enterSubmodule, + ) + + bisectController := controllers.NewBisectController(common) + + reflogController := controllers.NewReflogController(common) + subCommitsController := controllers.NewSubCommitsController(common) + + getSavedCommitMessage := func() string { + return gui.State.savedCommitMessage + } + + getCommitMessage := func() string { + return strings.TrimSpace(gui.Views.CommitMessage.TextArea.GetContent()) + } + + setCommitMessage := gui.getSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage }) + + onCommitAttempt := func(message string) { + gui.State.savedCommitMessage = message + gui.Views.CommitMessage.ClearTextArea() + } + + onCommitSuccess := func() { + gui.State.savedCommitMessage = "" + } + + commitMessageController := controllers.NewCommitMessageController( + common, + getCommitMessage, + onCommitAttempt, + onCommitSuccess, + ) + + remoteBranchesController := controllers.NewRemoteBranchesController(common) + + gui.Controllers = Controllers{ + Submodules: submodulesController, + Global: controllers.NewGlobalController(common), + Files: controllers.NewFilesController( + common, + gui.enterSubmodule, + setCommitMessage, + getSavedCommitMessage, + gui.switchToMerge, + ), + Tags: controllers.NewTagsController(common), + LocalCommits: controllers.NewLocalCommitsController(common, syncController.HandlePull), + Remotes: controllers.NewRemotesController( + common, + func(branches []*models.RemoteBranch) { gui.State.Model.RemoteBranches = branches }, + ), + Menu: controllers.NewMenuController(common), + Undo: controllers.NewUndoController(common), + Sync: syncController, + } + + branchesController := controllers.NewBranchesController(common) + gitFlowController := controllers.NewGitFlowController(common) + filesRemoveController := controllers.NewFilesRemoveController(common) + stashController := controllers.NewStashController(common) + commitFilesController := controllers.NewCommitFilesController(common) + + switchToSubCommitsControllerFactory := controllers.NewSubCommitsSwitchControllerFactory( + common, + func(commits []*models.Commit) { gui.State.Model.SubCommits = commits }, + ) + + for _, context := range []controllers.ContextWithRefName{ + gui.State.Contexts.Branches, + gui.State.Contexts.RemoteBranches, + gui.State.Contexts.Tags, + } { + controllers.AttachControllers(context, switchToSubCommitsControllerFactory.Create(context)) + } + + commitishControllerFactory := controllers.NewCommitishControllerFactory( + common, + gui.SwitchToCommitFilesContext, + ) + + for _, context := range []controllers.Commitish{ + gui.State.Contexts.LocalCommits, + gui.State.Contexts.ReflogCommits, + gui.State.Contexts.SubCommits, + gui.State.Contexts.Stash, + } { + controllers.AttachControllers(context, commitishControllerFactory.Create(context)) + } + + controllers.AttachControllers(gui.State.Contexts.Branches, branchesController, gitFlowController) + controllers.AttachControllers(gui.State.Contexts.Files, gui.Controllers.Files, filesRemoveController) + controllers.AttachControllers(gui.State.Contexts.Tags, gui.Controllers.Tags) + controllers.AttachControllers(gui.State.Contexts.Submodules, gui.Controllers.Submodules) + controllers.AttachControllers(gui.State.Contexts.LocalCommits, gui.Controllers.LocalCommits, bisectController) + controllers.AttachControllers(gui.State.Contexts.ReflogCommits, reflogController) + controllers.AttachControllers(gui.State.Contexts.SubCommits, subCommitsController) + controllers.AttachControllers(gui.State.Contexts.CommitFiles, commitFilesController) + controllers.AttachControllers(gui.State.Contexts.Remotes, gui.Controllers.Remotes) + controllers.AttachControllers(gui.State.Contexts.Stash, stashController) + controllers.AttachControllers(gui.State.Contexts.Menu, gui.Controllers.Menu) + controllers.AttachControllers(gui.State.Contexts.CommitMessage, commitMessageController) + controllers.AttachControllers(gui.State.Contexts.RemoteBranches, remoteBranchesController) + controllers.AttachControllers(gui.State.Contexts.Global, gui.Controllers.Sync, gui.Controllers.Undo, gui.Controllers.Global) + + listControllerFactory := controllers.NewListControllerFactory(gui.c) + for _, context := range gui.getListContexts() { + controllers.AttachControllers(context, listControllerFactory.Create(context)) + } +} diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index e12554a3d..5f6ccec7e 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -122,11 +122,16 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types }, { Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), - Handler: self.createResetMenu, + Handler: self.createResetToUpstreamMenu, Description: self.c.Tr.LcViewResetToUpstreamOptions, OpensMenu: true, }, - // here + { + Key: opts.GetKey(opts.Config.Files.ViewResetOptions), + Handler: self.createResetMenu, + Description: self.c.Tr.LcViewResetOptions, + OpensMenu: true, + }, { Key: opts.GetKey(opts.Config.Files.ToggleTreeView), Handler: self.toggleTreeView, @@ -571,7 +576,7 @@ func (self *FilesController) stash() error { return self.handleStashSave(self.git.Stash.Save) } -func (self *FilesController) createResetMenu() error { +func (self *FilesController) createResetToUpstreamMenu() error { return self.helpers.Refs.CreateGitResetMenu("@{upstream}") } diff --git a/pkg/gui/controllers/workspace_reset_controller.go b/pkg/gui/controllers/workspace_reset_controller.go new file mode 100644 index 000000000..9153e34e8 --- /dev/null +++ b/pkg/gui/controllers/workspace_reset_controller.go @@ -0,0 +1,108 @@ +package controllers + +import ( + "fmt" + + "github.com/jesseduffield/lazygit/pkg/gui/style" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +// this is in its own file given that the workspace controller file is already quite long + +func (self *FilesController) createResetMenu() error { + red := style.FgRed + + nukeStr := "reset --hard HEAD && git clean -fd" + if len(self.model.Submodules) > 0 { + nukeStr = fmt.Sprintf("%s (%s)", nukeStr, self.c.Tr.LcAndResetSubmodules) + } + + menuItems := []*types.MenuItem{ + { + DisplayStrings: []string{ + self.c.Tr.LcDiscardAllChangesToAllFiles, + red.Sprint(nukeStr), + }, + OnPress: func() error { + self.c.LogAction(self.c.Tr.Actions.NukeWorkingTree) + if err := self.git.WorkingTree.ResetAndClean(); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + }, + }, + { + DisplayStrings: []string{ + self.c.Tr.LcDiscardAnyUnstagedChanges, + red.Sprint("git checkout -- ."), + }, + OnPress: func() error { + self.c.LogAction(self.c.Tr.Actions.DiscardUnstagedFileChanges) + if err := self.git.WorkingTree.DiscardAnyUnstagedFileChanges(); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + }, + }, + { + DisplayStrings: []string{ + self.c.Tr.LcDiscardUntrackedFiles, + red.Sprint("git clean -fd"), + }, + OnPress: func() error { + self.c.LogAction(self.c.Tr.Actions.RemoveUntrackedFiles) + if err := self.git.WorkingTree.RemoveUntrackedFiles(); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + }, + }, + { + DisplayStrings: []string{ + self.c.Tr.LcSoftReset, + red.Sprint("git reset --soft HEAD"), + }, + OnPress: func() error { + self.c.LogAction(self.c.Tr.Actions.SoftReset) + if err := self.git.WorkingTree.ResetSoft("HEAD"); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + }, + }, + { + DisplayStrings: []string{ + "mixed reset", + red.Sprint("git reset --mixed HEAD"), + }, + OnPress: func() error { + self.c.LogAction(self.c.Tr.Actions.MixedReset) + if err := self.git.WorkingTree.ResetMixed("HEAD"); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + }, + }, + { + DisplayStrings: []string{ + self.c.Tr.LcHardReset, + red.Sprint("git reset --hard HEAD"), + }, + OnPress: func() error { + self.c.LogAction(self.c.Tr.Actions.HardReset) + if err := self.git.WorkingTree.ResetHard("HEAD"); err != nil { + return self.c.Error(err) + } + + return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) + }, + }, + } + + return self.c.Menu(types.CreateMenuOptions{Title: "", Items: menuItems}) +} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 1cd2229f5..b65493d49 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -498,174 +498,6 @@ func NewGui( return gui, nil } -func (gui *Gui) resetControllers() { - helperCommon := gui.c - osCommand := gui.os - model := gui.State.Model - refsHelper := helpers.NewRefsHelper( - helperCommon, - gui.git, - gui.State.Contexts, - model, - ) - - rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling, refsHelper) - gui.helpers = &helpers.Helpers{ - Refs: refsHelper, - PatchBuilding: helpers.NewPatchBuildingHelper(helperCommon, gui.git), - Bisect: helpers.NewBisectHelper(helperCommon, gui.git), - Suggestions: helpers.NewSuggestionsHelper(helperCommon, model, gui.refreshSuggestions), - Files: helpers.NewFilesHelper(helperCommon, gui.git, osCommand), - WorkingTree: helpers.NewWorkingTreeHelper(model), - Tags: helpers.NewTagsHelper(helperCommon, gui.git), - GPG: helpers.NewGpgHelper(helperCommon, gui.os, gui.git), - MergeAndRebase: rebaseHelper, - CherryPick: helpers.NewCherryPickHelper( - helperCommon, - gui.git, - gui.State.Contexts, - func() *cherrypicking.CherryPicking { return gui.State.Modes.CherryPicking }, - rebaseHelper, - ), - } - - gui.CustomCommandsClient = custom_commands.NewClient( - helperCommon, - gui.os, - gui.git, - gui.State.Contexts, - gui.helpers, - gui.getKey, - ) - - common := controllers.NewControllerCommon( - helperCommon, - osCommand, - gui.git, - gui.helpers, - model, - gui.State.Contexts, - gui.State.Modes, - ) - - syncController := controllers.NewSyncController( - common, - gui.getSuggestedRemote, - ) - - submodulesController := controllers.NewSubmodulesController( - common, - gui.enterSubmodule, - ) - - bisectController := controllers.NewBisectController(common) - - reflogController := controllers.NewReflogController(common) - subCommitsController := controllers.NewSubCommitsController(common) - - getSavedCommitMessage := func() string { - return gui.State.savedCommitMessage - } - - getCommitMessage := func() string { - return strings.TrimSpace(gui.Views.CommitMessage.TextArea.GetContent()) - } - - setCommitMessage := gui.getSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage }) - - onCommitAttempt := func(message string) { - gui.State.savedCommitMessage = message - gui.Views.CommitMessage.ClearTextArea() - } - - onCommitSuccess := func() { - gui.State.savedCommitMessage = "" - } - - commitMessageController := controllers.NewCommitMessageController( - common, - getCommitMessage, - onCommitAttempt, - onCommitSuccess, - ) - - remoteBranchesController := controllers.NewRemoteBranchesController(common) - - gui.Controllers = Controllers{ - Submodules: submodulesController, - Global: controllers.NewGlobalController(common), - Files: controllers.NewFilesController( - common, - gui.enterSubmodule, - setCommitMessage, - getSavedCommitMessage, - gui.switchToMerge, - ), - Tags: controllers.NewTagsController(common), - LocalCommits: controllers.NewLocalCommitsController(common, syncController.HandlePull), - Remotes: controllers.NewRemotesController( - common, - func(branches []*models.RemoteBranch) { gui.State.Model.RemoteBranches = branches }, - ), - Menu: controllers.NewMenuController(common), - Undo: controllers.NewUndoController(common), - Sync: syncController, - } - - branchesController := controllers.NewBranchesController(common) - gitFlowController := controllers.NewGitFlowController(common) - filesRemoveController := controllers.NewFilesRemoveController(common) - stashController := controllers.NewStashController(common) - commitFilesController := controllers.NewCommitFilesController(common) - - switchToSubCommitsControllerFactory := controllers.NewSubCommitsSwitchControllerFactory( - common, - func(commits []*models.Commit) { gui.State.Model.SubCommits = commits }, - ) - - for _, context := range []controllers.ContextWithRefName{ - gui.State.Contexts.Branches, - gui.State.Contexts.RemoteBranches, - gui.State.Contexts.Tags, - } { - controllers.AttachControllers(context, switchToSubCommitsControllerFactory.Create(context)) - } - - commitishControllerFactory := controllers.NewCommitishControllerFactory( - common, - gui.SwitchToCommitFilesContext, - ) - - for _, context := range []controllers.Commitish{ - gui.State.Contexts.LocalCommits, - gui.State.Contexts.ReflogCommits, - gui.State.Contexts.SubCommits, - gui.State.Contexts.Stash, - } { - controllers.AttachControllers(context, commitishControllerFactory.Create(context)) - } - - controllers.AttachControllers(gui.State.Contexts.Branches, branchesController, gitFlowController) - controllers.AttachControllers(gui.State.Contexts.Files, gui.Controllers.Files, filesRemoveController) - controllers.AttachControllers(gui.State.Contexts.Tags, gui.Controllers.Tags) - controllers.AttachControllers(gui.State.Contexts.Submodules, gui.Controllers.Submodules) - controllers.AttachControllers(gui.State.Contexts.LocalCommits, gui.Controllers.LocalCommits, bisectController) - controllers.AttachControllers(gui.State.Contexts.ReflogCommits, reflogController) - controllers.AttachControllers(gui.State.Contexts.SubCommits, subCommitsController) - controllers.AttachControllers(gui.State.Contexts.CommitFiles, commitFilesController) - controllers.AttachControllers(gui.State.Contexts.Remotes, gui.Controllers.Remotes) - controllers.AttachControllers(gui.State.Contexts.Stash, stashController) - controllers.AttachControllers(gui.State.Contexts.Menu, gui.Controllers.Menu) - controllers.AttachControllers(gui.State.Contexts.CommitMessage, commitMessageController) - controllers.AttachControllers(gui.State.Contexts.RemoteBranches, remoteBranchesController) - controllers.AttachControllers(gui.State.Contexts.Global, gui.Controllers.Sync, gui.Controllers.Undo, gui.Controllers.Global) - - listControllerFactory := controllers.NewListControllerFactory(gui.c) - for _, context := range gui.getListContexts() { - controllers.AttachControllers(context, listControllerFactory.Create(context)) - } -} - var RuneReplacements = map[rune]string{ // for the commit graph graph.MergeSymbol: "M", diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 4b0fcd99a..12ceff538 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -365,14 +365,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Handler: self.handleShowAllBranchLogs, Description: self.c.Tr.LcAllBranchesLogGraph, }, - { - ViewName: "files", - Contexts: []string{string(context.FILES_CONTEXT_KEY)}, - Key: opts.GetKey(opts.Config.Files.ViewResetOptions), - Handler: self.handleCreateResetMenu, - Description: self.c.Tr.LcViewResetOptions, - OpensMenu: true, - }, { ViewName: "files", Contexts: []string{string(context.FILES_CONTEXT_KEY)}, diff --git a/pkg/gui/workspace_reset_options_panel.go b/pkg/gui/workspace_reset_options_panel.go deleted file mode 100644 index 97984029f..000000000 --- a/pkg/gui/workspace_reset_options_panel.go +++ /dev/null @@ -1,106 +0,0 @@ -package gui - -import ( - "fmt" - - "github.com/jesseduffield/lazygit/pkg/gui/style" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - -func (gui *Gui) handleCreateResetMenu() error { - red := style.FgRed - - nukeStr := "reset --hard HEAD && git clean -fd" - if len(gui.State.Model.Submodules) > 0 { - nukeStr = fmt.Sprintf("%s (%s)", nukeStr, gui.c.Tr.LcAndResetSubmodules) - } - - menuItems := []*types.MenuItem{ - { - DisplayStrings: []string{ - gui.c.Tr.LcDiscardAllChangesToAllFiles, - red.Sprint(nukeStr), - }, - OnPress: func() error { - gui.c.LogAction(gui.c.Tr.Actions.NukeWorkingTree) - if err := gui.git.WorkingTree.ResetAndClean(); err != nil { - return gui.c.Error(err) - } - - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) - }, - }, - { - DisplayStrings: []string{ - gui.c.Tr.LcDiscardAnyUnstagedChanges, - red.Sprint("git checkout -- ."), - }, - OnPress: func() error { - gui.c.LogAction(gui.c.Tr.Actions.DiscardUnstagedFileChanges) - if err := gui.git.WorkingTree.DiscardAnyUnstagedFileChanges(); err != nil { - return gui.c.Error(err) - } - - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) - }, - }, - { - DisplayStrings: []string{ - gui.c.Tr.LcDiscardUntrackedFiles, - red.Sprint("git clean -fd"), - }, - OnPress: func() error { - gui.c.LogAction(gui.c.Tr.Actions.RemoveUntrackedFiles) - if err := gui.git.WorkingTree.RemoveUntrackedFiles(); err != nil { - return gui.c.Error(err) - } - - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) - }, - }, - { - DisplayStrings: []string{ - gui.c.Tr.LcSoftReset, - red.Sprint("git reset --soft HEAD"), - }, - OnPress: func() error { - gui.c.LogAction(gui.c.Tr.Actions.SoftReset) - if err := gui.git.WorkingTree.ResetSoft("HEAD"); err != nil { - return gui.c.Error(err) - } - - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) - }, - }, - { - DisplayStrings: []string{ - "mixed reset", - red.Sprint("git reset --mixed HEAD"), - }, - OnPress: func() error { - gui.c.LogAction(gui.c.Tr.Actions.MixedReset) - if err := gui.git.WorkingTree.ResetMixed("HEAD"); err != nil { - return gui.c.Error(err) - } - - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) - }, - }, - { - DisplayStrings: []string{ - gui.c.Tr.LcHardReset, - red.Sprint("git reset --hard HEAD"), - }, - OnPress: func() error { - gui.c.LogAction(gui.c.Tr.Actions.HardReset) - if err := gui.git.WorkingTree.ResetHard("HEAD"); err != nil { - return gui.c.Error(err) - } - - return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.FILES}}) - }, - }, - } - - return gui.c.Menu(types.CreateMenuOptions{Title: "", Items: menuItems}) -} From 1ad4518d358914b0bae4d96153a9186090fb0d47 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 26 Feb 2022 19:35:30 +1100 Subject: [PATCH 090/385] update cheatsheet --- docs/keybindings/Keybindings_en.md | 8 ++++---- docs/keybindings/Keybindings_nl.md | 5 ++++- docs/keybindings/Keybindings_pl.md | 8 ++++---- docs/keybindings/Keybindings_zh.md | 8 ++++---- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index 542d94516..9b613792b 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -63,14 +63,14 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Branches Panel (Remote Branches (in Remotes tab)) - esc: Return to remotes list - g: view reset options space: checkout n: new branch M: merge into currently checked out branch - d: delete branch r: rebase checked-out branch onto this branch + d: delete branch u: set as upstream of checked-out branch + esc: Return to remotes list + g: view reset options enter: view commits@@ -178,7 +178,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Files Panel (Files)- D: view reset options ctrl+o: copy the file name to the clipboard ctrl+w: Toggle whether or not whitespace changes are shown in the diff view d: view 'discard changes' options @@ -197,6 +196,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct a: stage/unstage all enter: stage individual hunks/lines for file, or collapse/expand for directory g: view upstream reset options + D: view reset options `: toggle file tree view M: open external merge tool (git mergetool) f: fetch diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index a1216b853..734f7135d 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -69,9 +69,11 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct space: uitchecken n: nieuwe branch M: merge in met huidige checked out branch - d: verwijder branch r: rebase branch + d: verwijder branch u: stel in als upstream van uitgecheckte branch + esc: Ga terug naar remotes lijst + g: bekijk reset opties enter: bekijk commits@@ -192,6 +194,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct a: toggle staged alle enter: stage individuele hunks/lijnen g: bekijk upstream reset opties + D: bekijk reset opties `: toggle bestandsboom weergave M: open external merge tool (git mergetool) f: fetch diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index 8d877f282..8dd8ff8aa 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -63,14 +63,14 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Ga艂臋zie Panel (Remote Branches (in Remotes tab))- esc: wr贸膰 do listy repozytori贸w zdalnych - g: wy艣wietl opcje resetu space: prze艂膮cz n: nowa ga艂膮藕 M: scal do obecnej ga艂臋zi - d: usu艅 ga艂膮藕 r: zmiana bazy ga艂臋zi + d: usu艅 ga艂膮藕 u: set as upstream of checked-out branch + esc: wr贸膰 do listy repozytori贸w zdalnych + g: wy艣wietl opcje resetu enter: view commits@@ -178,7 +178,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Pliki Panel (Pliki)- D: wy艣wietl opcje resetu ctrl+o: copy the file name to the clipboard ctrl+w: Toggle whether or not whitespace changes are shown in the diff view d: poka偶 opcje porzucania zmian @@ -197,6 +196,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct a: prze艂膮cz stan poczekalni wszystkich enter: zatwierd藕 pojedyncze linie g: view upstream reset options + D: wy艣wietl opcje resetu `: toggle file tree view M: open external merge tool (git mergetool) f: pobierz diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index f718aa89f..34a60a0e5 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -63,14 +63,14 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## 鍒嗘敮 闈㈡澘 (杩滅▼鍒嗘敮锛堝湪杩滅▼椤甸潰涓級)diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index c075a7879..12b9a90f7 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -123,6 +123,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct o: 鎵撳紑鏂囦欢 e: 缂栬緫鏂囦欢 space: 琛ヤ竵涓寘鍚殑鍒囨崲鏂囦欢 + a: toggle all files included in patch enter: 杈撳叆鏂囦欢浠ュ皢鎵閫夎娣诲姞鍒拌ˉ涓佷腑锛堟垨鍒囨崲鐩綍鎶樺彔锛 `: 鍒囨崲鏂囦欢鏍戣鍥- esc: 杩斿洖杩滅▼浠撳簱鍒楄〃 - g: 鏌ョ湅閲嶇疆閫夐」 space: 妫鍑 n: 鏂板垎鏀 M: 鍚堝苟鍒板綋鍓嶆鍑虹殑鍒嗘敮 - d: 鍒犻櫎鍒嗘敮 r: 灏嗗凡妫鍑虹殑鍒嗘敮鍙樺熀鍒拌鍒嗘敮 + d: 鍒犻櫎鍒嗘敮 u: 璁剧疆涓烘鍑哄垎鏀殑涓婃父 + esc: 杩斿洖杩滅▼浠撳簱鍒楄〃 + g: 鏌ョ湅閲嶇疆閫夐」 enter: 鏌ョ湅鎻愪氦@@ -178,7 +178,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## 鏂囦欢 闈㈡澘 (鏂囦欢)- D: 鏌ョ湅閲嶇疆閫夐」 ctrl+o: 灏嗘枃浠跺悕澶嶅埗鍒板壀璐存澘 ctrl+w: 鍒囨崲鏄惁鍦ㄥ樊寮傝鍥句腑鏄剧ず绌虹櫧鏇存敼 d: 鏌ョ湅'鏀惧純鏇存敼鈥橀夐」 @@ -197,6 +196,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct a: 鍒囨崲鎵鏈夋枃浠剁殑鏆傚瓨鐘舵 enter: 鏆傚瓨鍗曚釜 鍧/琛 鐢ㄤ簬鏂囦欢, 鎴 鎶樺彔/灞曞紑 鐩綍 g: 鏌ョ湅涓婃父閲嶇疆閫夐」 + D: 鏌ョ湅閲嶇疆閫夐」 `: 鍒囨崲鏂囦欢鏍戣鍥 M: 鎵撳紑鍚堝苟宸ュ叿 f: 鎶撳彇 From c7b03bd3c2958cb6f08c1da8ea96749f6f91b8ad Mon Sep 17 00:00:00 2001 From: Jesse Duffield-## Status Panel +## Status Panel (Status)Date: Sat, 26 Feb 2022 19:39:39 +1100 Subject: [PATCH 091/385] rename handlers --- .../controllers/local_commits_controller.go | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index b905e948e..d8c257cb9 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -73,32 +73,32 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ }, { Key: opts.GetKey(opts.Config.Commits.CreateFixupCommit), - Handler: self.checkSelected(self.handleCreateFixupCommit), + Handler: self.checkSelected(self.createFixupCommit), Description: self.c.Tr.LcCreateFixupCommit, }, { Key: opts.GetKey(opts.Config.Commits.SquashAboveCommits), - Handler: self.checkSelected(self.handleSquashAllAboveFixupCommits), + Handler: self.checkSelected(self.squashAllAboveFixupCommits), Description: self.c.Tr.LcSquashAboveCommits, }, { Key: opts.GetKey(opts.Config.Commits.MoveDownCommit), - Handler: self.checkSelected(self.handleCommitMoveDown), + Handler: self.checkSelected(self.moveDown), Description: self.c.Tr.LcMoveDownCommit, }, { Key: opts.GetKey(opts.Config.Commits.MoveUpCommit), - Handler: self.checkSelected(self.handleCommitMoveUp), + Handler: self.checkSelected(self.moveUp), Description: self.c.Tr.LcMoveUpCommit, }, { Key: opts.GetKey(opts.Config.Commits.AmendToCommit), - Handler: self.checkSelected(self.handleCommitAmendTo), + Handler: self.checkSelected(self.amendTo), Description: self.c.Tr.LcAmendToCommit, }, { Key: opts.GetKey(opts.Config.Commits.RevertCommit), - Handler: self.checkSelected(self.handleCommitRevert), + Handler: self.checkSelected(self.revert), Description: self.c.Tr.LcRevertCommit, }, { @@ -155,27 +155,27 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ }, { Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), - Handler: self.checkSelected(self.handleCreateCommitResetMenu), + Handler: self.checkSelected(self.createResetMenu), Description: self.c.Tr.LcResetToThisCommit, }, { Key: opts.GetKey(opts.Config.Commits.CheckoutCommit), - Handler: self.checkSelected(self.handleCheckoutCommit), + Handler: self.checkSelected(self.checkout), Description: self.c.Tr.LcCheckoutCommit, }, { Key: opts.GetKey(opts.Config.Commits.TagCommit), - Handler: self.checkSelected(self.handleTagCommit), + Handler: self.checkSelected(self.createTag), Description: self.c.Tr.LcTagCommit, }, { Key: opts.GetKey(opts.Config.Commits.CopyCommitMessageToClipboard), - Handler: self.checkSelected(self.handleCopySelectedCommitMessageToClipboard), + Handler: self.checkSelected(self.copyCommitMessageToClipboard), Description: self.c.Tr.LcCopyCommitMessageToClipboard, }, { Key: opts.GetKey(opts.Config.Commits.OpenInBrowser), - Handler: self.checkSelected(self.handleOpenCommitInBrowser), + Handler: self.checkSelected(self.openInBrowser), Description: self.c.Tr.LcOpenCommitInBrowser, }, }...) @@ -208,7 +208,7 @@ func (self *LocalCommitsController) squashDown(commit *models.Commit) error { }) } -func (self *LocalCommitsController) fixup(commit *models.Commit) error { +func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) error { if len(self.model.Commits) <= 1 { return self.c.ErrorMsg(self.c.Tr.YouNoCommitsToSquash) } @@ -373,7 +373,7 @@ func (self *LocalCommitsController) handleMidRebaseCommand(action string, commit }) } -func (self *LocalCommitsController) handleCommitMoveDown(commit *models.Commit) error { +func (self *LocalCommitsController) moveDown(commit *models.Commit) error { index := self.context().GetSelectedLineIdx() commits := self.model.Commits if commit.Status == "rebasing" { @@ -405,7 +405,7 @@ func (self *LocalCommitsController) handleCommitMoveDown(commit *models.Commit) }) } -func (self *LocalCommitsController) handleCommitMoveUp(commit *models.Commit) error { +func (self *LocalCommitsController) moveUp(commit *models.Commit) error { index := self.context().GetSelectedLineIdx() if index == 0 { return nil @@ -439,7 +439,7 @@ func (self *LocalCommitsController) handleCommitMoveUp(commit *models.Commit) er }) } -func (self *LocalCommitsController) handleCommitAmendTo(commit *models.Commit) error { +func (self *LocalCommitsController) amendTo(commit *models.Commit) error { return self.c.Ask(types.AskOpts{ Title: self.c.Tr.AmendCommitTitle, Prompt: self.c.Tr.AmendCommitPrompt, @@ -453,7 +453,7 @@ func (self *LocalCommitsController) handleCommitAmendTo(commit *models.Commit) e }) } -func (self *LocalCommitsController) handleCommitRevert(commit *models.Commit) error { +func (self *LocalCommitsController) revert(commit *models.Commit) error { if commit.IsMerge() { return self.createRevertMergeCommitMenu(commit) } else { @@ -507,7 +507,7 @@ func (self *LocalCommitsController) afterRevertCommit() error { }) } -func (self *LocalCommitsController) handleCreateFixupCommit(commit *models.Commit) error { +func (self *LocalCommitsController) fixup(commit *models.Commit) error { prompt := utils.ResolvePlaceholderString( self.c.Tr.SureCreateFixupCommit, map[string]string{ @@ -529,7 +529,7 @@ func (self *LocalCommitsController) handleCreateFixupCommit(commit *models.Commi }) } -func (self *LocalCommitsController) handleSquashAllAboveFixupCommits(commit *models.Commit) error { +func (self *LocalCommitsController) squashAllAboveFixupCommits(commit *models.Commit) error { prompt := utils.ResolvePlaceholderString( self.c.Tr.SureSquashAboveCommits, map[string]string{ @@ -550,11 +550,11 @@ func (self *LocalCommitsController) handleSquashAllAboveFixupCommits(commit *mod }) } -func (self *LocalCommitsController) handleTagCommit(commit *models.Commit) error { +func (self *LocalCommitsController) createTag(commit *models.Commit) error { return self.helpers.Tags.CreateTagMenu(commit.Sha, func() {}) } -func (self *LocalCommitsController) handleCheckoutCommit(commit *models.Commit) error { +func (self *LocalCommitsController) checkout(commit *models.Commit) error { return self.c.Ask(types.AskOpts{ Title: self.c.Tr.LcCheckoutCommit, Prompt: self.c.Tr.SureCheckoutThisCommit, @@ -565,7 +565,7 @@ func (self *LocalCommitsController) handleCheckoutCommit(commit *models.Commit) }) } -func (self *LocalCommitsController) handleCreateCommitResetMenu(commit *models.Commit) error { +func (self *LocalCommitsController) createResetMenu(commit *models.Commit) error { return self.helpers.Refs.CreateGitResetMenu(commit.Sha) } @@ -597,7 +597,7 @@ func (self *LocalCommitsController) gotoBottom() error { return nil } -func (self *LocalCommitsController) handleCopySelectedCommitMessageToClipboard(commit *models.Commit) error { +func (self *LocalCommitsController) copyCommitMessageToClipboard(commit *models.Commit) error { message, err := self.git.Commit.GetCommitMessage(commit.Sha) if err != nil { return self.c.Error(err) @@ -696,7 +696,7 @@ func (self *LocalCommitsController) handleOpenLogMenu() error { }) } -func (self *LocalCommitsController) handleOpenCommitInBrowser(commit *models.Commit) error { +func (self *LocalCommitsController) openInBrowser(commit *models.Commit) error { url, err := self.helpers.Host.GetCommitURL(commit.Sha) if err != nil { return self.c.Error(err) From cf00949b85b72e4d4726c127a285b748a6a4ba55 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 27 Feb 2022 10:18:03 +1100 Subject: [PATCH 092/385] fix integration tests --- pkg/gui/controllers/local_commits_controller.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index d8c257cb9..1693f19c3 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -208,7 +208,7 @@ func (self *LocalCommitsController) squashDown(commit *models.Commit) error { }) } -func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) error { +func (self *LocalCommitsController) fixup(commit *models.Commit) error { if len(self.model.Commits) <= 1 { return self.c.ErrorMsg(self.c.Tr.YouNoCommitsToSquash) } @@ -507,7 +507,7 @@ func (self *LocalCommitsController) afterRevertCommit() error { }) } -func (self *LocalCommitsController) fixup(commit *models.Commit) error { +func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) error { prompt := utils.ResolvePlaceholderString( self.c.Tr.SureCreateFixupCommit, map[string]string{ From 59d4df2a4483993eeebaa0e79feb6c62493bcfe0 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 27 Feb 2022 11:42:22 +1100 Subject: [PATCH 093/385] fix click handling --- go.mod | 4 +- go.sum | 4 +- pkg/gui/context/base_context.go | 11 +++ pkg/gui/controllers.go | 1 + pkg/gui/controllers/attach.go | 1 + pkg/gui/controllers/base_controller.go | 4 + pkg/gui/controllers/commitish_controller.go | 4 + .../controllers/commits_files_controller.go | 10 +- pkg/gui/controllers/files_controller.go | 28 +++--- pkg/gui/controllers/list_controller.go | 83 +++++++++++------ .../controllers/local_commits_controller.go | 4 - pkg/gui/controllers/menu_controller.go | 8 +- pkg/gui/controllers/remotes_controller.go | 8 +- .../sub_commits_switch_controller.go | 4 + pkg/gui/controllers/submodules_controller.go | 8 +- pkg/gui/keybindings.go | 7 +- pkg/gui/types/context.go | 6 ++ vendor/github.com/jesseduffield/gocui/gui.go | 34 ++++--- vendor/golang.org/x/sys/unix/ioctl_linux.go | 23 +++++ vendor/golang.org/x/sys/unix/mkerrors.sh | 4 + vendor/golang.org/x/sys/unix/syscall_linux.go | 56 ++++++++++- .../x/sys/unix/syscall_linux_386.go | 8 -- .../x/sys/unix/syscall_linux_alarm.go | 14 +++ .../x/sys/unix/syscall_linux_amd64.go | 1 - .../x/sys/unix/syscall_linux_arm.go | 1 - .../x/sys/unix/syscall_linux_arm64.go | 1 - .../x/sys/unix/syscall_linux_mips64x.go | 1 - .../x/sys/unix/syscall_linux_mipsx.go | 1 - .../x/sys/unix/syscall_linux_ppc.go | 1 - .../x/sys/unix/syscall_linux_ppc64x.go | 1 - .../x/sys/unix/syscall_linux_riscv64.go | 1 - .../x/sys/unix/syscall_linux_s390x.go | 9 -- .../x/sys/unix/syscall_linux_sparc64.go | 1 - vendor/golang.org/x/sys/unix/zerrors_linux.go | 23 ++++- .../golang.org/x/sys/unix/zsyscall_linux.go | 20 ++++ .../x/sys/unix/zsyscall_linux_386.go | 13 ++- .../x/sys/unix/zsyscall_linux_amd64.go | 24 ++--- .../x/sys/unix/zsyscall_linux_arm.go | 11 --- .../x/sys/unix/zsyscall_linux_arm64.go | 11 --- .../x/sys/unix/zsyscall_linux_mips.go | 24 ++--- .../x/sys/unix/zsyscall_linux_mips64.go | 24 ++--- .../x/sys/unix/zsyscall_linux_mips64le.go | 11 --- .../x/sys/unix/zsyscall_linux_mipsle.go | 24 ++--- .../x/sys/unix/zsyscall_linux_ppc.go | 24 ++--- .../x/sys/unix/zsyscall_linux_ppc64.go | 24 ++--- .../x/sys/unix/zsyscall_linux_ppc64le.go | 24 ++--- .../x/sys/unix/zsyscall_linux_riscv64.go | 11 --- .../x/sys/unix/zsyscall_linux_s390x.go | 13 ++- .../x/sys/unix/zsyscall_linux_sparc64.go | 24 ++--- vendor/golang.org/x/sys/unix/ztypes_linux.go | 93 +++++++++++++++++++ .../x/sys/unix/ztypes_linux_s390x.go | 4 +- vendor/modules.txt | 4 +- 52 files changed, 499 insertions(+), 259 deletions(-) create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_alarm.go diff --git a/go.mod b/go.mod index 0cde50810..5a3dcd387 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/imdario/mergo v0.3.11 github.com/integrii/flaggy v1.4.0 github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 - github.com/jesseduffield/gocui v0.3.1-0.20220131110921-82fe47ec96ba + github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e github.com/jesseduffield/yaml v2.1.0+incompatible github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 @@ -42,7 +42,7 @@ require ( github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // indirect golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect - golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect + golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0 ) diff --git a/go.sum b/go.sum index 1b3593e93..3b11f219b 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,8 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= -github.com/jesseduffield/gocui v0.3.1-0.20220131110921-82fe47ec96ba h1:5czcvu7MjSzrS12qPCLhh6yiE2eRz+tZCybH7Q85TpM= -github.com/jesseduffield/gocui v0.3.1-0.20220131110921-82fe47ec96ba/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU= +github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 h1:9N08i5kjvOfkzMj6THmIM110wPTQLdVYEOHMHT2DFiI= +github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU= github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U= github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e/go.mod h1:u60qdFGXRd36jyEXxetz0vQceQIxzI13lIo3EFUDf4I= github.com/jesseduffield/yaml v2.1.0+incompatible h1:HWQJ1gIv2zHKbDYNp0Jwjlj24K8aqpFHnMCynY1EpmE= diff --git a/pkg/gui/context/base_context.go b/pkg/gui/context/base_context.go index b4beb293d..9b006662f 100644 --- a/pkg/gui/context/base_context.go +++ b/pkg/gui/context/base_context.go @@ -14,6 +14,7 @@ type BaseContext struct { keybindingsFns []types.KeybindingsFn mouseKeybindingsFns []types.MouseKeybindingsFn + onClickFn func() error focusable bool @@ -90,6 +91,16 @@ func (self *BaseContext) AddMouseKeybindingsFn(fn types.MouseKeybindingsFn) { self.mouseKeybindingsFns = append(self.mouseKeybindingsFns, fn) } +func (self *BaseContext) AddOnClickFn(fn func() error) { + if fn != nil { + self.onClickFn = fn + } +} + +func (self *BaseContext) GetOnClick() func() error { + return self.onClickFn +} + func (self *BaseContext) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { bindings := []*gocui.ViewMouseBinding{} for i := range self.mouseKeybindingsFns { diff --git a/pkg/gui/controllers.go b/pkg/gui/controllers.go index 0755bbe8e..04abf1103 100644 --- a/pkg/gui/controllers.go +++ b/pkg/gui/controllers.go @@ -173,6 +173,7 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(gui.State.Contexts.RemoteBranches, remoteBranchesController) controllers.AttachControllers(gui.State.Contexts.Global, gui.Controllers.Sync, gui.Controllers.Undo, gui.Controllers.Global) + // this must come last so that we've got our click handlers defined against the context listControllerFactory := controllers.NewListControllerFactory(gui.c) for _, context := range gui.getListContexts() { controllers.AttachControllers(context, listControllerFactory.Create(context)) diff --git a/pkg/gui/controllers/attach.go b/pkg/gui/controllers/attach.go index 008c15505..3e621c54c 100644 --- a/pkg/gui/controllers/attach.go +++ b/pkg/gui/controllers/attach.go @@ -6,5 +6,6 @@ func AttachControllers(context types.Context, controllers ...types.IController) for _, controller := range controllers { context.AddKeybindingsFn(controller.GetKeybindings) context.AddMouseKeybindingsFn(controller.GetMouseKeybindings) + context.AddOnClickFn(controller.GetOnClick()) } } diff --git a/pkg/gui/controllers/base_controller.go b/pkg/gui/controllers/base_controller.go index e510c1a9f..db7ad7a40 100644 --- a/pkg/gui/controllers/base_controller.go +++ b/pkg/gui/controllers/base_controller.go @@ -14,3 +14,7 @@ func (self *baseController) GetKeybindings(opts types.KeybindingsOpts) []*types. func (self *baseController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { return nil } + +func (self *baseController) GetOnClick() func() error { + return nil +} diff --git a/pkg/gui/controllers/commitish_controller.go b/pkg/gui/controllers/commitish_controller.go index b570e4aba..04e271253 100644 --- a/pkg/gui/controllers/commitish_controller.go +++ b/pkg/gui/controllers/commitish_controller.go @@ -58,6 +58,10 @@ func (self *CommitishController) GetKeybindings(opts types.KeybindingsOpts) []*t return bindings } +func (self *CommitishController) GetOnClick() func() error { + return self.checkSelected(self.enter) +} + func (self *CommitishController) checkSelected(callback func(string) error) func() error { return func() error { refName := self.context.GetSelectedRefName() diff --git a/pkg/gui/controllers/commits_files_controller.go b/pkg/gui/controllers/commits_files_controller.go index 5eed10883..d0015faff 100644 --- a/pkg/gui/controllers/commits_files_controller.go +++ b/pkg/gui/controllers/commits_files_controller.go @@ -70,9 +70,10 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) [] func (self *CommitFilesController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { return []*gocui.ViewMouseBinding{ { - ViewName: "main", - Key: gocui.MouseLeft, - Handler: self.onClickMain, + ViewName: "main", + Key: gocui.MouseLeft, + Handler: self.onClickMain, + FromContext: string(self.context().GetKey()), }, } } @@ -97,12 +98,11 @@ func (self *CommitFilesController) context() *context.CommitFilesContext { } func (self *CommitFilesController) onClickMain(opts gocui.ViewMouseBindingOpts) error { - clickedViewLineIdx := opts.Cy + opts.Oy node := self.context().GetSelectedFileNode() if node == nil { return nil } - return self.enterCommitFile(node, types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: clickedViewLineIdx}) + return self.enterCommitFile(node, types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: opts.Y}) } func (self *CommitFilesController) checkout(node *filetree.CommitFileNode) error { diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index 5f6ccec7e..b10efc15c 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -50,10 +50,6 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types Handler: self.checkSelectedFileNode(self.press), Description: self.c.Tr.LcToggleStaged, }, - // { - // Key: gocui.MouseLeft, - // Handler: func() error { return self.context().HandleClick(self.checkSelectedFileNode(self.press)) }, - // }, { Key: opts.GetKey(" "), // TODO: softcode Handler: self.handleStatusFilterPressed, @@ -153,18 +149,24 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types func (self *FilesController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { return []*gocui.ViewMouseBinding{ { - ViewName: "main", - Key: gocui.MouseLeft, - Handler: self.onClickMain, + ViewName: "main", + Key: gocui.MouseLeft, + Handler: self.onClickMain, + FromContext: string(self.context().GetKey()), }, { - ViewName: "secondary", - Key: gocui.MouseLeft, - Handler: self.onClickSecondary, + ViewName: "secondary", + Key: gocui.MouseLeft, + Handler: self.onClickSecondary, + FromContext: string(self.context().GetKey()), }, } } +func (self *FilesController) GetOnClick() func() error { + return self.checkSelectedFileNode(self.press) +} + func (self *FilesController) press(node *filetree.FileNode) error { if node.IsLeaf() { file := node.File @@ -631,13 +633,11 @@ func (self *FilesController) handleStashSave(stashFunc func(message string) erro } func (self *FilesController) onClickMain(opts gocui.ViewMouseBindingOpts) error { - clickedViewLineIdx := opts.Cy + opts.Oy - return self.EnterFile(types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: clickedViewLineIdx}) + return self.EnterFile(types.OnFocusOpts{ClickedViewName: "main", ClickedViewLineIdx: opts.Y}) } func (self *FilesController) onClickSecondary(opts gocui.ViewMouseBindingOpts) error { - clickedViewLineIdx := opts.Cy + opts.Oy - return self.EnterFile(types.OnFocusOpts{ClickedViewName: "secondary", ClickedViewLineIdx: clickedViewLineIdx}) + return self.EnterFile(types.OnFocusOpts{ClickedViewName: "secondary", ClickedViewLineIdx: opts.Y}) } func (self *FilesController) fetch() error { diff --git a/pkg/gui/controllers/list_controller.go b/pkg/gui/controllers/list_controller.go index 5b1d2e04a..c9898f908 100644 --- a/pkg/gui/controllers/list_controller.go +++ b/pkg/gui/controllers/list_controller.go @@ -61,6 +61,10 @@ func (self *ListController) handleLineChange(change int) error { self.context.GetList().MoveSelectedLine(change) after := self.context.GetList().GetSelectedLineIdx() + if err := self.pushContextIfNotFocused(); err != nil { + return err + } + // doing this check so that if we're holding the up key at the start of the list // we're not constantly re-rendering the main view. if before != after { @@ -86,20 +90,13 @@ func (self *ListController) HandleGotoBottom() error { return self.handleLineChange(self.context.GetList().GetItemsLength()) } -func (self *ListController) HandleClick(onClick func() error) error { +func (self *ListController) HandleClick(opts gocui.ViewMouseBindingOpts) error { prevSelectedLineIdx := self.context.GetList().GetSelectedLineIdx() - // because we're handling a click, we need to determine the new line idx based - // on the view itself. - newSelectedLineIdx := self.context.GetViewTrait().SelectedLineIdx() + newSelectedLineIdx := opts.Y + alreadyFocused := self.isFocused() - currentContextKey := self.c.CurrentContext().GetKey() - alreadyFocused := currentContextKey == self.context.GetKey() - - // we need to focus the view - if !alreadyFocused { - if err := self.c.PushContext(self.context); err != nil { - return err - } + if err := self.pushContextIfNotFocused(); err != nil { + return err } if newSelectedLineIdx > self.context.GetList().GetItemsLength()-1 { @@ -108,26 +105,37 @@ func (self *ListController) HandleClick(onClick func() error) error { self.context.GetList().SetSelectedLineIdx(newSelectedLineIdx) - if prevSelectedLineIdx == newSelectedLineIdx && alreadyFocused && onClick != nil { - return onClick() + if prevSelectedLineIdx == newSelectedLineIdx && alreadyFocused && self.context.GetOnClick() != nil { + return self.context.GetOnClick()() } return self.context.HandleFocus() } +func (self *ListController) pushContextIfNotFocused() error { + if !self.isFocused() { + if err := self.c.PushContext(self.context); err != nil { + return err + } + } + + return nil +} + +func (self *ListController) isFocused() bool { + return self.c.CurrentContext().GetKey() == self.context.GetKey() +} + func (self *ListController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { return []*types.Binding{ - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: gocui.MouseWheelUp, Modifier: gocui.ModNone, Handler: self.HandlePrevLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItem), Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevPage), Modifier: gocui.ModNone, Handler: self.HandlePrevPage, Description: self.c.Tr.LcPrevPage}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextPage), Modifier: gocui.ModNone, Handler: self.HandleNextPage, Description: self.c.Tr.LcNextPage}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Modifier: gocui.ModNone, Handler: self.HandleGotoTop, Description: self.c.Tr.LcGotoTop}, - {Key: gocui.MouseLeft, Modifier: gocui.ModNone, Handler: func() error { return self.HandleClick(nil) }}, - {Tag: "navigation", Key: gocui.MouseWheelDown, Modifier: gocui.ModNone, Handler: self.HandleNextLine}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Modifier: gocui.ModNone, Handler: self.HandleScrollLeft}, - {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollRight), Modifier: gocui.ModNone, Handler: self.HandleScrollRight}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Handler: self.HandlePrevLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Handler: self.HandlePrevLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Handler: self.HandleNextLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItem), Handler: self.HandleNextLine}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevPage), Handler: self.HandlePrevPage, Description: self.c.Tr.LcPrevPage}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextPage), Handler: self.HandleNextPage, Description: self.c.Tr.LcNextPage}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Handler: self.HandleGotoTop, Description: self.c.Tr.LcGotoTop}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Handler: self.HandleScrollLeft}, + {Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollRight), Handler: self.HandleScrollRight}, { Key: opts.GetKey(opts.Config.Universal.StartSearch), Handler: func() error { self.c.OpenSearch(); return nil }, @@ -142,3 +150,26 @@ func (self *ListController) GetKeybindings(opts types.KeybindingsOpts) []*types. }, } } + +func (self *ListController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { + return []*gocui.ViewMouseBinding{ + { + ViewName: self.context.GetViewName(), + ToContext: string(self.context.GetKey()), + Key: gocui.MouseWheelUp, + Handler: func(gocui.ViewMouseBindingOpts) error { return self.HandlePrevLine() }, + }, + { + ViewName: self.context.GetViewName(), + ToContext: string(self.context.GetKey()), + Key: gocui.MouseLeft, + Handler: func(opts gocui.ViewMouseBindingOpts) error { return self.HandleClick(opts) }, + }, + { + ViewName: self.context.GetViewName(), + ToContext: string(self.context.GetKey()), + Key: gocui.MouseWheelDown, + Handler: func(gocui.ViewMouseBindingOpts) error { return self.HandleNextLine() }, + }, + } +} diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index 1693f19c3..b54cfa3c0 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -136,10 +136,6 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ Description: self.c.Tr.LcGotoBottom, Tag: "navigation", }, - // { - // Key: gocui.MouseLeft, - // Handler: func() error { return self.context().HandleClick(self.checkSelected(self.enter)) }, - // }, } for _, binding := range outsideFilterModeBindings { diff --git a/pkg/gui/controllers/menu_controller.go b/pkg/gui/controllers/menu_controller.go index 91e85dec5..f217c993a 100644 --- a/pkg/gui/controllers/menu_controller.go +++ b/pkg/gui/controllers/menu_controller.go @@ -35,15 +35,15 @@ func (self *MenuController) GetKeybindings(opts types.KeybindingsOpts) []*types. Key: opts.GetKey(opts.Config.Universal.ConfirmAlt1), Handler: self.press, }, - // { - // Key: gocui.MouseLeft, - // Handler: func() error { return self.context.HandleClick(self.press) }, - // }, } return bindings } +func (self *MenuController) GetOnClick() func() error { + return self.press +} + func (self *MenuController) press() error { selectedItem := self.context().GetSelected() diff --git a/pkg/gui/controllers/remotes_controller.go b/pkg/gui/controllers/remotes_controller.go index 489454f89..fd4b34297 100644 --- a/pkg/gui/controllers/remotes_controller.go +++ b/pkg/gui/controllers/remotes_controller.go @@ -35,10 +35,6 @@ func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*typ Key: opts.GetKey(opts.Config.Universal.GoInto), Handler: self.checkSelected(self.enter), }, - // { - // Key: gocui.MouseLeft, - // Handler: func() error { return self.context.HandleClick(self.checkSelected(self.enter)) }, - // }, { Key: opts.GetKey(opts.Config.Branches.FetchRemote), Handler: self.checkSelected(self.fetch), @@ -64,6 +60,10 @@ func (self *RemotesController) GetKeybindings(opts types.KeybindingsOpts) []*typ return bindings } +func (self *RemotesController) GetOnClick() func() error { + return self.checkSelected(self.enter) +} + func (self *RemotesController) enter(remote *models.Remote) error { // naive implementation: get the branches from the remote and render them to the list, change the context self.setRemoteBranches(remote.Branches) diff --git a/pkg/gui/controllers/sub_commits_switch_controller.go b/pkg/gui/controllers/sub_commits_switch_controller.go index cbc9ce137..4c8f086a5 100644 --- a/pkg/gui/controllers/sub_commits_switch_controller.go +++ b/pkg/gui/controllers/sub_commits_switch_controller.go @@ -57,6 +57,10 @@ func (self *SubCommitsSwitchController) GetKeybindings(opts types.KeybindingsOpt return bindings } +func (self *SubCommitsSwitchController) GetOnClick() func() error { + return self.viewCommits +} + func (self *SubCommitsSwitchController) viewCommits() error { refName := self.context.GetSelectedRefName() if refName == "" { diff --git a/pkg/gui/controllers/submodules_controller.go b/pkg/gui/controllers/submodules_controller.go index 408536960..83c05da4b 100644 --- a/pkg/gui/controllers/submodules_controller.go +++ b/pkg/gui/controllers/submodules_controller.go @@ -69,13 +69,13 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []* Description: self.c.Tr.LcViewBulkSubmoduleOptions, OpensMenu: true, }, - // { - // Key: gocui.MouseLeft, - // Handler: func() error { return self.context().HandleClick(self.checkSelected(self.enter)) }, - // }, } } +func (self *SubmodulesController) GetOnClick() func() error { + return self.checkSelected(self.enter) +} + func (self *SubmodulesController) enter(submodule *models.SubmoduleConfig) error { return self.enterSubmodule(submodule) } diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 12ceff538..d6a586a10 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -988,12 +988,7 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi bindings = append(bindings, binding) } - for _, binding := range c.GetMouseKeybindings(opts) { - if contextKey != context.GLOBAL_CONTEXT_KEY { - binding.FromContext = string(contextKey) - } - mouseKeybindings = append(mouseKeybindings, binding) - } + mouseKeybindings = append(mouseKeybindings, c.GetMouseKeybindings(opts)...) } for _, viewName := range []string{"status", "branches", "files", "commits", "commitFiles", "stash", "menu"} { diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index ed971d348..5e588da0d 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -38,6 +38,11 @@ type IBaseContext interface { AddKeybindingsFn(KeybindingsFn) AddMouseKeybindingsFn(MouseKeybindingsFn) + + // This is a bit of a hack at the moment: we currently only set an onclick function so that + // our list controller can come along and wrap it in a list-specific click handler. + // We'll need to think of a better way to do this. + AddOnClickFn(func() error) } type Context interface { @@ -94,6 +99,7 @@ type MouseKeybindingsFn func(opts KeybindingsOpts) []*gocui.ViewMouseBinding type HasKeybindings interface { GetKeybindings(opts KeybindingsOpts) []*Binding GetMouseKeybindings(opts KeybindingsOpts) []*gocui.ViewMouseBinding + GetOnClick() func() error } type IController interface { diff --git a/vendor/github.com/jesseduffield/gocui/gui.go b/vendor/github.com/jesseduffield/gocui/gui.go index 1c7829b57..880f9dc93 100644 --- a/vendor/github.com/jesseduffield/gocui/gui.go +++ b/vendor/github.com/jesseduffield/gocui/gui.go @@ -69,6 +69,11 @@ type tabClickBinding struct { handler tabClickHandler } +// TODO: would be good to define inbound and outbound click handlers e.g. +// clicking on a file is an inbound thing where we don't care what context you're +// in when it happens, whereas clicking on the main view from the files view is an +// outbound click with a specific handler. But this requires more thinking about +// where handlers should live. type ViewMouseBinding struct { // the view that is clicked ViewName string @@ -77,6 +82,10 @@ type ViewMouseBinding struct { // of the view we're clicking. If this is blank then it is a global binding. FromContext string + // the context assigned to the clicked view. If blank, then we don't care + // what context is assigned + ToContext string + Handler func(ViewMouseBindingOpts) error // must be a mouse key @@ -84,13 +93,8 @@ type ViewMouseBinding struct { } type ViewMouseBindingOpts struct { - // cursor x/y - Cx int - Cy int - - // origin x/y - Ox int - Oy int + X int // i.e. origin x + cursor x + Y int // i.e. origin y + cursor y } type GuiMutexes struct { @@ -1137,8 +1141,8 @@ func (g *Gui) onKey(ev *GocuiEvent) error { } if ev.Mod == ModNone && IsMouseKey(ev.Key) { - opts := ViewMouseBindingOpts{Cx: newCx, Cy: newCy, Ox: v.ox, Oy: v.oy} - matched, err := g.execMouseKeybindings(v.Name(), ev, opts) + opts := ViewMouseBindingOpts{X: newCx + v.ox, Y: newCy + v.oy} + matched, err := g.execMouseKeybindings(v, ev, opts) if err != nil { return err } @@ -1155,16 +1159,20 @@ func (g *Gui) onKey(ev *GocuiEvent) error { return nil } -func (g *Gui) execMouseKeybindings(viewName string, ev *GocuiEvent, opts ViewMouseBindingOpts) (bool, error) { - // first pass looks for ones that match both the view and the current context +func (g *Gui) execMouseKeybindings(view *View, ev *GocuiEvent, opts ViewMouseBindingOpts) (bool, error) { + isMatch := func(binding *ViewMouseBinding) bool { + return binding.ViewName == view.Name() && ev.Key == binding.Key && (binding.ToContext == "" || binding.ToContext == view.Context) + } + + // first pass looks for ones that match both the view and the from context for _, binding := range g.viewMouseBindings { - if binding.ViewName == viewName && binding.FromContext == g.currentContext && ev.Key == binding.Key { + if isMatch(binding) && binding.FromContext != "" && binding.FromContext == g.currentContext { return true, binding.Handler(opts) } } for _, binding := range g.viewMouseBindings { - if binding.ViewName == viewName && ev.Key == binding.Key { + if isMatch(binding) && binding.FromContext == "" { return true, binding.Handler(opts) } } diff --git a/vendor/golang.org/x/sys/unix/ioctl_linux.go b/vendor/golang.org/x/sys/unix/ioctl_linux.go index 1dadead21..884430b81 100644 --- a/vendor/golang.org/x/sys/unix/ioctl_linux.go +++ b/vendor/golang.org/x/sys/unix/ioctl_linux.go @@ -194,3 +194,26 @@ func ioctlIfreqData(fd int, req uint, value *ifreqData) error { // identical so pass *IfreqData directly. return ioctlPtr(fd, req, unsafe.Pointer(value)) } + +// IoctlKCMClone attaches a new file descriptor to a multiplexor by cloning an +// existing KCM socket, returning a structure containing the file descriptor of +// the new socket. +func IoctlKCMClone(fd int) (*KCMClone, error) { + var info KCMClone + if err := ioctlPtr(fd, SIOCKCMCLONE, unsafe.Pointer(&info)); err != nil { + return nil, err + } + + return &info, nil +} + +// IoctlKCMAttach attaches a TCP socket and associated BPF program file +// descriptor to a multiplexor. +func IoctlKCMAttach(fd int, info KCMAttach) error { + return ioctlPtr(fd, SIOCKCMATTACH, unsafe.Pointer(&info)) +} + +// IoctlKCMUnattach unattaches a TCP socket file descriptor from a multiplexor. +func IoctlKCMUnattach(fd int, info KCMUnattach) error { + return ioctlPtr(fd, SIOCKCMUNATTACH, unsafe.Pointer(&info)) +} diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index a47b035f9..a03708748 100644 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -205,6 +205,7 @@ struct ltchars { #include #include #include +#include #include #include #include @@ -231,6 +232,7 @@ struct ltchars { #include #include #include +#include #include #include #include @@ -503,6 +505,7 @@ ccflags="$@" $2 ~ /^O?XTABS$/ || $2 ~ /^TC[IO](ON|OFF)$/ || $2 ~ /^IN_/ || + $2 ~ /^KCM/ || $2 ~ /^LANDLOCK_/ || $2 ~ /^LOCK_(SH|EX|NB|UN)$/ || $2 ~ /^LO_(KEY|NAME)_SIZE$/ || @@ -597,6 +600,7 @@ ccflags="$@" $2 ~ /^DEVLINK_/ || $2 ~ /^ETHTOOL_/ || $2 ~ /^LWTUNNEL_IP/ || + $2 ~ /^ITIMER_/ || $2 !~ "WMESGLEN" && $2 ~ /^W[A-Z0-9]+$/ || $2 ~/^PPPIOC/ || diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go index f432b0684..5f28f8fde 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -14,6 +14,7 @@ package unix import ( "encoding/binary" "syscall" + "time" "unsafe" ) @@ -249,6 +250,13 @@ func Getwd() (wd string, err error) { if n < 1 || n > len(buf) || buf[n-1] != 0 { return "", EINVAL } + // In some cases, Linux can return a path that starts with the + // "(unreachable)" prefix, which can potentially be a valid relative + // path. To work around that, return ENOENT if path is not absolute. + if buf[0] != '/' { + return "", ENOENT + } + return string(buf[0 : n-1]), nil } @@ -2314,11 +2322,56 @@ type RemoteIovec struct { //sys shmdt(addr uintptr) (err error) //sys shmget(key int, size int, flag int) (id int, err error) +//sys getitimer(which int, currValue *Itimerval) (err error) +//sys setitimer(which int, newValue *Itimerval, oldValue *Itimerval) (err error) + +// MakeItimerval creates an Itimerval from interval and value durations. +func MakeItimerval(interval, value time.Duration) Itimerval { + return Itimerval{ + Interval: NsecToTimeval(interval.Nanoseconds()), + Value: NsecToTimeval(value.Nanoseconds()), + } +} + +// A value which may be passed to the which parameter for Getitimer and +// Setitimer. +type ItimerWhich int + +// Possible which values for Getitimer and Setitimer. +const ( + ItimerReal ItimerWhich = ITIMER_REAL + ItimerVirtual ItimerWhich = ITIMER_VIRTUAL + ItimerProf ItimerWhich = ITIMER_PROF +) + +// Getitimer wraps getitimer(2) to return the current value of the timer +// specified by which. +func Getitimer(which ItimerWhich) (Itimerval, error) { + var it Itimerval + if err := getitimer(int(which), &it); err != nil { + return Itimerval{}, err + } + + return it, nil +} + +// Setitimer wraps setitimer(2) to arm or disarm the timer specified by which. +// It returns the previous value of the timer. +// +// If the Itimerval argument is the zero value, the timer will be disarmed. +func Setitimer(which ItimerWhich, it Itimerval) (Itimerval, error) { + var prev Itimerval + if err := setitimer(int(which), &it, &prev); err != nil { + return Itimerval{}, err + } + + return prev, nil +} + /* * Unimplemented */ // AfsSyscall -// Alarm // ArchPrctl // Brk // ClockNanosleep @@ -2334,7 +2387,6 @@ type RemoteIovec struct { // GetMempolicy // GetRobustList // GetThreadArea -// Getitimer // Getpmsg // IoCancel // IoDestroy diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_386.go b/vendor/golang.org/x/sys/unix/syscall_linux_386.go index 5f757e8aa..d44b8ad53 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_386.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_386.go @@ -173,14 +173,6 @@ const ( _SENDMMSG = 20 ) -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - fd, e := socketcall(_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0) - if e != 0 { - err = e - } - return -} - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { fd, e := socketcall(_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) if e != 0 { diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_alarm.go b/vendor/golang.org/x/sys/unix/syscall_linux_alarm.go new file mode 100644 index 000000000..08086ac6a --- /dev/null +++ b/vendor/golang.org/x/sys/unix/syscall_linux_alarm.go @@ -0,0 +1,14 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && (386 || amd64 || mips || mipsle || mips64 || mipsle || ppc64 || ppc64le || ppc || s390x || sparc64) +// +build linux +// +build 386 amd64 mips mipsle mips64 mipsle ppc64 ppc64le ppc s390x sparc64 + +package unix + +// SYS_ALARM is not defined on arm or riscv, but is available for other GOARCH +// values. + +//sys Alarm(seconds uint) (remaining uint, err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go index 4299125aa..bd21d93bf 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go @@ -62,7 +62,6 @@ func Stat(path string, stat *Stat_t) (err error) { //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys Truncate(path string, length int64) (err error) //sys Ustat(dev int, ubuf *Ustat_t) (err error) -//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) //sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go index 79edeb9cb..343c91f6b 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go @@ -27,7 +27,6 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { return newoffset, nil } -//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) //sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go index 862890de2..8c5628684 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go @@ -66,7 +66,6 @@ func Ustat(dev int, ubuf *Ustat_t) (err error) { return ENOSYS } -//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) //sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go index 8932e34ad..f0b138002 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go @@ -48,7 +48,6 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys Truncate(path string, length int64) (err error) //sys Ustat(dev int, ubuf *Ustat_t) (err error) -//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) //sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go index 7821c25d9..e6163c30f 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go @@ -41,7 +41,6 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64 //sys Ustat(dev int, ubuf *Ustat_t) (err error) -//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) //sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go b/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go index c5053a0f0..4740e80a8 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go @@ -43,7 +43,6 @@ import ( //sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 //sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64 //sys Ustat(dev int, ubuf *Ustat_t) (err error) -//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) //sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go index 25786c421..78bc9166e 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go @@ -45,7 +45,6 @@ package unix //sys Statfs(path string, buf *Statfs_t) (err error) //sys Truncate(path string, length int64) (err error) //sys Ustat(dev int, ubuf *Ustat_t) (err error) -//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) //sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go index 6f9f71041..3d6c4eb06 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go @@ -65,7 +65,6 @@ func Ustat(dev int, ubuf *Ustat_t) (err error) { return ENOSYS } -//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) //sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go index 6aa59cb27..89ce84a41 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go @@ -145,15 +145,6 @@ const ( netSendMMsg = 20 ) -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (int, error) { - args := [3]uintptr{uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))} - fd, _, err := Syscall(SYS_SOCKETCALL, netAccept, uintptr(unsafe.Pointer(&args)), 0) - if err != 0 { - return 0, err - } - return int(fd), nil -} - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (int, error) { args := [4]uintptr{uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags)} fd, _, err := Syscall(SYS_SOCKETCALL, netAccept4, uintptr(unsafe.Pointer(&args)), 0) diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go index bbe8d174f..35bdb098c 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go @@ -42,7 +42,6 @@ package unix //sys Statfs(path string, buf *Statfs_t) (err error) //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys Truncate(path string, length int64) (err error) -//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) //sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go index 4e5420586..bc7c9d075 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -38,7 +38,8 @@ const ( AF_KEY = 0xf AF_LLC = 0x1a AF_LOCAL = 0x1 - AF_MAX = 0x2d + AF_MAX = 0x2e + AF_MCTP = 0x2d AF_MPLS = 0x1c AF_NETBEUI = 0xd AF_NETLINK = 0x10 @@ -259,6 +260,17 @@ const ( BUS_USB = 0x3 BUS_VIRTUAL = 0x6 CAN_BCM = 0x2 + CAN_CTRLMODE_3_SAMPLES = 0x4 + CAN_CTRLMODE_BERR_REPORTING = 0x10 + CAN_CTRLMODE_CC_LEN8_DLC = 0x100 + CAN_CTRLMODE_FD = 0x20 + CAN_CTRLMODE_FD_NON_ISO = 0x80 + CAN_CTRLMODE_LISTENONLY = 0x2 + CAN_CTRLMODE_LOOPBACK = 0x1 + CAN_CTRLMODE_ONE_SHOT = 0x8 + CAN_CTRLMODE_PRESUME_ACK = 0x40 + CAN_CTRLMODE_TDC_AUTO = 0x200 + CAN_CTRLMODE_TDC_MANUAL = 0x400 CAN_EFF_FLAG = 0x80000000 CAN_EFF_ID_BITS = 0x1d CAN_EFF_MASK = 0x1fffffff @@ -336,6 +348,7 @@ const ( CAN_RTR_FLAG = 0x40000000 CAN_SFF_ID_BITS = 0xb CAN_SFF_MASK = 0x7ff + CAN_TERMINATION_DISABLED = 0x0 CAN_TP16 = 0x3 CAN_TP20 = 0x4 CAP_AUDIT_CONTROL = 0x1e @@ -1267,9 +1280,14 @@ const ( IP_XFRM_POLICY = 0x11 ISOFS_SUPER_MAGIC = 0x9660 ISTRIP = 0x20 + ITIMER_PROF = 0x2 + ITIMER_REAL = 0x0 + ITIMER_VIRTUAL = 0x1 IUTF8 = 0x4000 IXANY = 0x800 JFFS2_SUPER_MAGIC = 0x72b6 + KCMPROTO_CONNECTED = 0x0 + KCM_RECV_DISABLE = 0x1 KEXEC_ARCH_386 = 0x30000 KEXEC_ARCH_68K = 0x40000 KEXEC_ARCH_AARCH64 = 0xb70000 @@ -2442,6 +2460,9 @@ const ( SIOCGSTAMPNS = 0x8907 SIOCGSTAMPNS_OLD = 0x8907 SIOCGSTAMP_OLD = 0x8906 + SIOCKCMATTACH = 0x89e0 + SIOCKCMCLONE = 0x89e2 + SIOCKCMUNATTACH = 0x89e1 SIOCOUTQNSD = 0x894b SIOCPROTOPRIVATE = 0x89e0 SIOCRTMSG = 0x890d diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/vendor/golang.org/x/sys/unix/zsyscall_linux.go index 93edda4c4..30fa4055e 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux.go @@ -2032,3 +2032,23 @@ func shmget(key int, size int, flag int) (id int, err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func getitimer(which int, currValue *Itimerval) (err error) { + _, _, e1 := Syscall(SYS_GETITIMER, uintptr(which), uintptr(unsafe.Pointer(currValue)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func setitimer(which int, newValue *Itimerval, oldValue *Itimerval) (err error) { + _, _, e1 := Syscall(SYS_SETITIMER, uintptr(which), uintptr(unsafe.Pointer(newValue)), uintptr(unsafe.Pointer(oldValue))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go index ff90c81e7..2fc6271f4 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go @@ -1,4 +1,4 @@ -// go run mksyscall.go -l32 -tags linux,386 syscall_linux.go syscall_linux_386.go +// go run mksyscall.go -l32 -tags linux,386 syscall_linux.go syscall_linux_386.go syscall_linux_alarm.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build linux && 386 @@ -524,3 +524,14 @@ func utimes(path string, times *[2]Timeval) (err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Alarm(seconds uint) (remaining uint, err error) { + r0, _, e1 := Syscall(SYS_ALARM, uintptr(seconds), 0, 0) + remaining = uint(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go index fa7d3dbe4..43d9f0128 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go @@ -1,4 +1,4 @@ -// go run mksyscall.go -tags linux,amd64 syscall_linux.go syscall_linux_amd64.go +// go run mksyscall.go -tags linux,amd64 syscall_linux.go syscall_linux_amd64.go syscall_linux_alarm.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build linux && amd64 @@ -444,17 +444,6 @@ func Ustat(dev int, ubuf *Ustat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) fd = int(r0) @@ -691,3 +680,14 @@ func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, f } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Alarm(seconds uint) (remaining uint, err error) { + r0, _, e1 := Syscall(SYS_ALARM, uintptr(seconds), 0, 0) + remaining = uint(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go index 654f91530..7df0cb179 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go @@ -46,17 +46,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) fd = int(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go index e893f987f..076e8f1c5 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go @@ -389,17 +389,6 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) fd = int(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go index 6d1552885..7b3c84746 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go @@ -1,4 +1,4 @@ -// go run mksyscall.go -b32 -arm -tags linux,mips syscall_linux.go syscall_linux_mipsx.go +// go run mksyscall.go -b32 -arm -tags linux,mips syscall_linux.go syscall_linux_mipsx.go syscall_linux_alarm.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build linux && mips @@ -344,17 +344,6 @@ func Ustat(dev int, ubuf *Ustat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) fd = int(r0) @@ -702,3 +691,14 @@ func setrlimit(resource int, rlim *rlimit32) (err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Alarm(seconds uint) (remaining uint, err error) { + r0, _, e1 := Syscall(SYS_ALARM, uintptr(seconds), 0, 0) + remaining = uint(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go index 1e20d72df..0d3c45fbd 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go @@ -1,4 +1,4 @@ -// go run mksyscall.go -tags linux,mips64 syscall_linux.go syscall_linux_mips64x.go +// go run mksyscall.go -tags linux,mips64 syscall_linux.go syscall_linux_mips64x.go syscall_linux_alarm.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build linux && mips64 @@ -399,17 +399,6 @@ func Ustat(dev int, ubuf *Ustat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) fd = int(r0) @@ -696,3 +685,14 @@ func stat(path string, st *stat_t) (err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Alarm(seconds uint) (remaining uint, err error) { + r0, _, e1 := Syscall(SYS_ALARM, uintptr(seconds), 0, 0) + remaining = uint(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go index 82b5e2d9e..cb46b2aaa 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go @@ -399,17 +399,6 @@ func Ustat(dev int, ubuf *Ustat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) fd = int(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go index a0440c1d4..21c9baa6a 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go @@ -1,4 +1,4 @@ -// go run mksyscall.go -l32 -arm -tags linux,mipsle syscall_linux.go syscall_linux_mipsx.go +// go run mksyscall.go -l32 -arm -tags linux,mipsle syscall_linux.go syscall_linux_mipsx.go syscall_linux_alarm.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build linux && mipsle @@ -344,17 +344,6 @@ func Ustat(dev int, ubuf *Ustat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) fd = int(r0) @@ -702,3 +691,14 @@ func setrlimit(resource int, rlim *rlimit32) (err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Alarm(seconds uint) (remaining uint, err error) { + r0, _, e1 := Syscall(SYS_ALARM, uintptr(seconds), 0, 0) + remaining = uint(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go index 5864b9ca6..02b8f0887 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go @@ -1,4 +1,4 @@ -// go run mksyscall.go -b32 -tags linux,ppc syscall_linux.go syscall_linux_ppc.go +// go run mksyscall.go -b32 -tags linux,ppc syscall_linux.go syscall_linux_ppc.go syscall_linux_alarm.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build linux && ppc @@ -409,17 +409,6 @@ func Ustat(dev int, ubuf *Ustat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) fd = int(r0) @@ -707,3 +696,14 @@ func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, f } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Alarm(seconds uint) (remaining uint, err error) { + r0, _, e1 := Syscall(SYS_ALARM, uintptr(seconds), 0, 0) + remaining = uint(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go index beeb49e34..ac8cb09ba 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go @@ -1,4 +1,4 @@ -// go run mksyscall.go -tags linux,ppc64 syscall_linux.go syscall_linux_ppc64x.go +// go run mksyscall.go -tags linux,ppc64 syscall_linux.go syscall_linux_ppc64x.go syscall_linux_alarm.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build linux && ppc64 @@ -475,17 +475,6 @@ func Ustat(dev int, ubuf *Ustat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) fd = int(r0) @@ -753,3 +742,14 @@ func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, f } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Alarm(seconds uint) (remaining uint, err error) { + r0, _, e1 := Syscall(SYS_ALARM, uintptr(seconds), 0, 0) + remaining = uint(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go index 53139b82c..bd08d887a 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go @@ -1,4 +1,4 @@ -// go run mksyscall.go -tags linux,ppc64le syscall_linux.go syscall_linux_ppc64x.go +// go run mksyscall.go -tags linux,ppc64le syscall_linux.go syscall_linux_ppc64x.go syscall_linux_alarm.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build linux && ppc64le @@ -475,17 +475,6 @@ func Ustat(dev int, ubuf *Ustat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) fd = int(r0) @@ -753,3 +742,14 @@ func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, f } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Alarm(seconds uint) (remaining uint, err error) { + r0, _, e1 := Syscall(SYS_ALARM, uintptr(seconds), 0, 0) + remaining = uint(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go index 63b393b80..a834d2173 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go @@ -369,17 +369,6 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) fd = int(r0) diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go index 202add37d..9e462a96f 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go @@ -1,4 +1,4 @@ -// go run mksyscall.go -tags linux,s390x syscall_linux.go syscall_linux_s390x.go +// go run mksyscall.go -tags linux,s390x syscall_linux.go syscall_linux_s390x.go syscall_linux_alarm.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build linux && s390x @@ -533,3 +533,14 @@ func kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, f } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Alarm(seconds uint) (remaining uint, err error) { + r0, _, e1 := Syscall(SYS_ALARM, uintptr(seconds), 0, 0) + remaining = uint(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go index 2ab268c34..96d340242 100644 --- a/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go @@ -1,4 +1,4 @@ -// go run mksyscall.go -tags linux,sparc64 syscall_linux.go syscall_linux_sparc64.go +// go run mksyscall.go -tags linux,sparc64 syscall_linux.go syscall_linux_sparc64.go syscall_linux_alarm.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build linux && sparc64 @@ -455,17 +455,6 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { - r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) { r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0) fd = int(r0) @@ -697,3 +686,14 @@ func utimes(path string, times *[2]Timeval) (err error) { } return } + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Alarm(seconds uint) (remaining uint, err error) { + r0, _, e1 := Syscall(SYS_ALARM, uintptr(seconds), 0, 0) + remaining = uint(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go index 66788f156..e6a8d88c5 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -24,6 +24,11 @@ type ItimerSpec struct { Value Timespec } +type Itimerval struct { + Interval Timeval + Value Timeval +} + const ( TIME_OK = 0x0 TIME_INS = 0x1 @@ -4065,3 +4070,91 @@ const ( NL_POLICY_TYPE_ATTR_MASK = 0xc NL_POLICY_TYPE_ATTR_MAX = 0xc ) + +type CANBitTiming struct { + Bitrate uint32 + Sample_point uint32 + Tq uint32 + Prop_seg uint32 + Phase_seg1 uint32 + Phase_seg2 uint32 + Sjw uint32 + Brp uint32 +} + +type CANBitTimingConst struct { + Name [16]uint8 + Tseg1_min uint32 + Tseg1_max uint32 + Tseg2_min uint32 + Tseg2_max uint32 + Sjw_max uint32 + Brp_min uint32 + Brp_max uint32 + Brp_inc uint32 +} + +type CANClock struct { + Freq uint32 +} + +type CANBusErrorCounters struct { + Txerr uint16 + Rxerr uint16 +} + +type CANCtrlMode struct { + Mask uint32 + Flags uint32 +} + +type CANDeviceStats struct { + Bus_error uint32 + Error_warning uint32 + Error_passive uint32 + Bus_off uint32 + Arbitration_lost uint32 + Restarts uint32 +} + +const ( + CAN_STATE_ERROR_ACTIVE = 0x0 + CAN_STATE_ERROR_WARNING = 0x1 + CAN_STATE_ERROR_PASSIVE = 0x2 + CAN_STATE_BUS_OFF = 0x3 + CAN_STATE_STOPPED = 0x4 + CAN_STATE_SLEEPING = 0x5 + CAN_STATE_MAX = 0x6 +) + +const ( + IFLA_CAN_UNSPEC = 0x0 + IFLA_CAN_BITTIMING = 0x1 + IFLA_CAN_BITTIMING_CONST = 0x2 + IFLA_CAN_CLOCK = 0x3 + IFLA_CAN_STATE = 0x4 + IFLA_CAN_CTRLMODE = 0x5 + IFLA_CAN_RESTART_MS = 0x6 + IFLA_CAN_RESTART = 0x7 + IFLA_CAN_BERR_COUNTER = 0x8 + IFLA_CAN_DATA_BITTIMING = 0x9 + IFLA_CAN_DATA_BITTIMING_CONST = 0xa + IFLA_CAN_TERMINATION = 0xb + IFLA_CAN_TERMINATION_CONST = 0xc + IFLA_CAN_BITRATE_CONST = 0xd + IFLA_CAN_DATA_BITRATE_CONST = 0xe + IFLA_CAN_BITRATE_MAX = 0xf +) + +type KCMAttach struct { + Fd int32 + Bpf_fd int32 +} + +type KCMUnattach struct { + Fd int32 +} + +type KCMClone struct { + Fd int32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go index 635880610..c426c3576 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go @@ -210,8 +210,8 @@ type PtraceFpregs struct { } type PtracePer struct { - _ [0]uint64 - _ [32]byte + Control_regs [3]uint64 + _ [8]byte Starting_addr uint64 Ending_addr uint64 Perc_atmid uint16 diff --git a/vendor/modules.txt b/vendor/modules.txt index 417adb1dc..295a15987 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -159,7 +159,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem github.com/jesseduffield/go-git/v5/utils/merkletrie/index github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame github.com/jesseduffield/go-git/v5/utils/merkletrie/noder -# github.com/jesseduffield/gocui v0.3.1-0.20220131110921-82fe47ec96ba +# github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 ## explicit github.com/jesseduffield/gocui # github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e @@ -255,7 +255,7 @@ golang.org/x/crypto/ssh/knownhosts golang.org/x/net/context golang.org/x/net/internal/socks golang.org/x/net/proxy -# golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 +# golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 ## explicit golang.org/x/sys/cpu golang.org/x/sys/internal/unsafeheader From ea503633aa396d3063a22a9ead12f8b8cb66a1b0 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 27 Feb 2022 16:21:58 +1100 Subject: [PATCH 094/385] move keybindings --- pkg/gui/controllers/branches_controller.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index a151d4bcc..08ea95119 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -35,6 +35,11 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty Handler: self.checkSelected(self.press), Description: self.c.Tr.LcCheckout, }, + { + Key: opts.GetKey(opts.Config.Universal.New), + Handler: self.checkSelected(self.newBranch), + Description: self.c.Tr.LcNewBranch, + }, { Key: opts.GetKey(opts.Config.Branches.CreatePullRequest), Handler: self.checkSelected(self.handleCreatePullRequest), @@ -61,11 +66,6 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty Handler: self.forceCheckout, Description: self.c.Tr.LcForceCheckout, }, - { - Key: opts.GetKey(opts.Config.Universal.New), - Handler: self.checkSelected(self.newBranch), - Description: self.c.Tr.LcNewBranch, - }, { Key: opts.GetKey(opts.Config.Universal.Remove), Handler: self.checkSelectedAndReal(self.delete), From 36c149836ab7a1e0852455a117de7ac3a00b4133 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 27 Feb 2022 16:22:04 +1100 Subject: [PATCH 095/385] softcode keybinding --- pkg/gui/controllers/files_controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index b10efc15c..5fcde5202 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -51,7 +51,7 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types Description: self.c.Tr.LcToggleStaged, }, { - Key: opts.GetKey(" "), // TODO: softcode + Key: opts.GetKey(opts.Config.Files.OpenStatusFilter), Handler: self.handleStatusFilterPressed, Description: self.c.Tr.LcFileFilter, }, From fb3752c11fa8f17806ed4f67fdaac064efa00b97 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 27 Feb 2022 16:46:27 +1100 Subject: [PATCH 096/385] clean up keybindings menu --- docs/keybindings/Keybindings_en.md | 18 ++--- docs/keybindings/Keybindings_nl.md | 16 ++-- docs/keybindings/Keybindings_pl.md | 18 ++--- docs/keybindings/Keybindings_zh.md | 18 ++--- pkg/gui/keybindings.go | 126 +++++++++++++++-------------- pkg/gui/options_menu_panel.go | 34 ++++++-- 6 files changed, 123 insertions(+), 107 deletions(-) diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index 9b613792b..acac130a4 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -5,7 +5,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Global Keybindings - ctrl+r: switch to a recent repo (@@ -45,12 +47,12 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+o: copy branch name to clipboard i: show git-flow options space: checkout + n: new branch o: create pull request O: create pull request options ctrl+y: copy pull request URL to clipboard c: checkout by name F: force checkout - n: new branch d: delete branch r: rebase checked-out branch onto this branch M: merge into currently checked out branch @@ -218,8 +220,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Main Panel (Merging)) + ctrl+r: switch to a recent repo pgup: scroll up main panel (fn+up) pgdown: scroll down main panel (fn+down) m: view merge/rebase options @@ -35,6 +35,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct <: scroll to top >: scroll to bottom /: start search + H: scroll left + L: scroll right ]: next tab [: previous tab - H: scroll left - L: scroll right esc: return to files panel M: open external merge tool (git mergetool) space: pick hunk @@ -234,8 +234,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Main Panel (Normal)## Main Panel (Staging) @@ -274,8 +272,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct v: toggle drag select V: toggle drag select a: toggle select hunk - H: scroll left - L: scroll right c: commit changes w: commit changes without pre-commit hook C: commit changes using git editor @@ -297,7 +293,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: view selected item's files- 艕: scroll down (fn+up) - 艖: scroll up (fn+down) + mouse wheel down: scroll down (fn+up) + mouse wheel up: scroll up (fn+down)## Main Panel (Patch Building) @@ -252,8 +252,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct v: toggle drag select V: toggle drag select a: toggle select hunk - H: scroll left - L: scroll righte: edit config file diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index 734f7135d..5b076f637 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -5,7 +5,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Globale Sneltoetsen-## Status Paneel +## Status Paneel (Status)- ctrl+r: wissel naar een recente repo (@@ -46,12 +48,12 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+o: kopieer branch name naar klembord i: laat git-flow opties zien space: uitchecken + n: nieuwe branch o: maak een pull-request O: bekijk opties voor pull-aanvraag ctrl+y: kopieer de URL van het pull-verzoek naar het klembord c: uitchecken bij naam F: forceer checkout - n: nieuwe branch d: verwijder branch r: rebase branch M: merge in met huidige checked out branch @@ -216,8 +218,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Hoofd Paneel (Mergen)) + ctrl+r: wissel naar een recente repo pgup: scroll naar beneden vanaf hoofdpaneel (fn+up) pgdown: scroll naar beneden vanaf hoofdpaneel (fn+down) m: bekijk merge/rebase opties @@ -36,6 +36,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct <: scroll naar boven >: scroll naar beneden /: start met zoeken + H: scroll left + L: scroll right ]: volgende tabblad [: vorige tabblad - H: scroll left - L: scroll right esc: ga terug naar het bestanden paneel M: open external merge tool (git mergetool) space: kies hunk @@ -232,8 +232,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Hoofd Paneel (Normaal)## Hoofd Paneel (Staging) @@ -295,7 +293,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: bekijk gecommite bestanden- 艕: scroll omlaag (fn+up) - 艖: scroll omhoog (fn+down) + mouse wheel down: scroll omlaag (fn+up) + mouse wheel up: scroll omhoog (fn+down)## Hoofd Paneel (Patch Bouwen) @@ -250,8 +250,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct v: toggle drag selecteer V: toggle drag selecteer a: toggle selecteer hunk - H: scroll left - L: scroll righte: verander config bestand diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index 8dd8ff8aa..fd26ea20d 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -5,7 +5,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Globalne-## Status Panel +## Status Panel (Status)- ctrl+r: switch to a recent repo (@@ -45,12 +47,12 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+o: copy branch name to clipboard i: show git-flow options space: prze艂膮cz + n: nowa ga艂膮藕 o: utw贸rz 偶膮danie pobrania O: utw贸rz opcje 偶膮dania 艣ci膮gni臋cia ctrl+y: skopiuj adres URL 偶膮dania pobrania do schowka c: prze艂膮cz u偶ywaj膮c nazwy F: wymu艣 prze艂膮czenie - n: nowa ga艂膮藕 d: usu艅 ga艂膮藕 r: zmiana bazy ga艂臋zi M: scal do obecnej ga艂臋zi @@ -218,8 +220,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## G艂贸wne Panel (Scalanie)) + ctrl+r: switch to a recent repo pgup: scroll up main panel (fn+up) pgdown: scroll down main panel (fn+down) m: widok scalenia/opcje zmiany bazy @@ -35,6 +35,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct <: scroll to top >: scroll to bottom /: start search + H: scroll left + L: scroll right ]: next tab [: previous tab - H: scroll left - L: scroll right esc: wr贸膰 do panelu plik贸w M: open external merge tool (git mergetool) space: wybierz kawa艂ek @@ -234,8 +234,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## G艂贸wne Panel (Zwyk艂e)## G艂贸wne Panel (Poczekalnia) @@ -274,8 +272,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct v: toggle drag select V: toggle drag select a: toggle select hunk - H: scroll left - L: scroll right c: Zatwierd藕 zmiany w: zatwierd藕 zmiany bez skryptu pre-commit C: Zatwierd藕 zmiany u偶ywaj膮c edytora @@ -297,7 +293,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: przegl膮daj pliki commita- 艕: przewi艅 w d贸艂 (fn+up) - 艖: przewi艅 w g贸r臋 (fn+down) + mouse wheel down: przewi艅 w d贸艂 (fn+up) + mouse wheel up: przewi艅 w g贸r臋 (fn+down)## G艂贸wne Panel (Patch Building) @@ -252,8 +252,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct v: toggle drag select V: toggle drag select a: toggle select hunk - H: scroll left - L: scroll righte: edytuj konfiguracj臋 diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index 34a60a0e5..c075a7879 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -5,7 +5,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## 鍏ㄥ眬閿粦瀹-## 鐘舵 闈㈡澘 +## 鐘舵 闈㈡澘 (鐘舵)- ctrl+r: 鍒囨崲鍒版渶杩戠殑浠撳簱 (@@ -45,12 +47,12 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+o: 灏嗗垎鏀悕绉板鍒跺埌鍓创鏉 i: 鏄剧ず git-flow 閫夐」 space: 妫鍑 + n: 鏂板垎鏀 o: 鍒涘缓鎶撳彇璇锋眰 O: 鍒涘缓鎶撳彇璇锋眰閫夐」 ctrl+y: 灏嗘姄鍙栬姹 URL 澶嶅埗鍒板壀璐存澘 c: 鎸夊悕绉版鍑 F: 寮哄埗妫鍑 - n: 鏂板垎鏀 d: 鍒犻櫎鍒嗘敮 r: 灏嗗凡妫鍑虹殑鍒嗘敮鍙樺熀鍒拌鍒嗘敮 M: 鍚堝苟鍒板綋鍓嶆鍑虹殑鍒嗘敮 @@ -218,8 +220,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## 涓昏 闈㈡澘 (鍚堝苟涓)) + ctrl+r: 鍒囨崲鍒版渶杩戠殑浠撳簱 pgup: 鍚戜笂婊氬姩涓婚潰鏉 (fn+up) pgdown: 鍚戜笅婊氬姩涓婚潰鏉 (fn+down) m: 鏌ョ湅 鍚堝苟/鍙樺熀 閫夐」 @@ -35,6 +35,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct <: 婊氬姩鍒伴《閮 >: 婊氬姩鍒板簳閮 /: 寮濮嬫悳绱 + H: scroll left + L: scroll right ]: 涓嬩竴涓爣绛 [: 涓婁竴涓爣绛 - H: scroll left - L: scroll right esc: 杩斿洖鏂囦欢闈㈡澘 M: 鎵撳紑鍚堝苟宸ュ叿 space: 閫変腑鍖哄潡 @@ -234,8 +234,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## 涓昏 闈㈡澘 (姝e父)## 涓昏 闈㈡澘 (姝e湪鏆傚瓨) @@ -274,8 +272,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct v: 鍒囨崲鎷栧姩閫夋嫨 V: 鍒囨崲鎷栧姩閫夋嫨 a: 鍒囨崲閫夋嫨鍖哄潡 - H: scroll left - L: scroll right c: 鎻愪氦鏇存敼 w: 鎻愪氦鏇存敼鑰屾棤闇棰勫厛鎻愪氦閽╁瓙 C: 鎻愪氦鏇存敼锛堜娇鐢ㄧ紪杈戝櫒缂栬緫鎻愪氦淇℃伅锛 @@ -297,7 +293,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: 鏌ョ湅鎻愪氦鐨勬枃浠- 艕: 鍚戜笅婊氬姩 (fn+up) - 艖: 鍚戜笂婊氬姩 (fn+down) + mouse wheel down: 鍚戜笅婊氬姩 (fn+up) + mouse wheel up: 鍚戜笂婊氬姩 (fn+down)## 涓昏 闈㈡澘 (鏋勫缓琛ヤ竵涓) @@ -252,8 +252,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct v: 鍒囨崲鎷栧姩閫夋嫨 V: 鍒囨崲鎷栧姩閫夋嫨 a: 鍒囨崲閫夋嫨鍖哄潡 - H: scroll left - L: scroll righte: 缂栬緫閰嶇疆鏂囦欢 diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index d6a586a10..2bf2b9815 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -15,64 +15,66 @@ import ( ) var keyMapReversed = map[gocui.Key]string{ - gocui.KeyF1: "f1", - gocui.KeyF2: "f2", - gocui.KeyF3: "f3", - gocui.KeyF4: "f4", - gocui.KeyF5: "f5", - gocui.KeyF6: "f6", - gocui.KeyF7: "f7", - gocui.KeyF8: "f8", - gocui.KeyF9: "f9", - gocui.KeyF10: "f10", - gocui.KeyF11: "f11", - gocui.KeyF12: "f12", - gocui.KeyInsert: "insert", - gocui.KeyDelete: "delete", - gocui.KeyHome: "home", - gocui.KeyEnd: "end", - gocui.KeyPgup: "pgup", - gocui.KeyPgdn: "pgdown", - gocui.KeyArrowUp: "鈻", - gocui.KeyArrowDown: "鈻", - gocui.KeyArrowLeft: "鈼", - gocui.KeyArrowRight: "鈻", - gocui.KeyTab: "tab", // ctrl+i - gocui.KeyBacktab: "shift+tab", - gocui.KeyEnter: "enter", // ctrl+m - gocui.KeyAltEnter: "alt+enter", - gocui.KeyEsc: "esc", // ctrl+[, ctrl+3 - gocui.KeyBackspace: "backspace", // ctrl+h - gocui.KeyCtrlSpace: "ctrl+space", // ctrl+~, ctrl+2 - gocui.KeyCtrlSlash: "ctrl+/", // ctrl+_ - gocui.KeySpace: "space", - gocui.KeyCtrlA: "ctrl+a", - gocui.KeyCtrlB: "ctrl+b", - gocui.KeyCtrlC: "ctrl+c", - gocui.KeyCtrlD: "ctrl+d", - gocui.KeyCtrlE: "ctrl+e", - gocui.KeyCtrlF: "ctrl+f", - gocui.KeyCtrlG: "ctrl+g", - gocui.KeyCtrlJ: "ctrl+j", - gocui.KeyCtrlK: "ctrl+k", - gocui.KeyCtrlL: "ctrl+l", - gocui.KeyCtrlN: "ctrl+n", - gocui.KeyCtrlO: "ctrl+o", - gocui.KeyCtrlP: "ctrl+p", - gocui.KeyCtrlQ: "ctrl+q", - gocui.KeyCtrlR: "ctrl+r", - gocui.KeyCtrlS: "ctrl+s", - gocui.KeyCtrlT: "ctrl+t", - gocui.KeyCtrlU: "ctrl+u", - gocui.KeyCtrlV: "ctrl+v", - gocui.KeyCtrlW: "ctrl+w", - gocui.KeyCtrlX: "ctrl+x", - gocui.KeyCtrlY: "ctrl+y", - gocui.KeyCtrlZ: "ctrl+z", - gocui.KeyCtrl4: "ctrl+4", // ctrl+\ - gocui.KeyCtrl5: "ctrl+5", // ctrl+] - gocui.KeyCtrl6: "ctrl+6", - gocui.KeyCtrl8: "ctrl+8", + gocui.KeyF1: "f1", + gocui.KeyF2: "f2", + gocui.KeyF3: "f3", + gocui.KeyF4: "f4", + gocui.KeyF5: "f5", + gocui.KeyF6: "f6", + gocui.KeyF7: "f7", + gocui.KeyF8: "f8", + gocui.KeyF9: "f9", + gocui.KeyF10: "f10", + gocui.KeyF11: "f11", + gocui.KeyF12: "f12", + gocui.KeyInsert: "insert", + gocui.KeyDelete: "delete", + gocui.KeyHome: "home", + gocui.KeyEnd: "end", + gocui.KeyPgup: "pgup", + gocui.KeyPgdn: "pgdown", + gocui.KeyArrowUp: "鈻", + gocui.KeyArrowDown: "鈻", + gocui.KeyArrowLeft: "鈼", + gocui.KeyArrowRight: "鈻", + gocui.KeyTab: "tab", // ctrl+i + gocui.KeyBacktab: "shift+tab", + gocui.KeyEnter: "enter", // ctrl+m + gocui.KeyAltEnter: "alt+enter", + gocui.KeyEsc: "esc", // ctrl+[, ctrl+3 + gocui.KeyBackspace: "backspace", // ctrl+h + gocui.KeyCtrlSpace: "ctrl+space", // ctrl+~, ctrl+2 + gocui.KeyCtrlSlash: "ctrl+/", // ctrl+_ + gocui.KeySpace: "space", + gocui.KeyCtrlA: "ctrl+a", + gocui.KeyCtrlB: "ctrl+b", + gocui.KeyCtrlC: "ctrl+c", + gocui.KeyCtrlD: "ctrl+d", + gocui.KeyCtrlE: "ctrl+e", + gocui.KeyCtrlF: "ctrl+f", + gocui.KeyCtrlG: "ctrl+g", + gocui.KeyCtrlJ: "ctrl+j", + gocui.KeyCtrlK: "ctrl+k", + gocui.KeyCtrlL: "ctrl+l", + gocui.KeyCtrlN: "ctrl+n", + gocui.KeyCtrlO: "ctrl+o", + gocui.KeyCtrlP: "ctrl+p", + gocui.KeyCtrlQ: "ctrl+q", + gocui.KeyCtrlR: "ctrl+r", + gocui.KeyCtrlS: "ctrl+s", + gocui.KeyCtrlT: "ctrl+t", + gocui.KeyCtrlU: "ctrl+u", + gocui.KeyCtrlV: "ctrl+v", + gocui.KeyCtrlW: "ctrl+w", + gocui.KeyCtrlX: "ctrl+x", + gocui.KeyCtrlY: "ctrl+y", + gocui.KeyCtrlZ: "ctrl+z", + gocui.KeyCtrl4: "ctrl+4", // ctrl+\ + gocui.KeyCtrl5: "ctrl+5", // ctrl+] + gocui.KeyCtrl6: "ctrl+6", + gocui.KeyCtrl8: "ctrl+8", + gocui.MouseWheelUp: "mouse wheel up", + gocui.MouseWheelDown: "mouse wheel down", } var keymap = map[string]interface{}{ @@ -249,7 +251,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi ViewName: "", Key: opts.GetKey(opts.Config.Universal.OpenRecentRepos), Handler: self.handleCreateRecentReposMenu, - Alternative: "diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index fd26ea20d..2d032e5e3 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -123,6 +123,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct o: otw贸rz plik e: edytuj plik space: toggle file included in patch + a: toggle all files included in patch enter: enter file to add selected聽lines to the patch (or toggle directory collapsed) `: toggle file tree view", Description: self.c.Tr.SwitchRepo, }, { @@ -325,6 +326,7 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi }, { ViewName: "status", + Contexts: []string{string(context.STATUS_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Universal.Edit), Handler: self.handleEditConfig, Description: self.c.Tr.EditConfig, @@ -343,24 +345,28 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi }, { ViewName: "status", + Contexts: []string{string(context.STATUS_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Universal.OpenFile), Handler: self.handleOpenConfig, Description: self.c.Tr.OpenConfig, }, { ViewName: "status", + Contexts: []string{string(context.STATUS_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Status.CheckForUpdate), Handler: self.handleCheckForUpdate, Description: self.c.Tr.LcCheckForUpdate, }, { ViewName: "status", + Contexts: []string{string(context.STATUS_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Status.RecentRepos), Handler: self.handleCreateRecentReposMenu, Description: self.c.Tr.SwitchRepo, }, { ViewName: "status", + Contexts: []string{string(context.STATUS_CONTEXT_KEY)}, Key: opts.GetKey(opts.Config.Status.AllBranchesLogGraph), Handler: self.handleShowAllBranchLogs, Description: self.c.Tr.LcAllBranchesLogGraph, @@ -729,6 +735,7 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Handler: self.scrollLeftMain, Description: self.c.Tr.LcScrollLeft, + Tag: "navigation", }, { ViewName: "main", @@ -736,6 +743,7 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi Key: opts.GetKey(opts.Config.Universal.ScrollRight), Handler: self.scrollRightMain, Description: self.c.Tr.LcScrollRight, + Tag: "navigation", }, { ViewName: "main", diff --git a/pkg/gui/options_menu_panel.go b/pkg/gui/options_menu_panel.go index 17ced988e..85ed34b5d 100644 --- a/pkg/gui/options_menu_panel.go +++ b/pkg/gui/options_menu_panel.go @@ -12,7 +12,7 @@ import ( func (gui *Gui) getBindings(context types.Context) []*types.Binding { var ( - bindingsGlobal, bindingsPanel []*types.Binding + bindingsGlobal, bindingsPanel, bindingsNavigation []*types.Binding ) bindings, _ := gui.GetInitialKeybindings() @@ -24,18 +24,40 @@ func (gui *Gui) getBindings(context types.Context) []*types.Binding { for _, binding := range bindings { if GetKeyDisplay(binding.Key) != "" && binding.Description != "" { - if len(binding.Contexts) == 0 { + if len(binding.Contexts) == 0 && binding.ViewName == "" { bindingsGlobal = append(bindingsGlobal, binding) + } else if binding.Tag == "navigation" { + bindingsNavigation = append(bindingsNavigation, binding) } else if utils.IncludesString(binding.Contexts, string(context.GetKey())) { bindingsPanel = append(bindingsPanel, binding) } } } - // append dummy element to have a separator between - // panel and global keybindings - bindingsPanel = append(bindingsPanel, &types.Binding{}) - return append(bindingsPanel, bindingsGlobal...) + resultBindings := []*types.Binding{} + resultBindings = append(resultBindings, uniqueBindings(bindingsPanel)...) + // adding a separator between the panel-specific bindings and the other bindings + resultBindings = append(resultBindings, &types.Binding{}) + resultBindings = append(resultBindings, uniqueBindings(bindingsGlobal)...) + resultBindings = append(resultBindings, uniqueBindings(bindingsNavigation)...) + + return resultBindings +} + +// We shouldn't really need to do this. We should define alternative keys for the same +// handler in the keybinding struct. +func uniqueBindings(bindings []*types.Binding) []*types.Binding { + keys := make(map[string]bool) + result := make([]*types.Binding, 0) + + for _, binding := range bindings { + if _, ok := keys[binding.Description]; !ok { + keys[binding.Description] = true + result = append(result, binding) + } + } + + return result } func (gui *Gui) displayDescription(binding *types.Binding) string { From 31ab43d0c5380563a9cf5f1a265a06cd5e9deef4 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Thu, 3 Mar 2022 19:39:33 +1100 Subject: [PATCH 097/385] add host helper --- pkg/gui/controllers.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/gui/controllers.go b/pkg/gui/controllers.go index 04abf1103..3e33783e1 100644 --- a/pkg/gui/controllers.go +++ b/pkg/gui/controllers.go @@ -25,6 +25,7 @@ func (gui *Gui) resetControllers() { rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon, gui.State.Contexts, gui.git, gui.takeOverMergeConflictScrolling, refsHelper) gui.helpers = &helpers.Helpers{ Refs: refsHelper, + Host: helpers.NewHostHelper(helperCommon, gui.git), PatchBuilding: helpers.NewPatchBuildingHelper(helperCommon, gui.git), Bisect: helpers.NewBisectHelper(helperCommon, gui.git), Suggestions: helpers.NewSuggestionsHelper(helperCommon, model, gui.refreshSuggestions), From 7bdd7088e796231503d26a8f0e52c96f2887e5b5 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Thu, 3 Mar 2022 19:48:11 +1100 Subject: [PATCH 098/385] prevent early exit from setup script --- test/integration/discardFileChanges/setup.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/integration/discardFileChanges/setup.sh b/test/integration/discardFileChanges/setup.sh index 82fa59475..ac9573e82 100644 --- a/test/integration/discardFileChanges/setup.sh +++ b/test/integration/discardFileChanges/setup.sh @@ -1,6 +1,7 @@ #!/bin/sh -set -e +# expecting an error so we're not setting this +# set -e cd $1 From 729da3549ab7792b2ce0f89e2f37b2ad03efd8e6 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Tue, 15 Mar 2022 21:24:58 +1100 Subject: [PATCH 099/385] go mod vendor --- go.sum | 4 ++++ vendor/github.com/go-errors/errors/README.md | 1 - vendor/github.com/go-errors/errors/stackframe.go | 14 +++----------- vendor/modules.txt | 2 +- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/go.sum b/go.sum index 3b11f219b..f5b697e1d 100644 --- a/go.sum +++ b/go.sum @@ -41,6 +41,8 @@ github.com/gdamore/tcell/v2 v2.4.1-0.20220313203054-2a1a1b586447/go.mod h1:I8YJF github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= +github.com/go-errors/errors v1.4.1 h1:IvVlgbzSsaUNudsw5dcXSzF3EWyXTi5XrAdngnuhRyg= +github.com/go-errors/errors v1.4.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= @@ -186,6 +188,8 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 h1:BXxu8t6QN0G1uff4bzZzSkpsax8+ALqTGUtz08QrV00= +golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/vendor/github.com/go-errors/errors/README.md b/vendor/github.com/go-errors/errors/README.md index 3d7852594..2ee13f117 100644 --- a/vendor/github.com/go-errors/errors/README.md +++ b/vendor/github.com/go-errors/errors/README.md @@ -79,4 +79,3 @@ This package is licensed under the MIT license, see LICENSE.MIT for details. > ``` * v1.4.0 *BREAKING* v1.4.0 reverted all changes from v1.3.0 and is identical to v1.2.0 * v1.4.1 no code change, but now without an unnecessary cover.out file. -* v1.4.2 performance improvement to ErrorStack() to avoid unnecessary work https://github.com/go-errors/errors/pull/40 diff --git a/vendor/github.com/go-errors/errors/stackframe.go b/vendor/github.com/go-errors/errors/stackframe.go index ef4a8b3f3..f420849d2 100644 --- a/vendor/github.com/go-errors/errors/stackframe.go +++ b/vendor/github.com/go-errors/errors/stackframe.go @@ -53,7 +53,7 @@ func (frame *StackFrame) Func() *runtime.Func { func (frame *StackFrame) String() string { str := fmt.Sprintf("%s:%d (0x%x)\n", frame.File, frame.LineNumber, frame.ProgramCounter) - source, err := frame.sourceLine() + source, err := frame.SourceLine() if err != nil { return str } @@ -63,21 +63,13 @@ func (frame *StackFrame) String() string { // SourceLine gets the line of code (from File and Line) of the original source if possible. func (frame *StackFrame) SourceLine() (string, error) { - source, err := frame.sourceLine() - if err != nil { - return source, New(err) - } - return source, err -} - -func (frame *StackFrame) sourceLine() (string, error) { if frame.LineNumber <= 0 { return "???", nil } file, err := os.Open(frame.File) if err != nil { - return "", err + return "", New(err) } defer file.Close() @@ -90,7 +82,7 @@ func (frame *StackFrame) sourceLine() (string, error) { currentLine++ } if err := scanner.Err(); err != nil { - return "", err + return "", New(err) } return "???", nil diff --git a/vendor/modules.txt b/vendor/modules.txt index 295a15987..bd07c38aa 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -74,7 +74,7 @@ github.com/gdamore/tcell/v2/terminfo/x/xfce github.com/gdamore/tcell/v2/terminfo/x/xterm github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty github.com/gdamore/tcell/v2/terminfo/x/xterm_termite -# github.com/go-errors/errors v1.4.2 +# github.com/go-errors/errors v1.4.1 ## explicit github.com/go-errors/errors # github.com/go-git/gcfg v1.5.0 From 205c7d60aa84e7e3ccc8ca3f4a37dae5b4e25ca6 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Thu, 17 Mar 2022 18:38:36 +1100 Subject: [PATCH 100/385] update cheatsheets --- docs/keybindings/Keybindings_nl.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index 5b076f637..428d9507b 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -14,14 +14,13 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct x: open menu +: volgende scherm modus (normaal/half/groot) _: vorige scherm modus - :: voer aangepaste commando uit ctrl+s: bekijk scoping opties W: open diff menu ctrl+e: open diff menu @: open command log menu }: Increase the size of the context shown around changes in the diff view {: Decrease the size of the context shown around changes in the diff view - :: voor aangepaste commando uit + :: voer aangepaste commando uit z: ongedaan maken (via reflog) (experimenteel) ctrl+z: redo (via reflog) (experimenteel) P: push @@ -66,15 +65,13 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Branches Paneel (Remote Branches (in Remotes tabblad)) - esc: ga terug naar remotes lijst - g: bekijk reset opties space: uitchecken n: nieuwe branch M: merge in met huidige checked out branch r: rebase branch d: verwijder branch u: stel in als upstream van uitgecheckte branch - esc: Ga terug naar remotes lijst + esc: ga terug naar remotes lijst g: bekijk reset opties enter: bekijk commits@@ -183,6 +180,11 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ## Bestanden Paneel (Bestanden)+ ctrl+o: kopieer de bestandsnaam naar het klembord + ctrl+w: Toggle whether or not whitespace changes are shown in the diff view + d: bekijk 'veranderingen ongedaan maken' opties + space: toggle staged + ctrl+b: Filter files (staged/unstaged) c: commit veranderingen w: commit veranderingen zonder pre-commit hook A: wijzig laatste commit @@ -270,8 +272,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct v: toggle drag selecteer V: toggle drag selecteer a: toggle selecteer hunk - H: scroll left - L: scroll right c: commit veranderingen w: commit veranderingen zonder pre-commit hook C: commit veranderingen met de git editor From 4fde97b066eef9742c96dac8b5a15468e003ec92 Mon Sep 17 00:00:00 2001 From: Jesse Duffielddiff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index 428d9507b..dd9c45ad2 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -123,6 +123,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct o: open bestand e: verander bestand space: toggle bestand inbegrepen in patch + a: toggle all files included in patch enter: enter bestand om geselecteerde regels toe te voegen aan de patch `: toggle bestandsboom weergaveDate: Thu, 17 Mar 2022 21:50:39 +1100 Subject: [PATCH 101/385] update go to v1.18 --- go.mod | 43 +++++++--- go.sum | 11 --- vendor/github.com/OpenPeeDeeP/xdg/go.mod | 8 -- vendor/github.com/OpenPeeDeeP/xdg/go.sum | 8 -- vendor/github.com/atotto/clipboard/go.mod | 1 - vendor/github.com/aybabtme/humanlog/go.mod | 14 ---- vendor/github.com/aybabtme/humanlog/go.sum | 16 ---- vendor/github.com/cli/safeexec/go.mod | 3 - vendor/github.com/creack/pty/go.mod | 4 - vendor/github.com/fatih/color/go.mod | 8 -- vendor/github.com/fatih/color/go.sum | 8 -- vendor/github.com/gdamore/encoding/go.mod | 5 -- vendor/github.com/gdamore/encoding/go.sum | 2 - vendor/github.com/gdamore/tcell/v2/go.mod | 12 --- vendor/github.com/gdamore/tcell/v2/go.sum | 17 ---- vendor/github.com/go-errors/errors/go.mod | 6 -- vendor/github.com/go-git/go-billy/v5/go.mod | 10 --- vendor/github.com/go-git/go-billy/v5/go.sum | 14 ---- vendor/github.com/go-logfmt/logfmt/go.mod | 3 - vendor/github.com/gookit/color/go.mod | 9 -- vendor/github.com/gookit/color/go.sum | 15 ---- vendor/github.com/imdario/mergo/go.mod | 5 -- vendor/github.com/imdario/mergo/go.sum | 4 - vendor/github.com/integrii/flaggy/go.mod | 3 - .../github.com/jesseduffield/go-git/v5/go.mod | 28 ------- .../github.com/jesseduffield/go-git/v5/go.sum | 82 ------------------- vendor/github.com/jesseduffield/gocui/go.mod | 10 --- vendor/github.com/jesseduffield/gocui/go.sum | 29 ------- .../jesseduffield/minimal/gitignore/go.mod | 5 -- .../jesseduffield/minimal/gitignore/go.sum | 2 - vendor/github.com/kardianos/osext/go.mod | 1 - .../go-windows-terminal-sequences/go.mod | 1 - vendor/github.com/kyokomi/emoji/v2/go.mod | 3 - .../github.com/lucasb-eyer/go-colorful/go.mod | 3 - vendor/github.com/mattn/go-colorable/go.mod | 8 -- vendor/github.com/mattn/go-colorable/go.sum | 5 -- vendor/github.com/mattn/go-isatty/go.mod | 5 -- vendor/github.com/mattn/go-isatty/go.sum | 2 - vendor/github.com/mattn/go-runewidth/go.mod | 5 -- vendor/github.com/mattn/go-runewidth/go.sum | 2 - vendor/github.com/mitchellh/go-homedir/go.mod | 1 - vendor/github.com/rivo/uniseg/go.mod | 3 - vendor/github.com/sanity-io/litter/go.mod | 9 -- vendor/github.com/sanity-io/litter/go.sum | 6 -- vendor/github.com/sirupsen/logrus/go.mod | 10 --- vendor/github.com/sirupsen/logrus/go.sum | 16 ---- vendor/github.com/xanzy/ssh-agent/go.mod | 6 -- vendor/github.com/xanzy/ssh-agent/go.sum | 4 - vendor/github.com/xo/terminfo/go.mod | 3 - vendor/github.com/xo/terminfo/go.sum | 0 vendor/golang.org/x/term/go.mod | 5 -- vendor/golang.org/x/term/go.sum | 2 - vendor/gopkg.in/yaml.v3/go.mod | 5 -- vendor/modules.txt | 71 +++++++++------- 54 files changed, 74 insertions(+), 487 deletions(-) delete mode 100644 vendor/github.com/OpenPeeDeeP/xdg/go.mod delete mode 100644 vendor/github.com/OpenPeeDeeP/xdg/go.sum delete mode 100644 vendor/github.com/atotto/clipboard/go.mod delete mode 100644 vendor/github.com/aybabtme/humanlog/go.mod delete mode 100644 vendor/github.com/aybabtme/humanlog/go.sum delete mode 100644 vendor/github.com/cli/safeexec/go.mod delete mode 100644 vendor/github.com/creack/pty/go.mod delete mode 100644 vendor/github.com/fatih/color/go.mod delete mode 100644 vendor/github.com/fatih/color/go.sum delete mode 100644 vendor/github.com/gdamore/encoding/go.mod delete mode 100644 vendor/github.com/gdamore/encoding/go.sum delete mode 100644 vendor/github.com/gdamore/tcell/v2/go.mod delete mode 100644 vendor/github.com/gdamore/tcell/v2/go.sum delete mode 100644 vendor/github.com/go-errors/errors/go.mod delete mode 100644 vendor/github.com/go-git/go-billy/v5/go.mod delete mode 100644 vendor/github.com/go-git/go-billy/v5/go.sum delete mode 100644 vendor/github.com/go-logfmt/logfmt/go.mod delete mode 100644 vendor/github.com/gookit/color/go.mod delete mode 100644 vendor/github.com/gookit/color/go.sum delete mode 100644 vendor/github.com/imdario/mergo/go.mod delete mode 100644 vendor/github.com/imdario/mergo/go.sum delete mode 100644 vendor/github.com/integrii/flaggy/go.mod delete mode 100644 vendor/github.com/jesseduffield/go-git/v5/go.mod delete mode 100644 vendor/github.com/jesseduffield/go-git/v5/go.sum delete mode 100644 vendor/github.com/jesseduffield/gocui/go.mod delete mode 100644 vendor/github.com/jesseduffield/gocui/go.sum delete mode 100644 vendor/github.com/jesseduffield/minimal/gitignore/go.mod delete mode 100644 vendor/github.com/jesseduffield/minimal/gitignore/go.sum delete mode 100644 vendor/github.com/kardianos/osext/go.mod delete mode 100644 vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod delete mode 100644 vendor/github.com/kyokomi/emoji/v2/go.mod delete mode 100644 vendor/github.com/lucasb-eyer/go-colorful/go.mod delete mode 100644 vendor/github.com/mattn/go-colorable/go.mod delete mode 100644 vendor/github.com/mattn/go-colorable/go.sum delete mode 100644 vendor/github.com/mattn/go-isatty/go.mod delete mode 100644 vendor/github.com/mattn/go-isatty/go.sum delete mode 100644 vendor/github.com/mattn/go-runewidth/go.mod delete mode 100644 vendor/github.com/mattn/go-runewidth/go.sum delete mode 100644 vendor/github.com/mitchellh/go-homedir/go.mod delete mode 100644 vendor/github.com/rivo/uniseg/go.mod delete mode 100644 vendor/github.com/sanity-io/litter/go.mod delete mode 100644 vendor/github.com/sanity-io/litter/go.sum delete mode 100644 vendor/github.com/sirupsen/logrus/go.mod delete mode 100644 vendor/github.com/sirupsen/logrus/go.sum delete mode 100644 vendor/github.com/xanzy/ssh-agent/go.mod delete mode 100644 vendor/github.com/xanzy/ssh-agent/go.sum delete mode 100644 vendor/github.com/xo/terminfo/go.mod delete mode 100644 vendor/github.com/xo/terminfo/go.sum delete mode 100644 vendor/golang.org/x/term/go.mod delete mode 100644 vendor/golang.org/x/term/go.sum delete mode 100644 vendor/gopkg.in/yaml.v3/go.mod diff --git a/go.mod b/go.mod index 5a3dcd387..677a482f9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/jesseduffield/lazygit -go 1.14 +go 1.18 require ( github.com/OpenPeeDeeP/xdg v1.0.0 @@ -9,13 +9,8 @@ require ( github.com/cli/safeexec v1.0.0 github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 github.com/creack/pty v1.1.11 - github.com/fatih/color v1.9.0 // indirect github.com/fsnotify/fsnotify v1.4.7 - github.com/gdamore/tcell/v2 v2.4.1-0.20220313203054-2a1a1b586447 // indirect github.com/go-errors/errors v1.4.1 - github.com/go-logfmt/logfmt v0.5.0 // indirect - github.com/golang/protobuf v1.3.2 // indirect - github.com/google/go-cmp v0.5.6 // indirect github.com/gookit/color v1.4.2 github.com/imdario/mergo v0.3.11 github.com/integrii/flaggy v1.4.0 @@ -24,15 +19,10 @@ require ( github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e github.com/jesseduffield/yaml v2.1.0+incompatible github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 - github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect - github.com/kylelemons/godebug v1.1.0 // indirect github.com/kyokomi/emoji/v2 v2.2.8 github.com/lucasb-eyer/go-colorful v1.2.0 - github.com/mattn/go-colorable v0.1.11 // indirect github.com/mattn/go-runewidth v0.0.13 github.com/mgutz/str v1.2.0 - github.com/onsi/ginkgo v1.10.3 // indirect - github.com/onsi/gomega v1.7.1 // indirect github.com/pmezard/go-difflib v1.0.0 github.com/sahilm/fuzzy v0.1.0 github.com/sanity-io/litter v1.5.2 @@ -40,9 +30,38 @@ require ( github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad github.com/stretchr/testify v1.7.0 github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 + gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emirpasic/gods v1.12.0 // indirect + github.com/fatih/color v1.9.0 // indirect + github.com/gdamore/encoding v1.0.0 // indirect + github.com/gdamore/tcell/v2 v2.4.1-0.20220313203054-2a1a1b586447 // indirect + github.com/go-git/gcfg v1.5.0 // indirect + github.com/go-git/go-billy/v5 v5.0.0 // indirect + github.com/go-logfmt/logfmt v0.5.0 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/google/go-cmp v0.5.6 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect + github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect + github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect + github.com/mattn/go-colorable v0.1.11 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/onsi/ginkgo v1.10.3 // indirect + github.com/onsi/gomega v1.7.1 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/sergi/go-diff v1.1.0 // indirect + github.com/xanzy/ssh-agent v0.2.1 // indirect golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // indirect golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0 + golang.org/x/text v0.3.7 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) diff --git a/go.sum b/go.sum index f5b697e1d..cc15e70e0 100644 --- a/go.sum +++ b/go.sum @@ -27,15 +27,12 @@ github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3 github.com/fatih/color v1.7.1-0.20180516100307-2d684516a886/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU= -github.com/gdamore/tcell/v2 v2.4.1-0.20210926162909-66f061b1fc9b h1:eoaSI4eEwM5eTx/HvmRSwmicxuMhL73AyoEfM1oCJLc= -github.com/gdamore/tcell/v2 v2.4.1-0.20210926162909-66f061b1fc9b/go.mod h1:ZPwXnysybtQqdqKcWMWXux9aGdtMHe+kr+cwEZEe+A4= github.com/gdamore/tcell/v2 v2.4.1-0.20220313203054-2a1a1b586447 h1:4idf9699cuWAc7ZIB+2RzuDWU30oRkB0X/FZTUlWOVY= github.com/gdamore/tcell/v2 v2.4.1-0.20220313203054-2a1a1b586447/go.mod h1:I8YJFI9gzgl4dHi9UlRDZosCW+jYkDA37AXmXvL51w4= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= @@ -43,8 +40,6 @@ github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aev github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= github.com/go-errors/errors v1.4.1 h1:IvVlgbzSsaUNudsw5dcXSzF3EWyXTi5XrAdngnuhRyg= github.com/go-errors/errors v1.4.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= @@ -57,8 +52,6 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -182,12 +175,9 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 h1:BXxu8t6QN0G1uff4bzZzSkpsax8+ALqTGUtz08QrV00= golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -198,7 +188,6 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/vendor/github.com/OpenPeeDeeP/xdg/go.mod b/vendor/github.com/OpenPeeDeeP/xdg/go.mod deleted file mode 100644 index 94df76372..000000000 --- a/vendor/github.com/OpenPeeDeeP/xdg/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/OpenPeeDeeP/xdg - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/objx v0.1.1 // indirect - github.com/stretchr/testify v1.2.2 -) diff --git a/vendor/github.com/OpenPeeDeeP/xdg/go.sum b/vendor/github.com/OpenPeeDeeP/xdg/go.sum deleted file mode 100644 index 604d09fa8..000000000 --- a/vendor/github.com/OpenPeeDeeP/xdg/go.sum +++ /dev/null @@ -1,8 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= diff --git a/vendor/github.com/atotto/clipboard/go.mod b/vendor/github.com/atotto/clipboard/go.mod deleted file mode 100644 index 68ec980e7..000000000 --- a/vendor/github.com/atotto/clipboard/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/atotto/clipboard diff --git a/vendor/github.com/aybabtme/humanlog/go.mod b/vendor/github.com/aybabtme/humanlog/go.mod deleted file mode 100644 index 594f15ab1..000000000 --- a/vendor/github.com/aybabtme/humanlog/go.mod +++ /dev/null @@ -1,14 +0,0 @@ -module github.com/aybabtme/humanlog - -go 1.13 - -require ( - github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 - github.com/fatih/color v1.7.1-0.20180516100307-2d684516a886 - github.com/go-logfmt/logfmt v0.4.0 - github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 - github.com/mattn/go-colorable v0.1.0 - github.com/mattn/go-isatty v0.0.4 // indirect - github.com/urfave/cli v1.20.1-0.20180226030253-8e01ec4cd3e2 - golang.org/x/sys v0.0.0-20170407050850-f3918c30c5c2 // indirect -) diff --git a/vendor/github.com/aybabtme/humanlog/go.sum b/vendor/github.com/aybabtme/humanlog/go.sum deleted file mode 100644 index 8359a61f6..000000000 --- a/vendor/github.com/aybabtme/humanlog/go.sum +++ /dev/null @@ -1,16 +0,0 @@ -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= -github.com/fatih/color v1.7.1-0.20180516100307-2d684516a886 h1:NAFoy+QgUpERgK3y1xiVh5HcOvSeZHpXTTo5qnvnuK4= -github.com/fatih/color v1.7.1-0.20180516100307-2d684516a886/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/mattn/go-colorable v0.1.0 h1:v2XXALHHh6zHfYTJ+cSkwtyffnaOyR1MXaA91mTrb8o= -github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/urfave/cli v1.20.1-0.20180226030253-8e01ec4cd3e2 h1:xAkHCttGHKXIr10OSiFzNt0XOJyHMdng0ylSynT8sMo= -github.com/urfave/cli v1.20.1-0.20180226030253-8e01ec4cd3e2/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -golang.org/x/sys v0.0.0-20170407050850-f3918c30c5c2 h1:niKkabq6kYToDafvvFw9MeTkT4ifSvpOCRP6pFxOCZE= -golang.org/x/sys v0.0.0-20170407050850-f3918c30c5c2/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/cli/safeexec/go.mod b/vendor/github.com/cli/safeexec/go.mod deleted file mode 100644 index 266fab447..000000000 --- a/vendor/github.com/cli/safeexec/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/cli/safeexec - -go 1.15 diff --git a/vendor/github.com/creack/pty/go.mod b/vendor/github.com/creack/pty/go.mod deleted file mode 100644 index e48decaf4..000000000 --- a/vendor/github.com/creack/pty/go.mod +++ /dev/null @@ -1,4 +0,0 @@ -module github.com/creack/pty - -go 1.13 - diff --git a/vendor/github.com/fatih/color/go.mod b/vendor/github.com/fatih/color/go.mod deleted file mode 100644 index bc0df7545..000000000 --- a/vendor/github.com/fatih/color/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/fatih/color - -go 1.13 - -require ( - github.com/mattn/go-colorable v0.1.4 - github.com/mattn/go-isatty v0.0.11 -) diff --git a/vendor/github.com/fatih/color/go.sum b/vendor/github.com/fatih/color/go.sum deleted file mode 100644 index 44328a8db..000000000 --- a/vendor/github.com/fatih/color/go.sum +++ /dev/null @@ -1,8 +0,0 @@ -github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/gdamore/encoding/go.mod b/vendor/github.com/gdamore/encoding/go.mod deleted file mode 100644 index e91b30d5a..000000000 --- a/vendor/github.com/gdamore/encoding/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/gdamore/encoding - -go 1.9 - -require golang.org/x/text v0.3.0 diff --git a/vendor/github.com/gdamore/encoding/go.sum b/vendor/github.com/gdamore/encoding/go.sum deleted file mode 100644 index 6bad37b2a..000000000 --- a/vendor/github.com/gdamore/encoding/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/vendor/github.com/gdamore/tcell/v2/go.mod b/vendor/github.com/gdamore/tcell/v2/go.mod deleted file mode 100644 index 4b10eda4e..000000000 --- a/vendor/github.com/gdamore/tcell/v2/go.mod +++ /dev/null @@ -1,12 +0,0 @@ -module github.com/gdamore/tcell/v2 - -go 1.12 - -require ( - github.com/gdamore/encoding v1.0.0 - github.com/lucasb-eyer/go-colorful v1.2.0 - github.com/mattn/go-runewidth v0.0.13 - golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02 - golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf - golang.org/x/text v0.3.7 -) diff --git a/vendor/github.com/gdamore/tcell/v2/go.sum b/vendor/github.com/gdamore/tcell/v2/go.sum deleted file mode 100644 index 84e8300d6..000000000 --- a/vendor/github.com/gdamore/tcell/v2/go.sum +++ /dev/null @@ -1,17 +0,0 @@ -github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= -github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= -github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= -github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02 h1:7NCfEGl0sfUojmX78nK9pBJuUlSZWEJA/TwASvfiPLo= -golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= -golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/vendor/github.com/go-errors/errors/go.mod b/vendor/github.com/go-errors/errors/go.mod deleted file mode 100644 index a70bad1b2..000000000 --- a/vendor/github.com/go-errors/errors/go.mod +++ /dev/null @@ -1,6 +0,0 @@ -module github.com/go-errors/errors - -go 1.14 - -// Was not API-compatible with earlier or later releases. -retract v1.3.0 diff --git a/vendor/github.com/go-git/go-billy/v5/go.mod b/vendor/github.com/go-git/go-billy/v5/go.mod deleted file mode 100644 index 78ce0af2a..000000000 --- a/vendor/github.com/go-git/go-billy/v5/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/go-git/go-billy/v5 - -require ( - github.com/kr/text v0.2.0 // indirect - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f -) - -go 1.13 diff --git a/vendor/github.com/go-git/go-billy/v5/go.sum b/vendor/github.com/go-git/go-billy/v5/go.sum deleted file mode 100644 index cdc052bc7..000000000 --- a/vendor/github.com/go-git/go-billy/v5/go.sum +++ /dev/null @@ -1,14 +0,0 @@ -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/go-git/go-billy v1.0.0 h1:bXR6Zu3opPSg0R4dDxqaLglY4rxw7ja7wS16qSpOKL4= -github.com/go-git/go-billy v3.1.0+incompatible h1:dwrJ8G2Jt1srYgIJs+lRjA36qBY68O2Lg5idKG8ef5M= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/vendor/github.com/go-logfmt/logfmt/go.mod b/vendor/github.com/go-logfmt/logfmt/go.mod deleted file mode 100644 index df7192988..000000000 --- a/vendor/github.com/go-logfmt/logfmt/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/go-logfmt/logfmt - -go 1.13 diff --git a/vendor/github.com/gookit/color/go.mod b/vendor/github.com/gookit/color/go.mod deleted file mode 100644 index cd94efc3a..000000000 --- a/vendor/github.com/gookit/color/go.mod +++ /dev/null @@ -1,9 +0,0 @@ -module github.com/gookit/color - -go 1.12 - -require ( - github.com/stretchr/testify v1.6.1 - github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 - golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 -) diff --git a/vendor/github.com/gookit/color/go.sum b/vendor/github.com/gookit/color/go.sum deleted file mode 100644 index 2d67cba01..000000000 --- a/vendor/github.com/gookit/color/go.sum +++ /dev/null @@ -1,15 +0,0 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= -github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/imdario/mergo/go.mod b/vendor/github.com/imdario/mergo/go.mod deleted file mode 100644 index 3d689d93e..000000000 --- a/vendor/github.com/imdario/mergo/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/imdario/mergo - -go 1.13 - -require gopkg.in/yaml.v2 v2.3.0 diff --git a/vendor/github.com/imdario/mergo/go.sum b/vendor/github.com/imdario/mergo/go.sum deleted file mode 100644 index 168980da5..000000000 --- a/vendor/github.com/imdario/mergo/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/integrii/flaggy/go.mod b/vendor/github.com/integrii/flaggy/go.mod deleted file mode 100644 index 5f87729d1..000000000 --- a/vendor/github.com/integrii/flaggy/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/integrii/flaggy - -go 1.12 diff --git a/vendor/github.com/jesseduffield/go-git/v5/go.mod b/vendor/github.com/jesseduffield/go-git/v5/go.mod deleted file mode 100644 index c6a9be01f..000000000 --- a/vendor/github.com/jesseduffield/go-git/v5/go.mod +++ /dev/null @@ -1,28 +0,0 @@ -module github.com/jesseduffield/go-git/v5 - -require ( - github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect - github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 - github.com/emirpasic/gods v1.12.0 - github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect - github.com/gliderlabs/ssh v0.2.2 - github.com/go-git/gcfg v1.5.0 - github.com/go-git/go-billy/v5 v5.0.0 - github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 - github.com/google/go-cmp v0.3.0 - github.com/imdario/mergo v0.3.9 - github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 - github.com/jessevdk/go-flags v1.4.0 - github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd - github.com/mitchellh/go-homedir v1.1.0 - github.com/pkg/errors v0.8.1 // indirect - github.com/sergi/go-diff v1.1.0 - github.com/xanzy/ssh-agent v0.2.1 - golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 - golang.org/x/net v0.0.0-20200301022130-244492dfa37a - golang.org/x/text v0.3.2 - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f - gopkg.in/warnings.v0 v0.1.2 // indirect -) - -go 1.13 diff --git a/vendor/github.com/jesseduffield/go-git/v5/go.sum b/vendor/github.com/jesseduffield/go-git/v5/go.sum deleted file mode 100644 index 9af1b0611..000000000 --- a/vendor/github.com/jesseduffield/go-git/v5/go.sum +++ /dev/null @@ -1,82 +0,0 @@ -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= -github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc= -github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= -github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M= -github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= -github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/jesseduffield/gocui/go.mod b/vendor/github.com/jesseduffield/gocui/go.mod deleted file mode 100644 index d7f11d16c..000000000 --- a/vendor/github.com/jesseduffield/gocui/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/jesseduffield/gocui - -go 1.12 - -require ( - github.com/gdamore/tcell/v2 v2.4.0 - github.com/go-errors/errors v1.0.2 - github.com/mattn/go-runewidth v0.0.10 - github.com/stretchr/testify v1.7.0 -) diff --git a/vendor/github.com/jesseduffield/gocui/go.sum b/vendor/github.com/jesseduffield/gocui/go.sum deleted file mode 100644 index 8ed3f9b35..000000000 --- a/vendor/github.com/jesseduffield/gocui/go.sum +++ /dev/null @@ -1,29 +0,0 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= -github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= -github.com/gdamore/tcell/v2 v2.4.0 h1:W6dxJEmaxYvhICFoTY3WrLLEXsQ11SaFnKGVEXW57KM= -github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU= -github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4= -github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= -github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= -github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= -github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY= -github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= -golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/jesseduffield/minimal/gitignore/go.mod b/vendor/github.com/jesseduffield/minimal/gitignore/go.mod deleted file mode 100644 index 0137e6b0f..000000000 --- a/vendor/github.com/jesseduffield/minimal/gitignore/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/jesseduffield/minimal/gitignore - -go 1.15 - -require github.com/gobwas/glob v0.2.3 diff --git a/vendor/github.com/jesseduffield/minimal/gitignore/go.sum b/vendor/github.com/jesseduffield/minimal/gitignore/go.sum deleted file mode 100644 index 39fa9fa07..000000000 --- a/vendor/github.com/jesseduffield/minimal/gitignore/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= diff --git a/vendor/github.com/kardianos/osext/go.mod b/vendor/github.com/kardianos/osext/go.mod deleted file mode 100644 index 66c73d7c2..000000000 --- a/vendor/github.com/kardianos/osext/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/kardianos/osext diff --git a/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod b/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod deleted file mode 100644 index 716c61312..000000000 --- a/vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/konsorten/go-windows-terminal-sequences diff --git a/vendor/github.com/kyokomi/emoji/v2/go.mod b/vendor/github.com/kyokomi/emoji/v2/go.mod deleted file mode 100644 index f18dda204..000000000 --- a/vendor/github.com/kyokomi/emoji/v2/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/kyokomi/emoji/v2 - -go 1.14 diff --git a/vendor/github.com/lucasb-eyer/go-colorful/go.mod b/vendor/github.com/lucasb-eyer/go-colorful/go.mod deleted file mode 100644 index 35925f3d7..000000000 --- a/vendor/github.com/lucasb-eyer/go-colorful/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/lucasb-eyer/go-colorful - -go 1.12 diff --git a/vendor/github.com/mattn/go-colorable/go.mod b/vendor/github.com/mattn/go-colorable/go.mod deleted file mode 100644 index 27351c027..000000000 --- a/vendor/github.com/mattn/go-colorable/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/mattn/go-colorable - -require ( - github.com/mattn/go-isatty v0.0.14 - golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect -) - -go 1.13 diff --git a/vendor/github.com/mattn/go-colorable/go.sum b/vendor/github.com/mattn/go-colorable/go.sum deleted file mode 100644 index 40c33b333..000000000 --- a/vendor/github.com/mattn/go-colorable/go.sum +++ /dev/null @@ -1,5 +0,0 @@ -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/vendor/github.com/mattn/go-isatty/go.mod b/vendor/github.com/mattn/go-isatty/go.mod deleted file mode 100644 index c9a20b7f3..000000000 --- a/vendor/github.com/mattn/go-isatty/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/mattn/go-isatty - -go 1.12 - -require golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c diff --git a/vendor/github.com/mattn/go-isatty/go.sum b/vendor/github.com/mattn/go-isatty/go.sum deleted file mode 100644 index 912e29cbc..000000000 --- a/vendor/github.com/mattn/go-isatty/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/mattn/go-runewidth/go.mod b/vendor/github.com/mattn/go-runewidth/go.mod deleted file mode 100644 index 62dba1bfc..000000000 --- a/vendor/github.com/mattn/go-runewidth/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/mattn/go-runewidth - -go 1.9 - -require github.com/rivo/uniseg v0.2.0 diff --git a/vendor/github.com/mattn/go-runewidth/go.sum b/vendor/github.com/mattn/go-runewidth/go.sum deleted file mode 100644 index 03f902d56..000000000 --- a/vendor/github.com/mattn/go-runewidth/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= diff --git a/vendor/github.com/mitchellh/go-homedir/go.mod b/vendor/github.com/mitchellh/go-homedir/go.mod deleted file mode 100644 index 7efa09a04..000000000 --- a/vendor/github.com/mitchellh/go-homedir/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/mitchellh/go-homedir diff --git a/vendor/github.com/rivo/uniseg/go.mod b/vendor/github.com/rivo/uniseg/go.mod deleted file mode 100644 index a54280b2d..000000000 --- a/vendor/github.com/rivo/uniseg/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/rivo/uniseg - -go 1.12 diff --git a/vendor/github.com/sanity-io/litter/go.mod b/vendor/github.com/sanity-io/litter/go.mod deleted file mode 100644 index c1c20c939..000000000 --- a/vendor/github.com/sanity-io/litter/go.mod +++ /dev/null @@ -1,9 +0,0 @@ -module github.com/sanity-io/litter - -go 1.14 - -require ( - github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b // indirect - github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0 // indirect - github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312 -) diff --git a/vendor/github.com/sanity-io/litter/go.sum b/vendor/github.com/sanity-io/litter/go.sum deleted file mode 100644 index 800ae0053..000000000 --- a/vendor/github.com/sanity-io/litter/go.sum +++ /dev/null @@ -1,6 +0,0 @@ -github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b h1:XxMZvQZtTXpWMNWK82vdjCLCe7uGMFXdTsJH0v3Hkvw= -github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0 h1:GD+A8+e+wFkqje55/2fOVnZPkoDIu1VooBWfNrnY8Uo= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312 h1:UsFdQ3ZmlzS0BqZYGxvYaXvFGUbCmPGy8DM7qWJJiIQ= -github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= diff --git a/vendor/github.com/sirupsen/logrus/go.mod b/vendor/github.com/sirupsen/logrus/go.mod deleted file mode 100644 index 12fdf9898..000000000 --- a/vendor/github.com/sirupsen/logrus/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/sirupsen/logrus - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/konsorten/go-windows-terminal-sequences v1.0.1 - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/objx v0.1.1 // indirect - github.com/stretchr/testify v1.2.2 - golang.org/x/sys v0.0.0-20190422165155-953cdadca894 -) diff --git a/vendor/github.com/sirupsen/logrus/go.sum b/vendor/github.com/sirupsen/logrus/go.sum deleted file mode 100644 index 596c318b9..000000000 --- a/vendor/github.com/sirupsen/logrus/go.sum +++ /dev/null @@ -1,16 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs= -github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/xanzy/ssh-agent/go.mod b/vendor/github.com/xanzy/ssh-agent/go.mod deleted file mode 100644 index 6664c4888..000000000 --- a/vendor/github.com/xanzy/ssh-agent/go.mod +++ /dev/null @@ -1,6 +0,0 @@ -module github.com/xanzy/ssh-agent - -require ( - golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2 - golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0 // indirect -) diff --git a/vendor/github.com/xanzy/ssh-agent/go.sum b/vendor/github.com/xanzy/ssh-agent/go.sum deleted file mode 100644 index a9a001692..000000000 --- a/vendor/github.com/xanzy/ssh-agent/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2 h1:NwxKRvbkH5MsNkvOtPZi3/3kmI8CAzs3mtv+GLQMkNo= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0 h1:bzeyCHgoAyjZjAhvTpks+qM7sdlh4cCSitmXeCEO3B4= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/xo/terminfo/go.mod b/vendor/github.com/xo/terminfo/go.mod deleted file mode 100644 index 7a3a7597a..000000000 --- a/vendor/github.com/xo/terminfo/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/xo/terminfo - -go 1.15 diff --git a/vendor/github.com/xo/terminfo/go.sum b/vendor/github.com/xo/terminfo/go.sum deleted file mode 100644 index e69de29bb..000000000 diff --git a/vendor/golang.org/x/term/go.mod b/vendor/golang.org/x/term/go.mod deleted file mode 100644 index edf0e5b1d..000000000 --- a/vendor/golang.org/x/term/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module golang.org/x/term - -go 1.17 - -require golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 diff --git a/vendor/golang.org/x/term/go.sum b/vendor/golang.org/x/term/go.sum deleted file mode 100644 index ff132135e..000000000 --- a/vendor/golang.org/x/term/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/vendor/gopkg.in/yaml.v3/go.mod b/vendor/gopkg.in/yaml.v3/go.mod deleted file mode 100644 index f407ea321..000000000 --- a/vendor/gopkg.in/yaml.v3/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module "gopkg.in/yaml.v3" - -require ( - "gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405 -) diff --git a/vendor/modules.txt b/vendor/modules.txt index bd07c38aa..95470036a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -5,20 +5,22 @@ github.com/OpenPeeDeeP/xdg ## explicit github.com/atotto/clipboard # github.com/aybabtme/humanlog v0.4.1 -## explicit +## explicit; go 1.13 github.com/aybabtme/humanlog # github.com/cli/safeexec v1.0.0 -## explicit +## explicit; go 1.15 github.com/cli/safeexec # github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 ## explicit github.com/cloudfoundry/jibber_jabber # github.com/creack/pty v1.1.11 -## explicit +## explicit; go 1.13 github.com/creack/pty # github.com/davecgh/go-spew v1.1.1 +## explicit github.com/davecgh/go-spew/spew # github.com/emirpasic/gods v1.12.0 +## explicit github.com/emirpasic/gods/containers github.com/emirpasic/gods/lists github.com/emirpasic/gods/lists/arraylist @@ -26,15 +28,16 @@ github.com/emirpasic/gods/trees github.com/emirpasic/gods/trees/binaryheap github.com/emirpasic/gods/utils # github.com/fatih/color v1.9.0 -## explicit +## explicit; go 1.13 github.com/fatih/color # github.com/fsnotify/fsnotify v1.4.7 ## explicit github.com/fsnotify/fsnotify # github.com/gdamore/encoding v1.0.0 +## explicit; go 1.9 github.com/gdamore/encoding # github.com/gdamore/tcell/v2 v2.4.1-0.20220313203054-2a1a1b586447 -## explicit +## explicit; go 1.12 github.com/gdamore/tcell/v2 github.com/gdamore/tcell/v2/terminfo github.com/gdamore/tcell/v2/terminfo/a/aixterm @@ -75,23 +78,26 @@ github.com/gdamore/tcell/v2/terminfo/x/xterm github.com/gdamore/tcell/v2/terminfo/x/xterm_kitty github.com/gdamore/tcell/v2/terminfo/x/xterm_termite # github.com/go-errors/errors v1.4.1 -## explicit +## explicit; go 1.14 github.com/go-errors/errors # github.com/go-git/gcfg v1.5.0 +## explicit github.com/go-git/gcfg github.com/go-git/gcfg/scanner github.com/go-git/gcfg/token github.com/go-git/gcfg/types # github.com/go-git/go-billy/v5 v5.0.0 +## explicit; go 1.13 github.com/go-git/go-billy/v5 github.com/go-git/go-billy/v5/helper/chroot github.com/go-git/go-billy/v5/helper/polyfill github.com/go-git/go-billy/v5/osfs github.com/go-git/go-billy/v5/util # github.com/go-logfmt/logfmt v0.5.0 -## explicit +## explicit; go 1.13 github.com/go-logfmt/logfmt # github.com/gobwas/glob v0.2.3 +## explicit github.com/gobwas/glob github.com/gobwas/glob/compiler github.com/gobwas/glob/match @@ -100,23 +106,22 @@ github.com/gobwas/glob/syntax/ast github.com/gobwas/glob/syntax/lexer github.com/gobwas/glob/util/runes github.com/gobwas/glob/util/strings -# github.com/golang/protobuf v1.3.2 -## explicit # github.com/google/go-cmp v0.5.6 -## explicit +## explicit; go 1.8 # github.com/gookit/color v1.4.2 -## explicit +## explicit; go 1.12 github.com/gookit/color # github.com/imdario/mergo v0.3.11 -## explicit +## explicit; go 1.13 github.com/imdario/mergo # github.com/integrii/flaggy v1.4.0 -## explicit +## explicit; go 1.12 github.com/integrii/flaggy # github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 +## explicit github.com/jbenet/go-context/io # github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 -## explicit +## explicit; go 1.13 github.com/jesseduffield/go-git/v5 github.com/jesseduffield/go-git/v5/config github.com/jesseduffield/go-git/v5/internal/revision @@ -160,10 +165,10 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/index github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame github.com/jesseduffield/go-git/v5/utils/merkletrie/noder # github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 -## explicit +## explicit; go 1.12 github.com/jesseduffield/gocui # github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e -## explicit +## explicit; go 1.15 github.com/jesseduffield/minimal/gitignore # github.com/jesseduffield/yaml v2.1.0+incompatible ## explicit @@ -172,32 +177,36 @@ github.com/jesseduffield/yaml ## explicit github.com/kardianos/osext # github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd +## explicit github.com/kevinburke/ssh_config # github.com/konsorten/go-windows-terminal-sequences v1.0.2 ## explicit github.com/konsorten/go-windows-terminal-sequences # github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 +## explicit github.com/kr/logfmt # github.com/kylelemons/godebug v1.1.0 -## explicit +## explicit; go 1.11 # github.com/kyokomi/emoji/v2 v2.2.8 -## explicit +## explicit; go 1.14 github.com/kyokomi/emoji/v2 # github.com/lucasb-eyer/go-colorful v1.2.0 -## explicit +## explicit; go 1.12 github.com/lucasb-eyer/go-colorful # github.com/mattn/go-colorable v0.1.11 -## explicit +## explicit; go 1.13 github.com/mattn/go-colorable # github.com/mattn/go-isatty v0.0.14 +## explicit; go 1.12 github.com/mattn/go-isatty # github.com/mattn/go-runewidth v0.0.13 -## explicit +## explicit; go 1.9 github.com/mattn/go-runewidth # github.com/mgutz/str v1.2.0 ## explicit github.com/mgutz/str # github.com/mitchellh/go-homedir v1.1.0 +## explicit github.com/mitchellh/go-homedir # github.com/onsi/ginkgo v1.10.3 ## explicit @@ -207,14 +216,16 @@ github.com/mitchellh/go-homedir ## explicit github.com/pmezard/go-difflib/difflib # github.com/rivo/uniseg v0.2.0 +## explicit; go 1.12 github.com/rivo/uniseg # github.com/sahilm/fuzzy v0.1.0 ## explicit github.com/sahilm/fuzzy # github.com/sanity-io/litter v1.5.2 -## explicit +## explicit; go 1.14 github.com/sanity-io/litter # github.com/sergi/go-diff v1.1.0 +## explicit; go 1.12 github.com/sergi/go-diff/diffmatchpatch # github.com/sirupsen/logrus v1.4.2 ## explicit @@ -223,15 +234,16 @@ github.com/sirupsen/logrus ## explicit github.com/spkg/bom # github.com/stretchr/testify v1.7.0 -## explicit +## explicit; go 1.13 github.com/stretchr/testify/assert # github.com/xanzy/ssh-agent v0.2.1 +## explicit github.com/xanzy/ssh-agent # github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 -## explicit +## explicit; go 1.15 github.com/xo/terminfo # golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 -## explicit +## explicit; go 1.11 golang.org/x/crypto/blowfish golang.org/x/crypto/cast5 golang.org/x/crypto/chacha20 @@ -251,21 +263,22 @@ golang.org/x/crypto/ssh/agent golang.org/x/crypto/ssh/internal/bcrypt_pbkdf golang.org/x/crypto/ssh/knownhosts # golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c -## explicit +## explicit; go 1.11 golang.org/x/net/context golang.org/x/net/internal/socks golang.org/x/net/proxy # golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 -## explicit +## explicit; go 1.17 golang.org/x/sys/cpu golang.org/x/sys/internal/unsafeheader golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows # golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 -## explicit +## explicit; go 1.17 golang.org/x/term # golang.org/x/text v0.3.7 +## explicit; go 1.17 golang.org/x/text/encoding golang.org/x/text/encoding/internal/identifier golang.org/x/text/transform @@ -273,6 +286,8 @@ golang.org/x/text/transform ## explicit gopkg.in/ozeidan/fuzzy-patricia.v3/patricia # gopkg.in/warnings.v0 v0.1.2 +## explicit gopkg.in/warnings.v0 # gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c +## explicit gopkg.in/yaml.v3 From 4b56d428ffda44cf433d7cfdd83ea99417ec3e86 Mon Sep 17 00:00:00 2001 From: Moritz Haase Date: Fri, 18 Mar 2022 10:59:58 +0100 Subject: [PATCH 102/385] pkg/updates: Fix resource availability check in Updater When trying to download an update, a 'Could not find any binary at ...' error message is shown erroneously. This happens since when checking the availability, a response code of 403 ('Forbidden') instead of 200 ('OK') is expected. Since 'http.Head()' handles redirects automatically, there is no need to also accept 3xx status codes. Fixes #1450. --- pkg/updates/updates.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/updates/updates.go b/pkg/updates/updates.go index 95fcfa0eb..58c93fa7d 100644 --- a/pkg/updates/updates.go +++ b/pkg/updates/updates.go @@ -329,7 +329,6 @@ func (u *Updater) verifyResourceFound(rawUrl string) bool { } defer resp.Body.Close() u.Log.Info("Received status code ", resp.StatusCode) - // 403 means the resource is there (not going to bother adding extra request headers) - // 404 means its not - return resp.StatusCode == 403 + // OK (200) indicates that the resource is present. + return resp.StatusCode == http.StatusOK } From d93fef4c61db20dd9e2bb535c2fbb742cdbed60a Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 19 Mar 2022 09:31:52 +1100 Subject: [PATCH 103/385] use generics to DRY up context code --- pkg/gui/commit_files_panel.go | 4 +-- pkg/gui/context/basic_view_model.go | 34 ++++++++++++++++++ pkg/gui/context/branches_context.go | 36 +++---------------- pkg/gui/context/commit_files_context.go | 2 +- pkg/gui/context/list_context_trait.go | 4 +-- pkg/gui/context/local_commits_context.go | 22 ++---------- pkg/gui/context/menu_context.go | 17 ++------- pkg/gui/context/reflog_commits_context.go | 34 ++---------------- pkg/gui/context/remote_branches_context.go | 36 +++---------------- pkg/gui/context/remotes_context.go | 34 ++---------------- pkg/gui/context/stash_context.go | 34 ++---------------- pkg/gui/context/sub_commits_context.go | 34 ++---------------- pkg/gui/context/submodules_context.go | 34 ++---------------- pkg/gui/context/suggestions_context.go | 34 ++---------------- pkg/gui/context/tags_context.go | 36 +++---------------- pkg/gui/context/traits/list_cursor.go | 8 ++--- pkg/gui/context/working_tree_context.go | 2 +- .../controllers/commits_files_controller.go | 4 +-- pkg/gui/controllers/files_controller.go | 10 +++--- .../controllers/files_remove_controller.go | 2 +- pkg/gui/controllers/list_controller.go | 6 ++-- .../controllers/local_commits_controller.go | 2 +- pkg/gui/files_panel.go | 2 +- pkg/gui/filetree/commit_file_tree.go | 6 ++-- .../filetree/commit_file_tree_view_model.go | 12 +++---- pkg/gui/filetree/file_tree.go | 8 ++--- pkg/gui/filetree/file_tree_view_model.go | 14 ++++---- pkg/gui/filtering_menu_panel.go | 2 +- pkg/gui/list_context_config.go | 2 +- pkg/gui/patch_building_panel.go | 4 +-- pkg/gui/types/context.go | 2 +- 31 files changed, 117 insertions(+), 364 deletions(-) create mode 100644 pkg/gui/context/basic_view_model.go diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index 0ada68090..21afc54f4 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -12,7 +12,7 @@ func (gui *Gui) onCommitFileFocus() error { } func (gui *Gui) commitFilesRenderToMain() error { - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() + node := gui.State.Contexts.CommitFiles.GetSelected() if node == nil { return nil } @@ -78,7 +78,7 @@ func (gui *Gui) refreshCommitFilesView() error { } func (gui *Gui) getSelectedCommitFileName() string { - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() + node := gui.State.Contexts.CommitFiles.GetSelected() if node == nil { return "" } diff --git a/pkg/gui/context/basic_view_model.go b/pkg/gui/context/basic_view_model.go new file mode 100644 index 000000000..a53be4d91 --- /dev/null +++ b/pkg/gui/context/basic_view_model.go @@ -0,0 +1,34 @@ +package context + +import "github.com/jesseduffield/lazygit/pkg/gui/context/traits" + +type BasicViewModel[T any] struct { + *traits.ListCursor + getModel func() []T +} + +func NewBasicViewModel[T any](getModel func() []T) *BasicViewModel[T] { + self := &BasicViewModel[T]{ + getModel: getModel, + } + + self.ListCursor = traits.NewListCursor(self) + + return self +} + +func (self *BasicViewModel[T]) Len() int { + return len(self.getModel()) +} + +func (self *BasicViewModel[T]) GetSelected() T { + if self.Len() == 0 { + return Zero[T]() + } + + return self.getModel()[self.GetSelectedLineIdx()] +} + +func Zero[T any]() T { + return *new(T) +} diff --git a/pkg/gui/context/branches_context.go b/pkg/gui/context/branches_context.go index 146810a86..e5de639d9 100644 --- a/pkg/gui/context/branches_context.go +++ b/pkg/gui/context/branches_context.go @@ -3,12 +3,11 @@ package context import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context/traits" "github.com/jesseduffield/lazygit/pkg/gui/types" ) type BranchesContext struct { - *BranchesViewModel + *BasicViewModel[*models.Branch] *ListContextTrait } @@ -25,10 +24,10 @@ func NewBranchesContext( c *types.HelperCommon, ) *BranchesContext { - viewModel := NewBranchesViewModel(getModel) + viewModel := NewBasicViewModel(getModel) return &BranchesContext{ - BranchesViewModel: viewModel, + BasicViewModel: viewModel, ListContextTrait: &ListContextTrait{ Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ ViewName: "branches", @@ -58,34 +57,7 @@ func (self *BranchesContext) GetSelectedItemId() string { return item.ID() } -type BranchesViewModel struct { - *traits.ListCursor - getModel func() []*models.Branch -} - -func NewBranchesViewModel(getModel func() []*models.Branch) *BranchesViewModel { - self := &BranchesViewModel{ - getModel: getModel, - } - - self.ListCursor = traits.NewListCursor(self) - - return self -} - -func (self *BranchesViewModel) GetItemsLength() int { - return len(self.getModel()) -} - -func (self *BranchesViewModel) GetSelected() *models.Branch { - if self.GetItemsLength() == 0 { - return nil - } - - return self.getModel()[self.GetSelectedLineIdx()] -} - -func (self *BranchesViewModel) GetSelectedRefName() string { +func (self *BranchesContext) GetSelectedRefName() string { item := self.GetSelected() if item == nil { return "" diff --git a/pkg/gui/context/commit_files_context.go b/pkg/gui/context/commit_files_context.go index 8f9bd91f7..0576be102 100644 --- a/pkg/gui/context/commit_files_context.go +++ b/pkg/gui/context/commit_files_context.go @@ -52,7 +52,7 @@ func NewCommitFilesContext( } func (self *CommitFilesContext) GetSelectedItemId() string { - item := self.GetSelectedFileNode() + item := self.GetSelected() if item == nil { return "" } diff --git a/pkg/gui/context/list_context_trait.go b/pkg/gui/context/list_context_trait.go index e508c8029..a10f0e3e9 100644 --- a/pkg/gui/context/list_context_trait.go +++ b/pkg/gui/context/list_context_trait.go @@ -27,7 +27,7 @@ func (self *ListContextTrait) GetViewTrait() types.IViewTrait { func (self *ListContextTrait) FocusLine() { // we need a way of knowing whether we've rendered to the view yet. self.viewTrait.FocusPoint(self.list.GetSelectedLineIdx()) - self.viewTrait.SetFooter(formatListFooter(self.list.GetSelectedLineIdx(), self.list.GetItemsLength())) + self.viewTrait.SetFooter(formatListFooter(self.list.GetSelectedLineIdx(), self.list.Len())) } func formatListFooter(selectedLineIdx int, length int) string { @@ -49,7 +49,7 @@ func (self *ListContextTrait) HandleFocusLost() error { // OnFocus assumes that the content of the context has already been rendered to the view. OnRender is the function which actually renders the content to the view func (self *ListContextTrait) HandleRender() error { self.list.RefreshSelectedIdx() - content := utils.RenderDisplayStrings(self.getDisplayStrings(0, self.list.GetItemsLength())) + content := utils.RenderDisplayStrings(self.getDisplayStrings(0, self.list.Len())) self.viewTrait.SetContent(content) self.c.Render() diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index 2930348e8..d8d64392c 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -3,7 +3,6 @@ package context import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context/traits" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -60,8 +59,7 @@ func (self *LocalCommitsContext) GetSelectedItemId() string { } type LocalCommitsViewModel struct { - *traits.ListCursor - getModel func() []*models.Commit + *BasicViewModel[*models.Commit] // If this is true we limit the amount of commits we load, for the sake of keeping things fast. // If the user attempts to scroll past the end of the list, we will load more commits. @@ -73,12 +71,10 @@ type LocalCommitsViewModel struct { func NewLocalCommitsViewModel(getModel func() []*models.Commit) *LocalCommitsViewModel { self := &LocalCommitsViewModel{ - getModel: getModel, - limitCommits: true, + BasicViewModel: NewBasicViewModel(getModel), + limitCommits: true, } - self.ListCursor = traits.NewListCursor(self) - return self } @@ -96,18 +92,6 @@ func (self *LocalCommitsContext) GetSelectedRefName() string { return item.RefName() } -func (self *LocalCommitsViewModel) GetItemsLength() int { - return len(self.getModel()) -} - -func (self *LocalCommitsViewModel) GetSelected() *models.Commit { - if self.GetItemsLength() == 0 { - return nil - } - - return self.getModel()[self.GetSelectedLineIdx()] -} - func (self *LocalCommitsViewModel) SetLimitCommits(value bool) { self.limitCommits = value } diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go index 2e75ba25a..67d6b126a 100644 --- a/pkg/gui/context/menu_context.go +++ b/pkg/gui/context/menu_context.go @@ -2,7 +2,6 @@ package context import ( "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazygit/pkg/gui/context/traits" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -59,8 +58,8 @@ func (self *MenuContext) GetSelectedItemId() string { } type MenuViewModel struct { - *traits.ListCursor menuItems []*types.MenuItem + *BasicViewModel[*types.MenuItem] } func NewMenuViewModel() *MenuViewModel { @@ -68,23 +67,11 @@ func NewMenuViewModel() *MenuViewModel { menuItems: nil, } - self.ListCursor = traits.NewListCursor(self) + self.BasicViewModel = NewBasicViewModel(func() []*types.MenuItem { return self.menuItems }) return self } -func (self *MenuViewModel) GetItemsLength() int { - return len(self.menuItems) -} - -func (self *MenuViewModel) GetSelected() *types.MenuItem { - if self.GetItemsLength() == 0 { - return nil - } - - return self.menuItems[self.GetSelectedLineIdx()] -} - func (self *MenuViewModel) SetMenuItems(items []*types.MenuItem) { self.menuItems = items } diff --git a/pkg/gui/context/reflog_commits_context.go b/pkg/gui/context/reflog_commits_context.go index fa136a7d4..815805515 100644 --- a/pkg/gui/context/reflog_commits_context.go +++ b/pkg/gui/context/reflog_commits_context.go @@ -3,12 +3,11 @@ package context import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context/traits" "github.com/jesseduffield/lazygit/pkg/gui/types" ) type ReflogCommitsContext struct { - *ReflogCommitsViewModel + *BasicViewModel[*models.Commit] *ListContextTrait } @@ -25,10 +24,10 @@ func NewReflogCommitsContext( c *types.HelperCommon, ) *ReflogCommitsContext { - viewModel := NewReflogCommitsViewModel(getModel) + viewModel := NewBasicViewModel(getModel) return &ReflogCommitsContext{ - ReflogCommitsViewModel: viewModel, + BasicViewModel: viewModel, ListContextTrait: &ListContextTrait{ Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ ViewName: "commits", @@ -71,30 +70,3 @@ func (self *ReflogCommitsContext) GetSelectedRefName() string { return item.RefName() } - -type ReflogCommitsViewModel struct { - *traits.ListCursor - getModel func() []*models.Commit -} - -func NewReflogCommitsViewModel(getModel func() []*models.Commit) *ReflogCommitsViewModel { - self := &ReflogCommitsViewModel{ - getModel: getModel, - } - - self.ListCursor = traits.NewListCursor(self) - - return self -} - -func (self *ReflogCommitsViewModel) GetItemsLength() int { - return len(self.getModel()) -} - -func (self *ReflogCommitsViewModel) GetSelected() *models.Commit { - if self.GetItemsLength() == 0 { - return nil - } - - return self.getModel()[self.GetSelectedLineIdx()] -} diff --git a/pkg/gui/context/remote_branches_context.go b/pkg/gui/context/remote_branches_context.go index c851c96ac..3cdd43a69 100644 --- a/pkg/gui/context/remote_branches_context.go +++ b/pkg/gui/context/remote_branches_context.go @@ -3,12 +3,11 @@ package context import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context/traits" "github.com/jesseduffield/lazygit/pkg/gui/types" ) type RemoteBranchesContext struct { - *RemoteBranchesViewModel + *BasicViewModel[*models.RemoteBranch] *ListContextTrait } @@ -25,10 +24,10 @@ func NewRemoteBranchesContext( c *types.HelperCommon, ) *RemoteBranchesContext { - viewModel := NewRemoteBranchesViewModel(getModel) + viewModel := NewBasicViewModel(getModel) return &RemoteBranchesContext{ - RemoteBranchesViewModel: viewModel, + BasicViewModel: viewModel, ListContextTrait: &ListContextTrait{ Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ ViewName: "branches", @@ -58,34 +57,7 @@ func (self *RemoteBranchesContext) GetSelectedItemId() string { return item.ID() } -type RemoteBranchesViewModel struct { - *traits.ListCursor - getModel func() []*models.RemoteBranch -} - -func NewRemoteBranchesViewModel(getModel func() []*models.RemoteBranch) *RemoteBranchesViewModel { - self := &RemoteBranchesViewModel{ - getModel: getModel, - } - - self.ListCursor = traits.NewListCursor(self) - - return self -} - -func (self *RemoteBranchesViewModel) GetItemsLength() int { - return len(self.getModel()) -} - -func (self *RemoteBranchesViewModel) GetSelected() *models.RemoteBranch { - if self.GetItemsLength() == 0 { - return nil - } - - return self.getModel()[self.GetSelectedLineIdx()] -} - -func (self *RemoteBranchesViewModel) GetSelectedRefName() string { +func (self *RemoteBranchesContext) GetSelectedRefName() string { item := self.GetSelected() if item == nil { return "" diff --git a/pkg/gui/context/remotes_context.go b/pkg/gui/context/remotes_context.go index 2b6afdeb5..9cb0b6054 100644 --- a/pkg/gui/context/remotes_context.go +++ b/pkg/gui/context/remotes_context.go @@ -3,12 +3,11 @@ package context import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context/traits" "github.com/jesseduffield/lazygit/pkg/gui/types" ) type RemotesContext struct { - *RemotesViewModel + *BasicViewModel[*models.Remote] *ListContextTrait } @@ -25,10 +24,10 @@ func NewRemotesContext( c *types.HelperCommon, ) *RemotesContext { - viewModel := NewRemotesViewModel(getModel) + viewModel := NewBasicViewModel(getModel) return &RemotesContext{ - RemotesViewModel: viewModel, + BasicViewModel: viewModel, ListContextTrait: &ListContextTrait{ Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ ViewName: "branches", @@ -57,30 +56,3 @@ func (self *RemotesContext) GetSelectedItemId() string { return item.ID() } - -type RemotesViewModel struct { - *traits.ListCursor - getModel func() []*models.Remote -} - -func NewRemotesViewModel(getModel func() []*models.Remote) *RemotesViewModel { - self := &RemotesViewModel{ - getModel: getModel, - } - - self.ListCursor = traits.NewListCursor(self) - - return self -} - -func (self *RemotesViewModel) GetItemsLength() int { - return len(self.getModel()) -} - -func (self *RemotesViewModel) GetSelected() *models.Remote { - if self.GetItemsLength() == 0 { - return nil - } - - return self.getModel()[self.GetSelectedLineIdx()] -} diff --git a/pkg/gui/context/stash_context.go b/pkg/gui/context/stash_context.go index d538fadf1..e2af64d10 100644 --- a/pkg/gui/context/stash_context.go +++ b/pkg/gui/context/stash_context.go @@ -3,12 +3,11 @@ package context import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context/traits" "github.com/jesseduffield/lazygit/pkg/gui/types" ) type StashContext struct { - *StashViewModel + *BasicViewModel[*models.StashEntry] *ListContextTrait } @@ -25,10 +24,10 @@ func NewStashContext( c *types.HelperCommon, ) *StashContext { - viewModel := NewStashViewModel(getModel) + viewModel := NewBasicViewModel(getModel) return &StashContext{ - StashViewModel: viewModel, + BasicViewModel: viewModel, ListContextTrait: &ListContextTrait{ Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ ViewName: "stash", @@ -71,30 +70,3 @@ func (self *StashContext) GetSelectedRefName() string { return item.RefName() } - -type StashViewModel struct { - *traits.ListCursor - getModel func() []*models.StashEntry -} - -func NewStashViewModel(getModel func() []*models.StashEntry) *StashViewModel { - self := &StashViewModel{ - getModel: getModel, - } - - self.ListCursor = traits.NewListCursor(self) - - return self -} - -func (self *StashViewModel) GetItemsLength() int { - return len(self.getModel()) -} - -func (self *StashViewModel) GetSelected() *models.StashEntry { - if self.GetItemsLength() == 0 { - return nil - } - - return self.getModel()[self.GetSelectedLineIdx()] -} diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go index 83e76e1e0..0f16f1688 100644 --- a/pkg/gui/context/sub_commits_context.go +++ b/pkg/gui/context/sub_commits_context.go @@ -3,12 +3,11 @@ package context import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context/traits" "github.com/jesseduffield/lazygit/pkg/gui/types" ) type SubCommitsContext struct { - *SubCommitsViewModel + *BasicViewModel[*models.Commit] *ViewportListContextTrait } @@ -25,10 +24,10 @@ func NewSubCommitsContext( c *types.HelperCommon, ) *SubCommitsContext { - viewModel := NewSubCommitsViewModel(getModel) + viewModel := NewBasicViewModel(getModel) return &SubCommitsContext{ - SubCommitsViewModel: viewModel, + BasicViewModel: viewModel, ViewportListContextTrait: &ViewportListContextTrait{ ListContextTrait: &ListContextTrait{ Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ @@ -72,30 +71,3 @@ func (self *SubCommitsContext) GetSelectedRefName() string { return item.RefName() } - -type SubCommitsViewModel struct { - *traits.ListCursor - getModel func() []*models.Commit -} - -func NewSubCommitsViewModel(getModel func() []*models.Commit) *SubCommitsViewModel { - self := &SubCommitsViewModel{ - getModel: getModel, - } - - self.ListCursor = traits.NewListCursor(self) - - return self -} - -func (self *SubCommitsViewModel) GetItemsLength() int { - return len(self.getModel()) -} - -func (self *SubCommitsViewModel) GetSelected() *models.Commit { - if self.GetItemsLength() == 0 { - return nil - } - - return self.getModel()[self.GetSelectedLineIdx()] -} diff --git a/pkg/gui/context/submodules_context.go b/pkg/gui/context/submodules_context.go index 2bf5fe274..a88ae0dfc 100644 --- a/pkg/gui/context/submodules_context.go +++ b/pkg/gui/context/submodules_context.go @@ -3,12 +3,11 @@ package context import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context/traits" "github.com/jesseduffield/lazygit/pkg/gui/types" ) type SubmodulesContext struct { - *SubmodulesViewModel + *BasicViewModel[*models.SubmoduleConfig] *ListContextTrait } @@ -25,10 +24,10 @@ func NewSubmodulesContext( c *types.HelperCommon, ) *SubmodulesContext { - viewModel := NewSubmodulesViewModel(getModel) + viewModel := NewBasicViewModel(getModel) return &SubmodulesContext{ - SubmodulesViewModel: viewModel, + BasicViewModel: viewModel, ListContextTrait: &ListContextTrait{ Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ ViewName: "files", @@ -57,30 +56,3 @@ func (self *SubmodulesContext) GetSelectedItemId() string { return item.ID() } - -type SubmodulesViewModel struct { - *traits.ListCursor - getModel func() []*models.SubmoduleConfig -} - -func NewSubmodulesViewModel(getModel func() []*models.SubmoduleConfig) *SubmodulesViewModel { - self := &SubmodulesViewModel{ - getModel: getModel, - } - - self.ListCursor = traits.NewListCursor(self) - - return self -} - -func (self *SubmodulesViewModel) GetItemsLength() int { - return len(self.getModel()) -} - -func (self *SubmodulesViewModel) GetSelected() *models.SubmoduleConfig { - if self.GetItemsLength() == 0 { - return nil - } - - return self.getModel()[self.GetSelectedLineIdx()] -} diff --git a/pkg/gui/context/suggestions_context.go b/pkg/gui/context/suggestions_context.go index 6c565eedf..1291b37c8 100644 --- a/pkg/gui/context/suggestions_context.go +++ b/pkg/gui/context/suggestions_context.go @@ -2,12 +2,11 @@ package context import ( "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazygit/pkg/gui/context/traits" "github.com/jesseduffield/lazygit/pkg/gui/types" ) type SuggestionsContext struct { - *SuggestionsViewModel + *BasicViewModel[*types.Suggestion] *ListContextTrait } @@ -24,10 +23,10 @@ func NewSuggestionsContext( c *types.HelperCommon, ) *SuggestionsContext { - viewModel := NewSuggestionsViewModel(getModel) + viewModel := NewBasicViewModel(getModel) return &SuggestionsContext{ - SuggestionsViewModel: viewModel, + BasicViewModel: viewModel, ListContextTrait: &ListContextTrait{ Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ ViewName: "suggestions", @@ -56,30 +55,3 @@ func (self *SuggestionsContext) GetSelectedItemId() string { return item.Value } - -type SuggestionsViewModel struct { - *traits.ListCursor - getModel func() []*types.Suggestion -} - -func NewSuggestionsViewModel(getModel func() []*types.Suggestion) *SuggestionsViewModel { - self := &SuggestionsViewModel{ - getModel: getModel, - } - - self.ListCursor = traits.NewListCursor(self) - - return self -} - -func (self *SuggestionsViewModel) GetItemsLength() int { - return len(self.getModel()) -} - -func (self *SuggestionsViewModel) GetSelected() *types.Suggestion { - if self.GetItemsLength() == 0 { - return nil - } - - return self.getModel()[self.GetSelectedLineIdx()] -} diff --git a/pkg/gui/context/tags_context.go b/pkg/gui/context/tags_context.go index aa6211f40..fd411ec9a 100644 --- a/pkg/gui/context/tags_context.go +++ b/pkg/gui/context/tags_context.go @@ -3,12 +3,11 @@ package context import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context/traits" "github.com/jesseduffield/lazygit/pkg/gui/types" ) type TagsContext struct { - *TagsViewModel + *BasicViewModel[*models.Tag] *ListContextTrait } @@ -25,10 +24,10 @@ func NewTagsContext( c *types.HelperCommon, ) *TagsContext { - viewModel := NewTagsViewModel(getModel) + viewModel := NewBasicViewModel(getModel) return &TagsContext{ - TagsViewModel: viewModel, + BasicViewModel: viewModel, ListContextTrait: &ListContextTrait{ Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ ViewName: "branches", @@ -58,34 +57,7 @@ func (self *TagsContext) GetSelectedItemId() string { return item.ID() } -type TagsViewModel struct { - *traits.ListCursor - getModel func() []*models.Tag -} - -func NewTagsViewModel(getModel func() []*models.Tag) *TagsViewModel { - self := &TagsViewModel{ - getModel: getModel, - } - - self.ListCursor = traits.NewListCursor(self) - - return self -} - -func (self *TagsViewModel) GetItemsLength() int { - return len(self.getModel()) -} - -func (self *TagsViewModel) GetSelected() *models.Tag { - if self.GetItemsLength() == 0 { - return nil - } - - return self.getModel()[self.GetSelectedLineIdx()] -} - -func (self *TagsViewModel) GetSelectedRefName() string { +func (self *TagsContext) GetSelectedRefName() string { item := self.GetSelected() if item == nil { return "" diff --git a/pkg/gui/context/traits/list_cursor.go b/pkg/gui/context/traits/list_cursor.go index 9423ad89c..6e80643d6 100644 --- a/pkg/gui/context/traits/list_cursor.go +++ b/pkg/gui/context/traits/list_cursor.go @@ -6,7 +6,7 @@ import ( ) type HasLength interface { - GetItemsLength() int + Len() int } type ListCursor struct { @@ -25,7 +25,7 @@ func (self *ListCursor) GetSelectedLineIdx() int { } func (self *ListCursor) SetSelectedLineIdx(value int) { - self.selectedIdx = utils.Clamp(value, 0, self.list.GetItemsLength()-1) + self.selectedIdx = utils.Clamp(value, 0, self.list.Len()-1) } // moves the cursor up or down by the given amount @@ -38,6 +38,6 @@ func (self *ListCursor) RefreshSelectedIdx() { self.SetSelectedLineIdx(self.selectedIdx) } -func (self *ListCursor) GetItemsLength() int { - return self.list.GetItemsLength() +func (self *ListCursor) Len() int { + return self.list.Len() } diff --git a/pkg/gui/context/working_tree_context.go b/pkg/gui/context/working_tree_context.go index ae647afb3..5223f2982 100644 --- a/pkg/gui/context/working_tree_context.go +++ b/pkg/gui/context/working_tree_context.go @@ -50,7 +50,7 @@ func NewWorkingTreeContext( } func (self *WorkingTreeContext) GetSelectedItemId() string { - item := self.GetSelectedFileNode() + item := self.GetSelected() if item == nil { return "" } diff --git a/pkg/gui/controllers/commits_files_controller.go b/pkg/gui/controllers/commits_files_controller.go index d0015faff..933d17321 100644 --- a/pkg/gui/controllers/commits_files_controller.go +++ b/pkg/gui/controllers/commits_files_controller.go @@ -80,7 +80,7 @@ func (self *CommitFilesController) GetMouseKeybindings(opts types.KeybindingsOpt func (self *CommitFilesController) checkSelected(callback func(*filetree.CommitFileNode) error) func() error { return func() error { - selected := self.context().GetSelectedFileNode() + selected := self.context().GetSelected() if selected == nil { return nil } @@ -98,7 +98,7 @@ func (self *CommitFilesController) context() *context.CommitFilesContext { } func (self *CommitFilesController) onClickMain(opts gocui.ViewMouseBindingOpts) error { - node := self.context().GetSelectedFileNode() + node := self.context().GetSelected() if node == nil { return nil } diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index 5fcde5202..db3eca7b1 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -216,7 +216,7 @@ func (self *FilesController) press(node *filetree.FileNode) error { func (self *FilesController) checkSelectedFileNode(callback func(*filetree.FileNode) error) func() error { return func() error { - node := self.context().GetSelectedFileNode() + node := self.context().GetSelected() if node == nil { return nil } @@ -234,7 +234,7 @@ func (self *FilesController) context() *context.WorkingTreeContext { } func (self *FilesController) getSelectedFile() *models.File { - node := self.context().GetSelectedFileNode() + node := self.context().GetSelected() if node == nil { return nil } @@ -246,7 +246,7 @@ func (self *FilesController) enter() error { } func (self *FilesController) EnterFile(opts types.OnFocusOpts) error { - node := self.context().GetSelectedFileNode() + node := self.context().GetSelected() if node == nil { return nil } @@ -535,7 +535,7 @@ func (self *FilesController) edit(node *filetree.FileNode) error { } func (self *FilesController) Open() error { - node := self.context().GetSelectedFileNode() + node := self.context().GetSelected() if node == nil { return nil } @@ -583,7 +583,7 @@ func (self *FilesController) createResetToUpstreamMenu() error { } func (self *FilesController) handleToggleDirCollapsed() error { - node := self.context().GetSelectedFileNode() + node := self.context().GetSelected() if node == nil { return nil } diff --git a/pkg/gui/controllers/files_remove_controller.go b/pkg/gui/controllers/files_remove_controller.go index 521167c33..c2416bfaf 100644 --- a/pkg/gui/controllers/files_remove_controller.go +++ b/pkg/gui/controllers/files_remove_controller.go @@ -139,7 +139,7 @@ func (self *FilesRemoveController) ResetSubmodule(submodule *models.SubmoduleCon func (self *FilesRemoveController) checkSelectedFileNode(callback func(*filetree.FileNode) error) func() error { return func() error { - node := self.context().GetSelectedFileNode() + node := self.context().GetSelected() if node == nil { return nil } diff --git a/pkg/gui/controllers/list_controller.go b/pkg/gui/controllers/list_controller.go index c9898f908..0f64228bb 100644 --- a/pkg/gui/controllers/list_controller.go +++ b/pkg/gui/controllers/list_controller.go @@ -83,11 +83,11 @@ func (self *ListController) HandleNextPage() error { } func (self *ListController) HandleGotoTop() error { - return self.handleLineChange(-self.context.GetList().GetItemsLength()) + return self.handleLineChange(-self.context.GetList().Len()) } func (self *ListController) HandleGotoBottom() error { - return self.handleLineChange(self.context.GetList().GetItemsLength()) + return self.handleLineChange(self.context.GetList().Len()) } func (self *ListController) HandleClick(opts gocui.ViewMouseBindingOpts) error { @@ -99,7 +99,7 @@ func (self *ListController) HandleClick(opts gocui.ViewMouseBindingOpts) error { return err } - if newSelectedLineIdx > self.context.GetList().GetItemsLength()-1 { + if newSelectedLineIdx > self.context.GetList().Len()-1 { return nil } diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index b54cfa3c0..d45e3ed56 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -588,7 +588,7 @@ func (self *LocalCommitsController) gotoBottom() error { } } - self.context().SetSelectedLineIdx(self.context().GetItemsLength() - 1) + self.context().SetSelectedLineIdx(self.context().Len() - 1) return nil } diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index 5d5d65c8f..765e33e4c 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -9,7 +9,7 @@ import ( // list panel functions func (gui *Gui) getSelectedFileNode() *filetree.FileNode { - return gui.State.Contexts.Files.GetSelectedFileNode() + return gui.State.Contexts.Files.GetSelected() } func (gui *Gui) getSelectedFile() *models.File { diff --git a/pkg/gui/filetree/commit_file_tree.go b/pkg/gui/filetree/commit_file_tree.go index d020aee21..055e273f3 100644 --- a/pkg/gui/filetree/commit_file_tree.go +++ b/pkg/gui/filetree/commit_file_tree.go @@ -8,7 +8,7 @@ import ( type ICommitFileTree interface { ITree - GetItemAtIndex(index int) *CommitFileNode + Get(index int) *CommitFileNode GetFile(path string) *models.CommitFile GetAllItems() []*CommitFileNode GetAllFiles() []*models.CommitFile @@ -42,7 +42,7 @@ func (self *CommitFileTree) ToggleShowTree() { self.SetTree() } -func (self *CommitFileTree) GetItemAtIndex(index int) *CommitFileNode { +func (self *CommitFileTree) Get(index int) *CommitFileNode { // need to traverse the three depth first until we get to the index. return self.tree.GetNodeAtIndex(index+1, self.collapsedPaths) // ignoring root } @@ -60,7 +60,7 @@ func (self *CommitFileTree) GetAllItems() []*CommitFileNode { return self.tree.Flatten(self.collapsedPaths)[1:] // ignoring root } -func (self *CommitFileTree) GetItemsLength() int { +func (self *CommitFileTree) Len() int { return self.tree.Size(self.collapsedPaths) - 1 // ignoring root } diff --git a/pkg/gui/filetree/commit_file_tree_view_model.go b/pkg/gui/filetree/commit_file_tree_view_model.go index e80003d28..72960c702 100644 --- a/pkg/gui/filetree/commit_file_tree_view_model.go +++ b/pkg/gui/filetree/commit_file_tree_view_model.go @@ -61,16 +61,16 @@ func (self *CommitFileTreeViewModel) SetCanRebase(canRebase bool) { self.canRebase = canRebase } -func (self *CommitFileTreeViewModel) GetSelectedFileNode() *CommitFileNode { - if self.GetItemsLength() == 0 { +func (self *CommitFileTreeViewModel) GetSelected() *CommitFileNode { + if self.Len() == 0 { return nil } - return self.GetItemAtIndex(self.GetSelectedLineIdx()) + return self.Get(self.GetSelectedLineIdx()) } func (self *CommitFileTreeViewModel) GetSelectedFile() *models.CommitFile { - node := self.GetSelectedFileNode() + node := self.GetSelected() if node == nil { return nil } @@ -79,7 +79,7 @@ func (self *CommitFileTreeViewModel) GetSelectedFile() *models.CommitFile { } func (self *CommitFileTreeViewModel) GetSelectedPath() string { - node := self.GetSelectedFileNode() + node := self.GetSelected() if node == nil { return "" } @@ -89,7 +89,7 @@ func (self *CommitFileTreeViewModel) GetSelectedPath() string { // duplicated from file_tree_view_model.go. Generics will help here func (self *CommitFileTreeViewModel) ToggleShowTree() { - selectedNode := self.GetSelectedFileNode() + selectedNode := self.GetSelected() self.ICommitFileTree.ToggleShowTree() diff --git a/pkg/gui/filetree/file_tree.go b/pkg/gui/filetree/file_tree.go index 113027e59..0d0524470 100644 --- a/pkg/gui/filetree/file_tree.go +++ b/pkg/gui/filetree/file_tree.go @@ -22,7 +22,7 @@ type ITree interface { ExpandToPath(path string) ToggleShowTree() GetIndexForPath(path string) (int, bool) - GetItemsLength() int + Len() int SetTree() IsCollapsed(path string) bool ToggleCollapsed(path string) @@ -35,7 +35,7 @@ type IFileTree interface { FilterFiles(test func(*models.File) bool) []*models.File SetFilter(filter FileTreeDisplayFilter) - GetItemAtIndex(index int) *FileNode + Get(index int) *FileNode GetFile(path string) *models.File GetAllItems() []*FileNode GetAllFiles() []*models.File @@ -104,7 +104,7 @@ func (self *FileTree) ToggleShowTree() { self.SetTree() } -func (self *FileTree) GetItemAtIndex(index int) *FileNode { +func (self *FileTree) Get(index int) *FileNode { // need to traverse the three depth first until we get to the index. return self.tree.GetNodeAtIndex(index+1, self.collapsedPaths) // ignoring root } @@ -135,7 +135,7 @@ func (self *FileTree) GetAllItems() []*FileNode { return self.tree.Flatten(self.collapsedPaths)[1:] // ignoring root } -func (self *FileTree) GetItemsLength() int { +func (self *FileTree) Len() int { return self.tree.Size(self.collapsedPaths) - 1 // ignoring root } diff --git a/pkg/gui/filetree/file_tree_view_model.go b/pkg/gui/filetree/file_tree_view_model.go index 9adb04cf1..333be8da2 100644 --- a/pkg/gui/filetree/file_tree_view_model.go +++ b/pkg/gui/filetree/file_tree_view_model.go @@ -35,16 +35,16 @@ func NewFileTreeViewModel(getFiles func() []*models.File, log *logrus.Entry, sho } } -func (self *FileTreeViewModel) GetSelectedFileNode() *FileNode { - if self.GetItemsLength() == 0 { +func (self *FileTreeViewModel) GetSelected() *FileNode { + if self.Len() == 0 { return nil } - return self.GetItemAtIndex(self.GetSelectedLineIdx()) + return self.Get(self.GetSelectedLineIdx()) } func (self *FileTreeViewModel) GetSelectedFile() *models.File { - node := self.GetSelectedFileNode() + node := self.GetSelected() if node == nil { return nil } @@ -53,7 +53,7 @@ func (self *FileTreeViewModel) GetSelectedFile() *models.File { } func (self *FileTreeViewModel) GetSelectedPath() string { - node := self.GetSelectedFileNode() + node := self.GetSelected() if node == nil { return "" } @@ -63,7 +63,7 @@ func (self *FileTreeViewModel) GetSelectedPath() string { func (self *FileTreeViewModel) SetTree() { newFiles := self.GetAllFiles() - selectedNode := self.GetSelectedFileNode() + selectedNode := self.GetSelected() // for when you stage the old file of a rename and the new file is in a collapsed dir for _, file := range newFiles { @@ -135,7 +135,7 @@ func (self *FileTreeViewModel) SetFilter(filter FileTreeDisplayFilter) { // If we're going from tree to flat and we have a file selected we want to select that. // If instead we've selected a directory we need to select the first file in that directory. func (self *FileTreeViewModel) ToggleShowTree() { - selectedNode := self.GetSelectedFileNode() + selectedNode := self.GetSelected() self.IFileTree.ToggleShowTree() diff --git a/pkg/gui/filtering_menu_panel.go b/pkg/gui/filtering_menu_panel.go index fefe6a892..7bcc26363 100644 --- a/pkg/gui/filtering_menu_panel.go +++ b/pkg/gui/filtering_menu_panel.go @@ -16,7 +16,7 @@ func (gui *Gui) handleCreateFilteringMenuPanel() error { fileName = node.GetPath() } case gui.State.Contexts.CommitFiles: - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() + node := gui.State.Contexts.CommitFiles.GetSelected() if node != nil { fileName = node.GetPath() } diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index 397e38bd9..89e1461b8 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -230,7 +230,7 @@ func (gui *Gui) commitFilesListContext() *context.CommitFilesContext { func() []*models.CommitFile { return gui.State.Model.CommitFiles }, gui.Views.CommitFiles, func(startIdx int, length int) [][]string { - if gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.GetItemsLength() == 0 { + if gui.State.Contexts.CommitFiles.CommitFileTreeViewModel.Len() == 0 { return [][]string{{style.FgRed.Sprint("(none)")}} } diff --git a/pkg/gui/patch_building_panel.go b/pkg/gui/patch_building_panel.go index d71b43e76..dd82f998a 100644 --- a/pkg/gui/patch_building_panel.go +++ b/pkg/gui/patch_building_panel.go @@ -13,7 +13,7 @@ func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error { gui.Views.Secondary.Title = "Custom Patch" // get diff from commit file that's currently selected - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() + node := gui.State.Contexts.CommitFiles.GetSelected() if node == nil { return nil } @@ -74,7 +74,7 @@ func (gui *Gui) handleToggleSelectionForPatch() error { } // add range of lines to those set for the file - node := gui.State.Contexts.CommitFiles.GetSelectedFileNode() + node := gui.State.Contexts.CommitFiles.GetSelected() if node == nil { return nil } diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index 5e588da0d..bf56cf5db 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -109,7 +109,7 @@ type IController interface { type IList interface { IListCursor - GetItemsLength() int + Len() int } type IListCursor interface { From a34bdf1a046c90c22a1c0b653241b8107e89c7f9 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 19 Mar 2022 09:38:49 +1100 Subject: [PATCH 104/385] update linters --- .github/workflows/automerge.yml | 2 +- .github/workflows/cd.yml | 2 +- .github/workflows/ci.yml | 26 +- .gitignore | 2 + .golangci.yml | 24 ++ go.mod | 3 +- go.sum | 5 +- pkg/app/app.go | 5 +- pkg/app/logging_windows.go | 3 +- pkg/cheatsheet/check.go | 3 +- pkg/cheatsheet/generate.go | 2 +- pkg/commands/git.go | 1 - pkg/commands/git_commands/rebase.go | 4 +- .../hosting_service/hosting_service.go | 5 +- pkg/commands/oscommands/cmd_obj_runner_win.go | 1 + .../oscommands/fake_cmd_obj_runner.go | 2 +- pkg/commands/oscommands/os.go | 4 +- pkg/commands/oscommands/os_test.go | 2 +- pkg/commands/patch/patch_manager.go | 6 +- pkg/commands/patch/patch_modifier.go | 6 +- pkg/config/app_config.go | 4 +- pkg/config/user_config.go | 3 +- pkg/gui/context/local_commits_context.go | 3 +- pkg/gui/context/sub_commits_context.go | 3 +- pkg/gui/controllers/branches_controller.go | 7 +- .../controllers/commits_files_controller.go | 1 - pkg/gui/controllers/helpers/refs_helper.go | 1 - pkg/gui/controllers/submodules_controller.go | 1 - pkg/gui/controllers/sync_controller.go | 1 - pkg/gui/filetree/commit_file_node.go | 6 +- pkg/gui/filetree/file_node.go | 6 +- pkg/gui/gui.go | 3 +- pkg/gui/gui_test.go | 1 + pkg/gui/keybindings.go | 4 +- pkg/gui/merge_panel.go | 4 +- pkg/gui/mergeconflicts/find_conflicts.go | 10 +- pkg/gui/mergeconflicts/state.go | 1 - pkg/gui/options_menu_panel.go | 4 +- pkg/gui/patch_building_panel.go | 1 - pkg/gui/presentation/commits.go | 8 +- pkg/gui/presentation/files.go | 16 +- pkg/gui/presentation/graph/cell.go | 12 +- pkg/gui/recording.go | 2 +- pkg/gui/types/context.go | 6 +- pkg/integration/integration.go | 5 +- pkg/tasks/tasks.go | 78 ++-- pkg/test/log.go | 5 +- pkg/utils/color.go | 6 +- pkg/utils/color_test.go | 2 +- pkg/utils/lines_test.go | 2 +- test/runner/main.go | 2 +- vendor/golang.org/x/exp/AUTHORS | 3 + vendor/golang.org/x/exp/CONTRIBUTORS | 3 + vendor/golang.org/x/exp/LICENSE | 27 ++ vendor/golang.org/x/exp/PATENTS | 22 ++ .../x/exp/constraints/constraints.go | 50 +++ vendor/golang.org/x/exp/slices/slices.go | 213 +++++++++++ vendor/golang.org/x/exp/slices/sort.go | 95 +++++ vendor/golang.org/x/exp/slices/zsortfunc.go | 342 +++++++++++++++++ .../golang.org/x/exp/slices/zsortordered.go | 344 ++++++++++++++++++ vendor/gopkg.in/yaml.v3/apic.go | 1 + vendor/gopkg.in/yaml.v3/decode.go | 65 ++-- vendor/gopkg.in/yaml.v3/emitterc.go | 58 ++- vendor/gopkg.in/yaml.v3/encode.go | 30 +- vendor/gopkg.in/yaml.v3/parserc.go | 48 ++- vendor/gopkg.in/yaml.v3/scannerc.go | 49 ++- vendor/gopkg.in/yaml.v3/yaml.go | 40 +- vendor/gopkg.in/yaml.v3/yamlh.go | 2 + vendor/modules.txt | 6 +- 69 files changed, 1510 insertions(+), 204 deletions(-) create mode 100644 .golangci.yml create mode 100644 vendor/golang.org/x/exp/AUTHORS create mode 100644 vendor/golang.org/x/exp/CONTRIBUTORS create mode 100644 vendor/golang.org/x/exp/LICENSE create mode 100644 vendor/golang.org/x/exp/PATENTS create mode 100644 vendor/golang.org/x/exp/constraints/constraints.go create mode 100644 vendor/golang.org/x/exp/slices/slices.go create mode 100644 vendor/golang.org/x/exp/slices/sort.go create mode 100644 vendor/golang.org/x/exp/slices/zsortfunc.go create mode 100644 vendor/golang.org/x/exp/slices/zsortordered.go diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml index 4eaff9686..36d301e59 100644 --- a/.github/workflows/automerge.yml +++ b/.github/workflows/automerge.yml @@ -25,4 +25,4 @@ jobs: uses: "pascalgn/automerge-action@135f0bdb927d9807b5446f7ca9ecc2c51de03c4a" env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - MERGE_METHOD: rebase \ No newline at end of file + MERGE_METHOD: rebase diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index a07cf1154..8e720d96b 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -16,7 +16,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v1 with: - go-version: 1.16.x + go-version: 1.18.x - name: Run goreleaser uses: goreleaser/goreleaser-action@v1 env: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2176fef97..f933ddb1b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,8 @@ name: Continuous Integration +env: + GO_VERSION: 1.18 + on: push: branches: @@ -24,7 +27,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v1 with: - go-version: 1.16.x + go-version: 1.18.x - name: Cache build uses: actions/cache@v1 with: @@ -46,7 +49,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v1 with: - go-version: 1.16.x + go-version: 1.18.x - name: Cache build uses: actions/cache@v1 with: @@ -74,7 +77,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v1 with: - go-version: 1.16.x + go-version: 1.18.x - name: Cache build uses: actions/cache@v1 with: @@ -87,11 +90,24 @@ jobs: go run scripts/cheatsheet/main.go check lint: runs-on: ubuntu-latest + env: + GOFLAGS: -mod=vendor steps: - - name: Checkout + - name: Checkout code uses: actions/checkout@v2 + - name: Setup Go + uses: actions/setup-go@v1 + with: + go-version: 1.18.x + - name: Cache build + uses: actions/cache@v1 + with: + path: ~/.cache/go-build + key: ${{runner.os}}-go-${{hashFiles('**/go.sum')}}-test + restore-keys: | + ${{runner.os}}-go- - name: Lint - uses: golangci/golangci-lint-action@v2 + uses: golangci/golangci-lint-action@v3.1.0 with: version: latest - name: Format code diff --git a/.gitignore b/.gitignore index 84258eeee..ea0475b55 100644 --- a/.gitignore +++ b/.gitignore @@ -23,8 +23,10 @@ lazygit.exe # Exceptions !.gitignore !.goreleaser.yml +!.golangci.yml !.circleci/ !.github/ + # these are for our integration tests !.git_keep !.gitmodules_keep diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 000000000..358a5d12a --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,24 @@ +linters: + disable: + - structcheck # gives false positives + enable: + - gofumpt + - thelper + - goimports + - tparallel + - wastedassign + - exportloopref + - unparam + - prealloc + - unconvert + - exhaustive + - makezero + # - goconst # TODO: enable and fix issues + fast: false + +linters-settings: + exhaustive: + default-signifies-exhaustive: true + +run: + go: 1.18 diff --git a/go.mod b/go.mod index 677a482f9..3e7598384 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad github.com/stretchr/testify v1.7.0 github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 + golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0 ) @@ -63,5 +64,5 @@ require ( golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index cc15e70e0..fc2d2400d 100644 --- a/go.sum +++ b/go.sum @@ -157,6 +157,8 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 h1:s/+U+w0teGzcoH2mdIlFQ6KfVKGaYpgyGdUefZrn9TU= +golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -205,5 +207,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/app/app.go b/pkg/app/app.go index 0ee7e4adf..2d279936f 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -65,7 +65,7 @@ func newDevelopmentLogger() *logrus.Logger { if err != nil { log.Fatal(err) } - file, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + file, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o666) if err != nil { log.Fatalf("Unable to log to log file: %v", err) } @@ -269,10 +269,9 @@ func (app *App) Rebase() error { app.Log.Info("args: ", os.Args) if strings.HasSuffix(os.Args[1], "git-rebase-todo") { - if err := ioutil.WriteFile(os.Args[1], []byte(os.Getenv("LAZYGIT_REBASE_TODO")), 0644); err != nil { + if err := ioutil.WriteFile(os.Args[1], []byte(os.Getenv("LAZYGIT_REBASE_TODO")), 0o644); err != nil { return err } - } else if strings.HasSuffix(os.Args[1], filepath.Join(gitDir(), "COMMIT_EDITMSG")) { // TODO: test // if we are rebasing and squashing, we'll see a COMMIT_EDITMSG // but in this case we don't need to edit it, so we'll just return diff --git a/pkg/app/logging_windows.go b/pkg/app/logging_windows.go index f8b3d4990..efbdfbbe1 100644 --- a/pkg/app/logging_windows.go +++ b/pkg/app/logging_windows.go @@ -5,11 +5,12 @@ package app import ( "bufio" - "github.com/aybabtme/humanlog" "log" "os" "strings" "time" + + "github.com/aybabtme/humanlog" ) func TailLogsForPlatform(logFilePath string, opts *humanlog.HandlerOptions) { diff --git a/pkg/cheatsheet/check.go b/pkg/cheatsheet/check.go index 03f65d910..ebcd0629f 100644 --- a/pkg/cheatsheet/check.go +++ b/pkg/cheatsheet/check.go @@ -19,7 +19,7 @@ func Check() { if err != nil { log.Fatalf("Error occured while checking if cheatsheets are up to date: %v", err) } - err = os.Mkdir(tmpDir, 0700) + err = os.Mkdir(tmpDir, 0o700) if err != nil { log.Fatalf("Error occured while checking if cheatsheets are up to date: %v", err) } @@ -70,7 +70,6 @@ func obtainContent(dir string) string { return nil }) - if err != nil { log.Fatalf("Error occured while checking if cheatsheets are up to date: %v", err) } diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index 804cb6b45..c7c2b0d37 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -174,7 +174,7 @@ outer: bindings []*types.Binding } - groupedBindings := make([]groupedBindingsType, len(contextAndViewBindingMap)) + groupedBindings := make([]groupedBindingsType, 0, len(contextAndViewBindingMap)) for contextAndView, contextBindings := range contextAndViewBindingMap { groupedBindings = append(groupedBindings, groupedBindingsType{contextAndView: contextAndView, bindings: contextBindings}) diff --git a/pkg/commands/git.go b/pkg/commands/git.go index 3880e0dfc..6c6a3ac7c 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -223,7 +223,6 @@ func setupRepository(openGitRepository func(string) (*gogit.Repository, error), } repository, err := openGitRepository(path) - if err != nil { if strings.Contains(err.Error(), `unquoted '\' must be followed by new line`) { return nil, errors.New(gitConfigParseErrorStr) diff --git a/pkg/commands/git_commands/rebase.go b/pkg/commands/git_commands/rebase.go index c726cad7e..71c8b0e63 100644 --- a/pkg/commands/git_commands/rebase.go +++ b/pkg/commands/git_commands/rebase.go @@ -185,7 +185,7 @@ func (self *RebaseCommands) EditRebaseTodo(index int, action string) error { content[contentIndex] = action + " " + strings.Join(splitLine[1:], " ") result := strings.Join(content, "\n") - return ioutil.WriteFile(fileName, []byte(result), 0644) + return ioutil.WriteFile(fileName, []byte(result), 0o644) } func (self *RebaseCommands) getTodoCommitCount(content []string) int { @@ -215,7 +215,7 @@ func (self *RebaseCommands) MoveTodoDown(index int) error { rearrangedContent = append(rearrangedContent, content[contentIndex+1:]...) result := strings.Join(rearrangedContent, "\n") - return ioutil.WriteFile(fileName, []byte(result), 0644) + return ioutil.WriteFile(fileName, []byte(result), 0o644) } // SquashAllAboveFixupCommits squashes all fixup! commits above the given one diff --git a/pkg/commands/hosting_service/hosting_service.go b/pkg/commands/hosting_service/hosting_service.go index 4a0a49681..b448e3925 100644 --- a/pkg/commands/hosting_service/hosting_service.go +++ b/pkg/commands/hosting_service/hosting_service.go @@ -9,6 +9,8 @@ import ( "github.com/jesseduffield/lazygit/pkg/i18n" "github.com/jesseduffield/lazygit/pkg/utils" "github.com/sirupsen/logrus" + + "golang.org/x/exp/slices" ) // This package is for handling logic specific to a git hosting service like github, gitlab, bitbucket, etc. @@ -94,8 +96,7 @@ func (self *HostingServiceMgr) getCandidateServiceDomains() []ServiceDomain { serviceDefinitionByProvider[serviceDefinition.provider] = serviceDefinition } - var serviceDomains = make([]ServiceDomain, len(defaultServiceDomains)) - copy(serviceDomains, defaultServiceDomains) + serviceDomains := slices.Clone(defaultServiceDomains) if len(self.configServiceDomains) > 0 { for gitDomain, typeAndDomain := range self.configServiceDomains { diff --git a/pkg/commands/oscommands/cmd_obj_runner_win.go b/pkg/commands/oscommands/cmd_obj_runner_win.go index 9e3d1fd02..9a64dfa77 100644 --- a/pkg/commands/oscommands/cmd_obj_runner_win.go +++ b/pkg/commands/oscommands/cmd_obj_runner_win.go @@ -20,6 +20,7 @@ func (b *Buffer) Read(p []byte) (n int, err error) { defer b.m.Unlock() return b.b.Read(p) } + func (b *Buffer) Write(p []byte) (n int, err error) { b.m.Lock() defer b.m.Unlock() diff --git a/pkg/commands/oscommands/fake_cmd_obj_runner.go b/pkg/commands/oscommands/fake_cmd_obj_runner.go index b542bfee3..d06861251 100644 --- a/pkg/commands/oscommands/fake_cmd_obj_runner.go +++ b/pkg/commands/oscommands/fake_cmd_obj_runner.go @@ -21,7 +21,7 @@ type FakeCmdObjRunner struct { var _ ICmdObjRunner = &FakeCmdObjRunner{} -func NewFakeRunner(t *testing.T) *FakeCmdObjRunner { +func NewFakeRunner(t *testing.T) *FakeCmdObjRunner { //nolint:thelper return &FakeCmdObjRunner{t: t} } diff --git a/pkg/commands/oscommands/os.go b/pkg/commands/oscommands/os.go index 1c4f5bf28..f3df3956f 100644 --- a/pkg/commands/oscommands/os.go +++ b/pkg/commands/oscommands/os.go @@ -103,7 +103,7 @@ func (c *OSCommand) Quote(message string) string { // AppendLineToFile adds a new line in file func (c *OSCommand) AppendLineToFile(filename, line string) error { c.LogCommand(fmt.Sprintf("Appending '%s' to file '%s'", line, filename), false) - f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600) if err != nil { return utils.WrapError(err) } @@ -145,7 +145,7 @@ func (c *OSCommand) CreateFileWithContent(path string, content string) error { return err } - if err := ioutil.WriteFile(path, []byte(content), 0644); err != nil { + if err := ioutil.WriteFile(path, []byte(content), 0o644); err != nil { c.Log.Error(err) return utils.WrapError(err) } diff --git a/pkg/commands/oscommands/os_test.go b/pkg/commands/oscommands/os_test.go index efda5a3a1..9c2d9a2a7 100644 --- a/pkg/commands/oscommands/os_test.go +++ b/pkg/commands/oscommands/os_test.go @@ -141,7 +141,7 @@ func TestOSCommandFileType(t *testing.T) { { "testDirectory", func() { - if err := os.Mkdir("testDirectory", 0644); err != nil { + if err := os.Mkdir("testDirectory", 0o644); err != nil { panic(err) } }, diff --git a/pkg/commands/patch/patch_manager.go b/pkg/commands/patch/patch_manager.go index c8e16a7fd..cbdf7b2d4 100644 --- a/pkg/commands/patch/patch_manager.go +++ b/pkg/commands/patch/patch_manager.go @@ -26,8 +26,10 @@ type fileInfo struct { diff string } -type applyPatchFunc func(patch string, flags ...string) error -type loadFileDiffFunc func(from string, to string, reverse bool, filename string, plain bool) (string, error) +type ( + applyPatchFunc func(patch string, flags ...string) error + loadFileDiffFunc func(from string, to string, reverse bool, filename string, plain bool) (string, error) +) // PatchManager manages the building of a patch for a commit to be applied to another commit (or the working tree, or removed from the current commit). We also support building patches from things like stashes, for which there is less flexibility type PatchManager struct { diff --git a/pkg/commands/patch/patch_modifier.go b/pkg/commands/patch/patch_modifier.go index 2109ad1f0..2d060ec18 100644 --- a/pkg/commands/patch/patch_modifier.go +++ b/pkg/commands/patch/patch_modifier.go @@ -8,8 +8,10 @@ import ( "github.com/sirupsen/logrus" ) -var hunkHeaderRegexp = regexp.MustCompile(`(?m)^@@ -(\d+)[^\+]+\+(\d+)[^@]+@@(.*)$`) -var patchHeaderRegexp = regexp.MustCompile(`(?ms)(^diff.*?)^@@`) +var ( + hunkHeaderRegexp = regexp.MustCompile(`(?m)^@@ -(\d+)[^\+]+\+(\d+)[^@]+@@(.*)$`) + patchHeaderRegexp = regexp.MustCompile(`(?ms)(^diff.*?)^@@`) +) func GetHeaderFromDiff(diff string) string { match := patchHeaderRegexp.FindStringSubmatch(diff) diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index 98620ad43..40509e86a 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -123,7 +123,7 @@ func configDirForVendor(vendor string) string { func findOrCreateConfigDir() (string, error) { folder := ConfigDir() - return folder, os.MkdirAll(folder, 0755) + return folder, os.MkdirAll(folder, 0o755) } func loadUserConfigWithDefaults(configFiles []string) (*UserConfig, error) { @@ -249,7 +249,7 @@ func (c *AppConfig) SaveAppState() error { return err } - err = ioutil.WriteFile(filepath, marshalledAppState, 0644) + err = ioutil.WriteFile(filepath, marshalledAppState, 0o644) if err != nil && os.IsPermission(err) { // apparently when people have read-only permissions they prefer us to fail silently return nil diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index ac8a2bbc1..51f443243 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -358,7 +358,8 @@ func GetDefaultConfig() *UserConfig { Paging: PagingConfig{ ColorArg: "always", Pager: "", - UseConfig: false}, + UseConfig: false, + }, Commit: CommitConfig{ SignOff: false, }, diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index d8d64392c..46e3be2cd 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -45,7 +45,8 @@ func NewLocalCommitsContext( viewTrait: NewViewTrait(view), getDisplayStrings: getDisplayStrings, c: c, - }}, + }, + }, } } diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go index 0f16f1688..93a0c3593 100644 --- a/pkg/gui/context/sub_commits_context.go +++ b/pkg/gui/context/sub_commits_context.go @@ -45,7 +45,8 @@ func NewSubCommitsContext( viewTrait: NewViewTrait(view), getDisplayStrings: getDisplayStrings, c: c, - }}, + }, + }, } } diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index 08ea95119..c578a405b 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -185,7 +185,8 @@ func (self *BranchesController) checkoutByName() error { }) }, }) - }}, + }, + }, ) } @@ -377,8 +378,8 @@ func (self *BranchesController) createPullRequestMenu(selectedBranch *models.Bra FindSuggestionsFunc: self.helpers.Suggestions.GetBranchNameSuggestionsFunc(), HandleConfirm: func(targetBranchName string) error { return self.createPullRequest(branch.Name, targetBranchName) - }}, - ) + }, + }) }, }, } diff --git a/pkg/gui/controllers/commits_files_controller.go b/pkg/gui/controllers/commits_files_controller.go index 933d17321..978d6c6a7 100644 --- a/pkg/gui/controllers/commits_files_controller.go +++ b/pkg/gui/controllers/commits_files_controller.go @@ -170,7 +170,6 @@ func (self *CommitFilesController) toggleForPatch(node *filetree.CommitFileNode) return self.git.Patch.PatchManager.RemoveFile(file.Name) } }) - if err != nil { return self.c.Error(err) } diff --git a/pkg/gui/controllers/helpers/refs_helper.go b/pkg/gui/controllers/helpers/refs_helper.go index e3e050117..65c01d4a7 100644 --- a/pkg/gui/controllers/helpers/refs_helper.go +++ b/pkg/gui/controllers/helpers/refs_helper.go @@ -71,7 +71,6 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions if strings.Contains(err.Error(), "Please commit your changes or stash them before you switch branch") { // offer to autostash changes return self.c.Ask(types.AskOpts{ - Title: self.c.Tr.AutoStashTitle, Prompt: self.c.Tr.AutoStashPrompt, HandleConfirm: func() error { diff --git a/pkg/gui/controllers/submodules_controller.go b/pkg/gui/controllers/submodules_controller.go index 83c05da4b..10b25df2b 100644 --- a/pkg/gui/controllers/submodules_controller.go +++ b/pkg/gui/controllers/submodules_controller.go @@ -90,7 +90,6 @@ func (self *SubmodulesController) add() error { Title: self.c.Tr.LcNewSubmoduleName, InitialContent: nameSuggestion, HandleConfirm: func(submoduleName string) error { - return self.c.Prompt(types.PromptOpts{ Title: self.c.Tr.LcNewSubmodulePath, InitialContent: submoduleName, diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go index 74db3d527..8501c5484 100644 --- a/pkg/gui/controllers/sync_controller.go +++ b/pkg/gui/controllers/sync_controller.go @@ -194,7 +194,6 @@ func (self *SyncController) pushAux(opts pushOpts) error { UpstreamBranch: opts.upstreamBranch, SetUpstream: opts.setUpstream, }) - if err != nil { if !opts.force && strings.Contains(err.Error(), "Updates were rejected") { forcePushDisabled := self.c.UserConfig.Git.DisableForcePushing diff --git a/pkg/gui/filetree/commit_file_node.go b/pkg/gui/filetree/commit_file_node.go index 98428348e..a8f7d0a95 100644 --- a/pkg/gui/filetree/commit_file_node.go +++ b/pkg/gui/filetree/commit_file_node.go @@ -12,8 +12,10 @@ type CommitFileNode struct { CompressionLevel int // equal to the number of forward slashes you'll see in the path when it's rendered in tree mode } -var _ INode = &CommitFileNode{} -var _ types.ListItem = &CommitFileNode{} +var ( + _ INode = &CommitFileNode{} + _ types.ListItem = &CommitFileNode{} +) func (s *CommitFileNode) ID() string { return s.GetPath() diff --git a/pkg/gui/filetree/file_node.go b/pkg/gui/filetree/file_node.go index 5a99b3e12..841f723fc 100644 --- a/pkg/gui/filetree/file_node.go +++ b/pkg/gui/filetree/file_node.go @@ -12,8 +12,10 @@ type FileNode struct { CompressionLevel int // equal to the number of forward slashes you'll see in the path when it's rendered in tree mode } -var _ INode = &FileNode{} -var _ types.ListItem = &FileNode{} +var ( + _ INode = &FileNode{} + _ types.ListItem = &FileNode{} +) func (s *FileNode) ID() string { return s.GetPath() diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index b65493d49..144be8df5 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -5,9 +5,8 @@ import ( "io/ioutil" "log" "os" - "sync" - "strings" + "sync" "time" "github.com/jesseduffield/gocui" diff --git a/pkg/gui/gui_test.go b/pkg/gui/gui_test.go index e35ab1896..58f0b0958 100644 --- a/pkg/gui/gui_test.go +++ b/pkg/gui/gui_test.go @@ -55,6 +55,7 @@ func Test(t *testing.T) { mode, speedEnv, func(t *testing.T, expected string, actual string, prefix string) { + t.Helper() assert.Equal(t, expected, actual, fmt.Sprintf("Unexpected %s. Expected:\n%s\nActual:\n%s\n", prefix, expected, actual)) }, includeSkipped, diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 2bf2b9815..13fdf7d26 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "strings" - "unicode/utf8" "github.com/jesseduffield/gocui" @@ -1021,7 +1020,8 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi ViewName: "", Key: opts.GetKey(opts.Config.Universal.JumpToBlock[i]), Modifier: gocui.ModNone, - Handler: self.goToSideWindow(window)}) + Handler: self.goToSideWindow(window), + }) } } diff --git a/pkg/gui/merge_panel.go b/pkg/gui/merge_panel.go index 60aa93a17..b9a00eaa2 100644 --- a/pkg/gui/merge_panel.go +++ b/pkg/gui/merge_panel.go @@ -54,7 +54,7 @@ func (gui *Gui) handleMergeConflictUndo() error { gui.c.LogAction("Restoring file to previous state") gui.LogCommand("Undoing last conflict resolution", false) - if err := ioutil.WriteFile(state.GetPath(), []byte(state.GetContent()), 0644); err != nil { + if err := ioutil.WriteFile(state.GetPath(), []byte(state.GetContent()), 0o644); err != nil { return err } @@ -127,7 +127,7 @@ func (gui *Gui) resolveConflict(selection mergeconflicts.Selection) (bool, error gui.c.LogAction("Resolve merge conflict") gui.LogCommand(logStr, false) state.PushContent(content) - return true, ioutil.WriteFile(state.GetPath(), []byte(content), 0644) + return true, ioutil.WriteFile(state.GetPath(), []byte(content), 0o644) } // precondition: we actually have conflicts to render diff --git a/pkg/gui/mergeconflicts/find_conflicts.go b/pkg/gui/mergeconflicts/find_conflicts.go index 14a08fd68..3802a66b7 100644 --- a/pkg/gui/mergeconflicts/find_conflicts.go +++ b/pkg/gui/mergeconflicts/find_conflicts.go @@ -57,10 +57,12 @@ func findConflicts(content string) []*mergeConflict { return conflicts } -var CONFLICT_START = "<<<<<<< " -var CONFLICT_END = ">>>>>>> " -var CONFLICT_START_BYTES = []byte(CONFLICT_START) -var CONFLICT_END_BYTES = []byte(CONFLICT_END) +var ( + CONFLICT_START = "<<<<<<< " + CONFLICT_END = ">>>>>>> " + CONFLICT_START_BYTES = []byte(CONFLICT_START) + CONFLICT_END_BYTES = []byte(CONFLICT_END) +) func determineLineType(line string) LineType { // TODO: find out whether we ever actually get this prefix diff --git a/pkg/gui/mergeconflicts/state.go b/pkg/gui/mergeconflicts/state.go index b40b979e9..3d0254e15 100644 --- a/pkg/gui/mergeconflicts/state.go +++ b/pkg/gui/mergeconflicts/state.go @@ -176,7 +176,6 @@ func (s *State) ContentAfterConflictResolve(selection Selection) (bool, string, content += line } }) - if err != nil { return false, "", err } diff --git a/pkg/gui/options_menu_panel.go b/pkg/gui/options_menu_panel.go index 85ed34b5d..0073bb041 100644 --- a/pkg/gui/options_menu_panel.go +++ b/pkg/gui/options_menu_panel.go @@ -11,9 +11,7 @@ import ( ) func (gui *Gui) getBindings(context types.Context) []*types.Binding { - var ( - bindingsGlobal, bindingsPanel, bindingsNavigation []*types.Binding - ) + var bindingsGlobal, bindingsPanel, bindingsNavigation []*types.Binding bindings, _ := gui.GetInitialKeybindings() customBindings, err := gui.CustomCommandsClient.GetCustomCommandKeybindings() diff --git a/pkg/gui/patch_building_panel.go b/pkg/gui/patch_building_panel.go index dd82f998a..e734433c4 100644 --- a/pkg/gui/patch_building_panel.go +++ b/pkg/gui/patch_building_panel.go @@ -88,7 +88,6 @@ func (gui *Gui) handleToggleSelectionForPatch() error { return nil }) - if err != nil { return err } diff --git a/pkg/gui/presentation/commits.go b/pkg/gui/presentation/commits.go index 2bc9f475c..2d5262e89 100644 --- a/pkg/gui/presentation/commits.go +++ b/pkg/gui/presentation/commits.go @@ -19,8 +19,10 @@ type pipeSetCacheKey struct { commitCount int } -var pipeSetCache = make(map[pipeSetCacheKey][][]*graph.Pipe) -var mutex sync.Mutex +var ( + pipeSetCache = make(map[pipeSetCacheKey][][]*graph.Pipe) + mutex sync.Mutex +) type bisectBounds struct { newIndex int @@ -226,6 +228,8 @@ func getBisectStatusText(bisectStatus BisectStatus, bisectInfo *git_commands.Bis return style.Sprintf("<-- skipped") case BisectStatusCandidate: return style.Sprintf("?") + case BisectStatusNone: + return "" } return "" diff --git a/pkg/gui/presentation/files.go b/pkg/gui/presentation/files.go index 3efb8d29b..be57a3510 100644 --- a/pkg/gui/presentation/files.go +++ b/pkg/gui/presentation/files.go @@ -12,13 +12,17 @@ import ( "github.com/jesseduffield/lazygit/pkg/utils" ) -const EXPANDED_ARROW = "鈻" -const COLLAPSED_ARROW = "鈻" +const ( + EXPANDED_ARROW = "鈻" + COLLAPSED_ARROW = "鈻" +) -const INNER_ITEM = "鈹溾攢 " -const LAST_ITEM = "鈹斺攢 " -const NESTED = "鈹 " -const NOTHING = " " +const ( + INNER_ITEM = "鈹溾攢 " + LAST_ITEM = "鈹斺攢 " + NESTED = "鈹 " + NOTHING = " " +) func RenderFileTree( tree filetree.IFileTree, diff --git a/pkg/gui/presentation/graph/cell.go b/pkg/gui/presentation/graph/cell.go index e970c6dd2..cc2ad53c3 100644 --- a/pkg/gui/presentation/graph/cell.go +++ b/pkg/gui/presentation/graph/cell.go @@ -8,8 +8,10 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/style" ) -const MergeSymbol = '鈴' -const CommitSymbol = '鈼' +const ( + MergeSymbol = '鈴' + CommitSymbol = '鈼' +) type cellType int @@ -66,8 +68,10 @@ type rgbCacheKey struct { str string } -var rgbCache = make(map[rgbCacheKey]string) -var rgbCacheMutex sync.RWMutex +var ( + rgbCache = make(map[rgbCacheKey]string) + rgbCacheMutex sync.RWMutex +) func cachedSprint(style style.TextStyle, str string) string { switch v := style.Style.(type) { diff --git a/pkg/gui/recording.go b/pkg/gui/recording.go index 0a7f723df..9edd50f08 100644 --- a/pkg/gui/recording.go +++ b/pkg/gui/recording.go @@ -70,5 +70,5 @@ func (gui *Gui) saveRecording(recording *gocui.Recording) error { path := recordEventsTo() - return ioutil.WriteFile(path, jsonEvents, 0600) + return ioutil.WriteFile(path, jsonEvents, 0o600) } diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index bf56cf5db..58dee1c0e 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -93,8 +93,10 @@ type KeybindingsOpts struct { Guards KeybindingGuards } -type KeybindingsFn func(opts KeybindingsOpts) []*Binding -type MouseKeybindingsFn func(opts KeybindingsOpts) []*gocui.ViewMouseBinding +type ( + KeybindingsFn func(opts KeybindingsOpts) []*Binding + MouseKeybindingsFn func(opts KeybindingsOpts) []*gocui.ViewMouseBinding +) type HasKeybindings interface { GetKeybindings(opts KeybindingsOpts) []*Binding diff --git a/pkg/integration/integration.go b/pkg/integration/integration.go index a55d460fe..86049a230 100644 --- a/pkg/integration/integration.go +++ b/pkg/integration/integration.go @@ -95,6 +95,7 @@ func RunTests( } fnWrapper(test, func(t *testing.T) error { + t.Helper() speeds := getTestSpeeds(test.Speed, mode, speedEnv) testPath := filepath.Join(testDir, test.Name) actualRepoDir := filepath.Join(testPath, "actual") @@ -218,7 +219,7 @@ func prepareIntegrationTestDir(actualDir string) { dir, err := ioutil.ReadDir(actualDir) if err != nil { if os.IsNotExist(err) { - err = os.Mkdir(actualDir, 0777) + err = os.Mkdir(actualDir, 0o777) if err != nil { panic(err) } @@ -332,7 +333,7 @@ func findOrCreateDir(path string) { _, err := os.Stat(path) if err != nil { if os.IsNotExist(err) { - err = os.MkdirAll(path, 0777) + err = os.MkdirAll(path, 0o777) if err != nil { panic(err) } diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index 4a987039c..fe257ae96 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -30,7 +30,7 @@ type ViewBufferManager struct { waitingMutex sync.Mutex taskIDMutex sync.Mutex Log *logrus.Entry - newTaskId int + newTaskID int readLines chan int taskKey string onNewKey func() @@ -70,14 +70,14 @@ func NewViewBufferManager( } } -func (m *ViewBufferManager) ReadLines(n int) { +func (self *ViewBufferManager) ReadLines(n int) { go utils.Safe(func() { - m.readLines <- n + self.readLines <- n }) } // note: onDone may be called twice -func (m *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), prefix string, linesToRead int, onDone func()) func(chan struct{}) error { +func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), prefix string, linesToRead int, onDone func()) func(chan struct{}) error { return func(stop chan struct{}) error { var once sync.Once var onDoneWrapper func() @@ -85,8 +85,8 @@ func (m *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), pref onDoneWrapper = func() { once.Do(onDone) } } - if m.throttle { - m.Log.Info("throttling task") + if self.throttle { + self.Log.Info("throttling task") time.Sleep(THROTTLE_TIME) } @@ -106,10 +106,10 @@ func (m *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), pref // are running slow at the moment. This is admittedly a crude estimate, but // the point is that we only want to throttle when things are running slow // and the user is flicking through a bunch of items. - m.throttle = time.Since(startTime) < THROTTLE_TIME && timeToStart > COMMAND_START_THRESHOLD + self.throttle = time.Since(startTime) < THROTTLE_TIME && timeToStart > COMMAND_START_THRESHOLD if err := oscommands.Kill(cmd); err != nil { if !strings.Contains(err.Error(), "process already finished") { - m.Log.Errorf("error when running cmd task: %v", err) + self.Log.Errorf("error when running cmd task: %v", err) } } @@ -122,7 +122,7 @@ func (m *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), pref loadingMutex := sync.Mutex{} // not sure if it's the right move to redefine this or not - m.readLines = make(chan int, 1024) + self.readLines = make(chan int, 1024) done := make(chan struct{}) @@ -140,9 +140,9 @@ func (m *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), pref case <-ticker.C: loadingMutex.Lock() if !loaded { - m.beforeStart() - _, _ = m.writer.Write([]byte("loading...")) - m.refreshView() + self.beforeStart() + _, _ = self.writer.Write([]byte("loading...")) + self.refreshView() } loadingMutex.Unlock() } @@ -154,7 +154,7 @@ func (m *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), pref select { case <-stop: break outer - case linesToRead := <-m.readLines: + case linesToRead := <-self.readLines: for i := 0; i < linesToRead; i++ { select { case <-stop: @@ -165,9 +165,9 @@ func (m *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), pref ok := scanner.Scan() loadingMutex.Lock() if !loaded { - m.beforeStart() + self.beforeStart() if prefix != "" { - _, _ = m.writer.Write([]byte(prefix)) + _, _ = self.writer.Write([]byte(prefix)) } loaded = true } @@ -176,21 +176,21 @@ func (m *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), pref if !ok { // if we're here then there's nothing left to scan from the source // so we're at the EOF and can flush the stale content - m.onEndOfInput() + self.onEndOfInput() break outer } - _, _ = m.writer.Write(append(scanner.Bytes(), '\n')) + _, _ = self.writer.Write(append(scanner.Bytes(), '\n')) } - m.refreshView() + self.refreshView() } } - m.refreshView() + self.refreshView() if err := cmd.Wait(); err != nil { // it's fine if we've killed this program ourselves if !strings.Contains(err.Error(), "signal: killed") { - m.Log.Error(err) + self.Log.Error(err) } } @@ -202,7 +202,7 @@ func (m *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), pref close(done) }) - m.readLines <- linesToRead + self.readLines <- linesToRead <-done @@ -211,15 +211,15 @@ func (m *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), pref } // Close closes the task manager, killing whatever task may currently be running -func (t *ViewBufferManager) Close() { - if t.stopCurrentTask == nil { +func (self *ViewBufferManager) Close() { + if self.stopCurrentTask == nil { return } c := make(chan struct{}) go utils.Safe(func() { - t.stopCurrentTask() + self.stopCurrentTask() c <- struct{}{} }) @@ -235,28 +235,28 @@ func (t *ViewBufferManager) Close() { // 1) command based, where the manager can be asked to read more lines, but the command can be killed // 2) string based, where the manager can also be asked to read more lines -func (m *ViewBufferManager) NewTask(f func(stop chan struct{}) error, key string) error { +func (self *ViewBufferManager) NewTask(f func(stop chan struct{}) error, key string) error { go utils.Safe(func() { - m.taskIDMutex.Lock() - m.newTaskId++ - taskID := m.newTaskId + self.taskIDMutex.Lock() + self.newTaskID++ + taskID := self.newTaskID - if m.GetTaskKey() != key && m.onNewKey != nil { - m.onNewKey() + if self.GetTaskKey() != key && self.onNewKey != nil { + self.onNewKey() } - m.taskKey = key + self.taskKey = key - m.taskIDMutex.Unlock() + self.taskIDMutex.Unlock() - m.waitingMutex.Lock() - defer m.waitingMutex.Unlock() + self.waitingMutex.Lock() + defer self.waitingMutex.Unlock() - if taskID < m.newTaskId { + if taskID < self.newTaskID { return } - if m.stopCurrentTask != nil { - m.stopCurrentTask() + if self.stopCurrentTask != nil { + self.stopCurrentTask() } stop := make(chan struct{}) @@ -268,11 +268,11 @@ func (m *ViewBufferManager) NewTask(f func(stop chan struct{}) error, key string <-notifyStopped } - m.stopCurrentTask = func() { once.Do(onStop) } + self.stopCurrentTask = func() { once.Do(onStop) } go utils.Safe(func() { if err := f(stop); err != nil { - m.Log.Error(err) // might need an onError callback + self.Log.Error(err) // might need an onError callback } close(notifyStopped) diff --git a/pkg/test/log.go b/pkg/test/log.go index 3b166bb5d..32d79b987 100644 --- a/pkg/test/log.go +++ b/pkg/test/log.go @@ -8,9 +8,7 @@ import ( "github.com/stretchr/testify/assert" ) -var ( - _ logrus.FieldLogger = &FakeFieldLogger{} -) +var _ logrus.FieldLogger = &FakeFieldLogger{} // for now we're just tracking calls to the Error and Errorf methods type FakeFieldLogger struct { @@ -37,5 +35,6 @@ func (self *FakeFieldLogger) Errorf(format string, args ...interface{}) { } func (self *FakeFieldLogger) AssertErrors(t *testing.T, expectedErrors []string) { + t.Helper() assert.EqualValues(t, expectedErrors, self.loggedErrors) } diff --git a/pkg/utils/color.go b/pkg/utils/color.go index 37c60179a..2eced49e2 100644 --- a/pkg/utils/color.go +++ b/pkg/utils/color.go @@ -8,8 +8,10 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/style" ) -var decoloriseCache = make(map[string]string) -var decoloriseMutex sync.RWMutex +var ( + decoloriseCache = make(map[string]string) + decoloriseMutex sync.RWMutex +) // Decolorise strips a string of color func Decolorise(str string) string { diff --git a/pkg/utils/color_test.go b/pkg/utils/color_test.go index 37144e955..1440f946c 100644 --- a/pkg/utils/color_test.go +++ b/pkg/utils/color_test.go @@ -5,7 +5,7 @@ import ( ) func TestDecolorise(t *testing.T) { - var tests = []struct { + tests := []struct { input string output string }{ diff --git a/pkg/utils/lines_test.go b/pkg/utils/lines_test.go index 6069b8f93..faafb863a 100644 --- a/pkg/utils/lines_test.go +++ b/pkg/utils/lines_test.go @@ -65,7 +65,7 @@ func TestNormalizeLinefeeds(t *testing.T) { byteArray []byte expected []byte } - var scenarios = []scenario{ + scenarios := []scenario{ { // \r\n []byte{97, 115, 100, 102, 13, 10}, diff --git a/test/runner/main.go b/test/runner/main.go index af6195cbc..509b66772 100644 --- a/test/runner/main.go +++ b/test/runner/main.go @@ -38,7 +38,7 @@ func main() { }, mode, speedEnv, - func(_t *testing.T, expected string, actual string, prefix string) { + func(_t *testing.T, expected string, actual string, prefix string) { //nolint:thelper assert.Equal(MockTestingT{}, expected, actual, fmt.Sprintf("Unexpected %s. Expected:\n%s\nActual:\n%s\n", prefix, expected, actual)) }, includeSkipped, diff --git a/vendor/golang.org/x/exp/AUTHORS b/vendor/golang.org/x/exp/AUTHORS new file mode 100644 index 000000000..15167cd74 --- /dev/null +++ b/vendor/golang.org/x/exp/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/exp/CONTRIBUTORS b/vendor/golang.org/x/exp/CONTRIBUTORS new file mode 100644 index 000000000..1c4577e96 --- /dev/null +++ b/vendor/golang.org/x/exp/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/exp/LICENSE b/vendor/golang.org/x/exp/LICENSE new file mode 100644 index 000000000..6a66aea5e --- /dev/null +++ b/vendor/golang.org/x/exp/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/exp/PATENTS b/vendor/golang.org/x/exp/PATENTS new file mode 100644 index 000000000..733099041 --- /dev/null +++ b/vendor/golang.org/x/exp/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/exp/constraints/constraints.go b/vendor/golang.org/x/exp/constraints/constraints.go new file mode 100644 index 000000000..2c033dff4 --- /dev/null +++ b/vendor/golang.org/x/exp/constraints/constraints.go @@ -0,0 +1,50 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package constraints defines a set of useful constraints to be used +// with type parameters. +package constraints + +// Signed is a constraint that permits any signed integer type. +// If future releases of Go add new predeclared signed integer types, +// this constraint will be modified to include them. +type Signed interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 +} + +// Unsigned is a constraint that permits any unsigned integer type. +// If future releases of Go add new predeclared unsigned integer types, +// this constraint will be modified to include them. +type Unsigned interface { + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr +} + +// Integer is a constraint that permits any integer type. +// If future releases of Go add new predeclared integer types, +// this constraint will be modified to include them. +type Integer interface { + Signed | Unsigned +} + +// Float is a constraint that permits any floating-point type. +// If future releases of Go add new predeclared floating-point types, +// this constraint will be modified to include them. +type Float interface { + ~float32 | ~float64 +} + +// Complex is a constraint that permits any complex numeric type. +// If future releases of Go add new predeclared complex numeric types, +// this constraint will be modified to include them. +type Complex interface { + ~complex64 | ~complex128 +} + +// Ordered is a constraint that permits any ordered type: any type +// that supports the operators < <= >= >. +// If future releases of Go add new ordered types, +// this constraint will be modified to include them. +type Ordered interface { + Integer | Float | ~string +} diff --git a/vendor/golang.org/x/exp/slices/slices.go b/vendor/golang.org/x/exp/slices/slices.go new file mode 100644 index 000000000..df78daf90 --- /dev/null +++ b/vendor/golang.org/x/exp/slices/slices.go @@ -0,0 +1,213 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package slices defines various functions useful with slices of any type. +// Unless otherwise specified, these functions all apply to the elements +// of a slice at index 0 <= i < len(s). +package slices + +import "golang.org/x/exp/constraints" + +// Equal reports whether two slices are equal: the same length and all +// elements equal. If the lengths are different, Equal returns false. +// Otherwise, the elements are compared in increasing index order, and the +// comparison stops at the first unequal pair. +// Floating point NaNs are not considered equal. +func Equal[E comparable](s1, s2 []E) bool { + if len(s1) != len(s2) { + return false + } + for i := range s1 { + if s1[i] != s2[i] { + return false + } + } + return true +} + +// EqualFunc reports whether two slices are equal using a comparison +// function on each pair of elements. If the lengths are different, +// EqualFunc returns false. Otherwise, the elements are compared in +// increasing index order, and the comparison stops at the first index +// for which eq returns false. +func EqualFunc[E1, E2 any](s1 []E1, s2 []E2, eq func(E1, E2) bool) bool { + if len(s1) != len(s2) { + return false + } + for i, v1 := range s1 { + v2 := s2[i] + if !eq(v1, v2) { + return false + } + } + return true +} + +// Compare compares the elements of s1 and s2. +// The elements are compared sequentially, starting at index 0, +// until one element is not equal to the other. +// The result of comparing the first non-matching elements is returned. +// If both slices are equal until one of them ends, the shorter slice is +// considered less than the longer one. +// The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2. +// Comparisons involving floating point NaNs are ignored. +func Compare[E constraints.Ordered](s1, s2 []E) int { + s2len := len(s2) + for i, v1 := range s1 { + if i >= s2len { + return +1 + } + v2 := s2[i] + switch { + case v1 < v2: + return -1 + case v1 > v2: + return +1 + } + } + if len(s1) < s2len { + return -1 + } + return 0 +} + +// CompareFunc is like Compare but uses a comparison function +// on each pair of elements. The elements are compared in increasing +// index order, and the comparisons stop after the first time cmp +// returns non-zero. +// The result is the first non-zero result of cmp; if cmp always +// returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2), +// and +1 if len(s1) > len(s2). +func CompareFunc[E1, E2 any](s1 []E1, s2 []E2, cmp func(E1, E2) int) int { + s2len := len(s2) + for i, v1 := range s1 { + if i >= s2len { + return +1 + } + v2 := s2[i] + if c := cmp(v1, v2); c != 0 { + return c + } + } + if len(s1) < s2len { + return -1 + } + return 0 +} + +// Index returns the index of the first occurrence of v in s, +// or -1 if not present. +func Index[E comparable](s []E, v E) int { + for i, vs := range s { + if v == vs { + return i + } + } + return -1 +} + +// IndexFunc returns the first index i satisfying f(s[i]), +// or -1 if none do. +func IndexFunc[E any](s []E, f func(E) bool) int { + for i, v := range s { + if f(v) { + return i + } + } + return -1 +} + +// Contains reports whether v is present in s. +func Contains[E comparable](s []E, v E) bool { + return Index(s, v) >= 0 +} + +// Insert inserts the values v... into s at index i, +// returning the modified slice. +// In the returned slice r, r[i] == v[0]. +// Insert panics if i is out of range. +// This function is O(len(s) + len(v)). +func Insert[S ~[]E, E any](s S, i int, v ...E) S { + tot := len(s) + len(v) + if tot <= cap(s) { + s2 := s[:tot] + copy(s2[i+len(v):], s[i:]) + copy(s2[i:], v) + return s2 + } + s2 := make(S, tot) + copy(s2, s[:i]) + copy(s2[i:], v) + copy(s2[i+len(v):], s[i:]) + return s2 +} + +// Delete removes the elements s[i:j] from s, returning the modified slice. +// Delete panics if s[i:j] is not a valid slice of s. +// Delete modifies the contents of the slice s; it does not create a new slice. +// Delete is O(len(s)-(j-i)), so if many items must be deleted, it is better to +// make a single call deleting them all together than to delete one at a time. +func Delete[S ~[]E, E any](s S, i, j int) S { + return append(s[:i], s[j:]...) +} + +// Clone returns a copy of the slice. +// The elements are copied using assignment, so this is a shallow clone. +func Clone[S ~[]E, E any](s S) S { + // Preserve nil in case it matters. + if s == nil { + return nil + } + return append(S([]E{}), s...) +} + +// Compact replaces consecutive runs of equal elements with a single copy. +// This is like the uniq command found on Unix. +// Compact modifies the contents of the slice s; it does not create a new slice. +func Compact[S ~[]E, E comparable](s S) S { + if len(s) == 0 { + return s + } + i := 1 + last := s[0] + for _, v := range s[1:] { + if v != last { + s[i] = v + i++ + last = v + } + } + return s[:i] +} + +// CompactFunc is like Compact but uses a comparison function. +func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S { + if len(s) == 0 { + return s + } + i := 1 + last := s[0] + for _, v := range s[1:] { + if !eq(v, last) { + s[i] = v + i++ + last = v + } + } + return s[:i] +} + +// Grow increases the slice's capacity, if necessary, to guarantee space for +// another n elements. After Grow(n), at least n elements can be appended +// to the slice without another allocation. Grow may modify elements of the +// slice between the length and the capacity. If n is negative or too large to +// allocate the memory, Grow panics. +func Grow[S ~[]E, E any](s S, n int) S { + return append(s, make(S, n)...)[:len(s)] +} + +// Clip removes unused capacity from the slice, returning s[:len(s):len(s)]. +func Clip[S ~[]E, E any](s S) S { + return s[:len(s):len(s)] +} diff --git a/vendor/golang.org/x/exp/slices/sort.go b/vendor/golang.org/x/exp/slices/sort.go new file mode 100644 index 000000000..b2035abe8 --- /dev/null +++ b/vendor/golang.org/x/exp/slices/sort.go @@ -0,0 +1,95 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package slices + +import "golang.org/x/exp/constraints" + +// Sort sorts a slice of any ordered type in ascending order. +func Sort[E constraints.Ordered](x []E) { + n := len(x) + quickSortOrdered(x, 0, n, maxDepth(n)) +} + +// Sort sorts the slice x in ascending order as determined by the less function. +// This sort is not guaranteed to be stable. +func SortFunc[E any](x []E, less func(a, b E) bool) { + n := len(x) + quickSortLessFunc(x, 0, n, maxDepth(n), less) +} + +// SortStable sorts the slice x while keeping the original order of equal +// elements, using less to compare elements. +func SortStableFunc[E any](x []E, less func(a, b E) bool) { + stableLessFunc(x, len(x), less) +} + +// IsSorted reports whether x is sorted in ascending order. +func IsSorted[E constraints.Ordered](x []E) bool { + for i := len(x) - 1; i > 0; i-- { + if x[i] < x[i-1] { + return false + } + } + return true +} + +// IsSortedFunc reports whether x is sorted in ascending order, with less as the +// comparison function. +func IsSortedFunc[E any](x []E, less func(a, b E) bool) bool { + for i := len(x) - 1; i > 0; i-- { + if less(x[i], x[i-1]) { + return false + } + } + return true +} + +// BinarySearch searches for target in a sorted slice and returns the smallest +// index at which target is found. If the target is not found, the index at +// which it could be inserted into the slice is returned; therefore, if the +// intention is to find target itself a separate check for equality with the +// element at the returned index is required. +func BinarySearch[E constraints.Ordered](x []E, target E) int { + return search(len(x), func(i int) bool { return x[i] >= target }) +} + +// BinarySearchFunc uses binary search to find and return the smallest index i +// in [0, n) at which ok(i) is true, assuming that on the range [0, n), +// ok(i) == true implies ok(i+1) == true. That is, BinarySearchFunc requires +// that ok is false for some (possibly empty) prefix of the input range [0, n) +// and then true for the (possibly empty) remainder; BinarySearchFunc returns +// the first true index. If there is no such index, BinarySearchFunc returns n. +// (Note that the "not found" return value is not -1 as in, for instance, +// strings.Index.) Search calls ok(i) only for i in the range [0, n). +func BinarySearchFunc[E any](x []E, ok func(E) bool) int { + return search(len(x), func(i int) bool { return ok(x[i]) }) +} + +// maxDepth returns a threshold at which quicksort should switch +// to heapsort. It returns 2*ceil(lg(n+1)). +func maxDepth(n int) int { + var depth int + for i := n; i > 0; i >>= 1 { + depth++ + } + return depth * 2 +} + +func search(n int, f func(int) bool) int { + // Define f(-1) == false and f(n) == true. + // Invariant: f(i-1) == false, f(j) == true. + i, j := 0, n + for i < j { + h := int(uint(i+j) >> 1) // avoid overflow when computing h + // i 鈮 h < j + if !f(h) { + i = h + 1 // preserves f(i-1) == false + } else { + j = h // preserves f(j) == true + } + } + // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i. + return i +} diff --git a/vendor/golang.org/x/exp/slices/zsortfunc.go b/vendor/golang.org/x/exp/slices/zsortfunc.go new file mode 100644 index 000000000..82f156fd6 --- /dev/null +++ b/vendor/golang.org/x/exp/slices/zsortfunc.go @@ -0,0 +1,342 @@ +// Code generated by gen_sort_variants.go; DO NOT EDIT. + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package slices + +// insertionSortLessFunc sorts data[a:b] using insertion sort. +func insertionSortLessFunc[Elem any](data []Elem, a, b int, less func(a, b Elem) bool) { + for i := a + 1; i < b; i++ { + for j := i; j > a && less(data[j], data[j-1]); j-- { + data[j], data[j-1] = data[j-1], data[j] + } + } +} + +// siftDownLessFunc implements the heap property on data[lo:hi]. +// first is an offset into the array where the root of the heap lies. +func siftDownLessFunc[Elem any](data []Elem, lo, hi, first int, less func(a, b Elem) bool) { + root := lo + for { + child := 2*root + 1 + if child >= hi { + break + } + if child+1 < hi && less(data[first+child], data[first+child+1]) { + child++ + } + if !less(data[first+root], data[first+child]) { + return + } + data[first+root], data[first+child] = data[first+child], data[first+root] + root = child + } +} + +func heapSortLessFunc[Elem any](data []Elem, a, b int, less func(a, b Elem) bool) { + first := a + lo := 0 + hi := b - a + + // Build heap with greatest element at top. + for i := (hi - 1) / 2; i >= 0; i-- { + siftDownLessFunc(data, i, hi, first, less) + } + + // Pop elements, largest first, into end of data. + for i := hi - 1; i >= 0; i-- { + data[first], data[first+i] = data[first+i], data[first] + siftDownLessFunc(data, lo, i, first, less) + } +} + +// Quicksort, loosely following Bentley and McIlroy, +// "Engineering a Sort Function" SP&E November 1993. + +// medianOfThreeLessFunc moves the median of the three values data[m0], data[m1], data[m2] into data[m1]. +func medianOfThreeLessFunc[Elem any](data []Elem, m1, m0, m2 int, less func(a, b Elem) bool) { + // sort 3 elements + if less(data[m1], data[m0]) { + data[m1], data[m0] = data[m0], data[m1] + } + // data[m0] <= data[m1] + if less(data[m2], data[m1]) { + data[m2], data[m1] = data[m1], data[m2] + // data[m0] <= data[m2] && data[m1] < data[m2] + if less(data[m1], data[m0]) { + data[m1], data[m0] = data[m0], data[m1] + } + } + // now data[m0] <= data[m1] <= data[m2] +} + +func swapRangeLessFunc[Elem any](data []Elem, a, b, n int, less func(a, b Elem) bool) { + for i := 0; i < n; i++ { + data[a+i], data[b+i] = data[b+i], data[a+i] + } +} + +func doPivotLessFunc[Elem any](data []Elem, lo, hi int, less func(a, b Elem) bool) (midlo, midhi int) { + m := int(uint(lo+hi) >> 1) // Written like this to avoid integer overflow. + if hi-lo > 40 { + // Tukey's "Ninther" median of three medians of three. + s := (hi - lo) / 8 + medianOfThreeLessFunc(data, lo, lo+s, lo+2*s, less) + medianOfThreeLessFunc(data, m, m-s, m+s, less) + medianOfThreeLessFunc(data, hi-1, hi-1-s, hi-1-2*s, less) + } + medianOfThreeLessFunc(data, lo, m, hi-1, less) + + // Invariants are: + // data[lo] = pivot (set up by ChoosePivot) + // data[lo < i < a] < pivot + // data[a <= i < b] <= pivot + // data[b <= i < c] unexamined + // data[c <= i < hi-1] > pivot + // data[hi-1] >= pivot + pivot := lo + a, c := lo+1, hi-1 + + for ; a < c && less(data[a], data[pivot]); a++ { + } + b := a + for { + for ; b < c && !less(data[pivot], data[b]); b++ { // data[b] <= pivot + } + for ; b < c && less(data[pivot], data[c-1]); c-- { // data[c-1] > pivot + } + if b >= c { + break + } + // data[b] > pivot; data[c-1] <= pivot + data[b], data[c-1] = data[c-1], data[b] + b++ + c-- + } + // If hi-c<3 then there are duplicates (by property of median of nine). + // Let's be a bit more conservative, and set border to 5. + protect := hi-c < 5 + if !protect && hi-c < (hi-lo)/4 { + // Lets test some points for equality to pivot + dups := 0 + if !less(data[pivot], data[hi-1]) { // data[hi-1] = pivot + data[c], data[hi-1] = data[hi-1], data[c] + c++ + dups++ + } + if !less(data[b-1], data[pivot]) { // data[b-1] = pivot + b-- + dups++ + } + // m-lo = (hi-lo)/2 > 6 + // b-lo > (hi-lo)*3/4-1 > 8 + // ==> m < b ==> data[m] <= pivot + if !less(data[m], data[pivot]) { // data[m] = pivot + data[m], data[b-1] = data[b-1], data[m] + b-- + dups++ + } + // if at least 2 points are equal to pivot, assume skewed distribution + protect = dups > 1 + } + if protect { + // Protect against a lot of duplicates + // Add invariant: + // data[a <= i < b] unexamined + // data[b <= i < c] = pivot + for { + for ; a < b && !less(data[b-1], data[pivot]); b-- { // data[b] == pivot + } + for ; a < b && less(data[a], data[pivot]); a++ { // data[a] < pivot + } + if a >= b { + break + } + // data[a] == pivot; data[b-1] < pivot + data[a], data[b-1] = data[b-1], data[a] + a++ + b-- + } + } + // Swap pivot into middle + data[pivot], data[b-1] = data[b-1], data[pivot] + return b - 1, c +} + +func quickSortLessFunc[Elem any](data []Elem, a, b, maxDepth int, less func(a, b Elem) bool) { + for b-a > 12 { // Use ShellSort for slices <= 12 elements + if maxDepth == 0 { + heapSortLessFunc(data, a, b, less) + return + } + maxDepth-- + mlo, mhi := doPivotLessFunc(data, a, b, less) + // Avoiding recursion on the larger subproblem guarantees + // a stack depth of at most lg(b-a). + if mlo-a < b-mhi { + quickSortLessFunc(data, a, mlo, maxDepth, less) + a = mhi // i.e., quickSortLessFunc(data, mhi, b) + } else { + quickSortLessFunc(data, mhi, b, maxDepth, less) + b = mlo // i.e., quickSortLessFunc(data, a, mlo) + } + } + if b-a > 1 { + // Do ShellSort pass with gap 6 + // It could be written in this simplified form cause b-a <= 12 + for i := a + 6; i < b; i++ { + if less(data[i], data[i-6]) { + data[i], data[i-6] = data[i-6], data[i] + } + } + insertionSortLessFunc(data, a, b, less) + } +} + +func stableLessFunc[Elem any](data []Elem, n int, less func(a, b Elem) bool) { + blockSize := 20 // must be > 0 + a, b := 0, blockSize + for b <= n { + insertionSortLessFunc(data, a, b, less) + a = b + b += blockSize + } + insertionSortLessFunc(data, a, n, less) + + for blockSize < n { + a, b = 0, 2*blockSize + for b <= n { + symMergeLessFunc(data, a, a+blockSize, b, less) + a = b + b += 2 * blockSize + } + if m := a + blockSize; m < n { + symMergeLessFunc(data, a, m, n, less) + } + blockSize *= 2 + } +} + +// symMergeLessFunc merges the two sorted subsequences data[a:m] and data[m:b] using +// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum +// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz +// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in +// Computer Science, pages 714-723. Springer, 2004. +// +// Let M = m-a and N = b-n. Wolog M < N. +// The recursion depth is bound by ceil(log(N+M)). +// The algorithm needs O(M*log(N/M + 1)) calls to data.Less. +// The algorithm needs O((M+N)*log(M)) calls to data.Swap. +// +// The paper gives O((M+N)*log(M)) as the number of assignments assuming a +// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation +// in the paper carries through for Swap operations, especially as the block +// swapping rotate uses only O(M+N) Swaps. +// +// symMerge assumes non-degenerate arguments: a < m && m < b. +// Having the caller check this condition eliminates many leaf recursion calls, +// which improves performance. +func symMergeLessFunc[Elem any](data []Elem, a, m, b int, less func(a, b Elem) bool) { + // Avoid unnecessary recursions of symMerge + // by direct insertion of data[a] into data[m:b] + // if data[a:m] only contains one element. + if m-a == 1 { + // Use binary search to find the lowest index i + // such that data[i] >= data[a] for m <= i < b. + // Exit the search loop with i == b in case no such index exists. + i := m + j := b + for i < j { + h := int(uint(i+j) >> 1) + if less(data[h], data[a]) { + i = h + 1 + } else { + j = h + } + } + // Swap values until data[a] reaches the position before i. + for k := a; k < i-1; k++ { + data[k], data[k+1] = data[k+1], data[k] + } + return + } + + // Avoid unnecessary recursions of symMerge + // by direct insertion of data[m] into data[a:m] + // if data[m:b] only contains one element. + if b-m == 1 { + // Use binary search to find the lowest index i + // such that data[i] > data[m] for a <= i < m. + // Exit the search loop with i == m in case no such index exists. + i := a + j := m + for i < j { + h := int(uint(i+j) >> 1) + if !less(data[m], data[h]) { + i = h + 1 + } else { + j = h + } + } + // Swap values until data[m] reaches the position i. + for k := m; k > i; k-- { + data[k], data[k-1] = data[k-1], data[k] + } + return + } + + mid := int(uint(a+b) >> 1) + n := mid + m + var start, r int + if m > mid { + start = n - b + r = mid + } else { + start = a + r = m + } + p := n - 1 + + for start < r { + c := int(uint(start+r) >> 1) + if !less(data[p-c], data[c]) { + start = c + 1 + } else { + r = c + } + } + + end := n - start + if start < m && m < end { + rotateLessFunc(data, start, m, end, less) + } + if a < start && start < mid { + symMergeLessFunc(data, a, start, mid, less) + } + if mid < end && end < b { + symMergeLessFunc(data, mid, end, b, less) + } +} + +// rotateLessFunc rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data: +// Data of the form 'x u v y' is changed to 'x v u y'. +// rotate performs at most b-a many calls to data.Swap, +// and it assumes non-degenerate arguments: a < m && m < b. +func rotateLessFunc[Elem any](data []Elem, a, m, b int, less func(a, b Elem) bool) { + i := m - a + j := b - m + + for i != j { + if i > j { + swapRangeLessFunc(data, m-i, m, j, less) + i -= j + } else { + swapRangeLessFunc(data, m-i, m+j-i, i, less) + j -= i + } + } + // i == j + swapRangeLessFunc(data, m-i, m, i, less) +} diff --git a/vendor/golang.org/x/exp/slices/zsortordered.go b/vendor/golang.org/x/exp/slices/zsortordered.go new file mode 100644 index 000000000..6fa64a2e2 --- /dev/null +++ b/vendor/golang.org/x/exp/slices/zsortordered.go @@ -0,0 +1,344 @@ +// Code generated by gen_sort_variants.go; DO NOT EDIT. + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package slices + +import "golang.org/x/exp/constraints" + +// insertionSortOrdered sorts data[a:b] using insertion sort. +func insertionSortOrdered[Elem constraints.Ordered](data []Elem, a, b int) { + for i := a + 1; i < b; i++ { + for j := i; j > a && (data[j] < data[j-1]); j-- { + data[j], data[j-1] = data[j-1], data[j] + } + } +} + +// siftDownOrdered implements the heap property on data[lo:hi]. +// first is an offset into the array where the root of the heap lies. +func siftDownOrdered[Elem constraints.Ordered](data []Elem, lo, hi, first int) { + root := lo + for { + child := 2*root + 1 + if child >= hi { + break + } + if child+1 < hi && (data[first+child] < data[first+child+1]) { + child++ + } + if !(data[first+root] < data[first+child]) { + return + } + data[first+root], data[first+child] = data[first+child], data[first+root] + root = child + } +} + +func heapSortOrdered[Elem constraints.Ordered](data []Elem, a, b int) { + first := a + lo := 0 + hi := b - a + + // Build heap with greatest element at top. + for i := (hi - 1) / 2; i >= 0; i-- { + siftDownOrdered(data, i, hi, first) + } + + // Pop elements, largest first, into end of data. + for i := hi - 1; i >= 0; i-- { + data[first], data[first+i] = data[first+i], data[first] + siftDownOrdered(data, lo, i, first) + } +} + +// Quicksort, loosely following Bentley and McIlroy, +// "Engineering a Sort Function" SP&E November 1993. + +// medianOfThreeOrdered moves the median of the three values data[m0], data[m1], data[m2] into data[m1]. +func medianOfThreeOrdered[Elem constraints.Ordered](data []Elem, m1, m0, m2 int) { + // sort 3 elements + if data[m1] < data[m0] { + data[m1], data[m0] = data[m0], data[m1] + } + // data[m0] <= data[m1] + if data[m2] < data[m1] { + data[m2], data[m1] = data[m1], data[m2] + // data[m0] <= data[m2] && data[m1] < data[m2] + if data[m1] < data[m0] { + data[m1], data[m0] = data[m0], data[m1] + } + } + // now data[m0] <= data[m1] <= data[m2] +} + +func swapRangeOrdered[Elem constraints.Ordered](data []Elem, a, b, n int) { + for i := 0; i < n; i++ { + data[a+i], data[b+i] = data[b+i], data[a+i] + } +} + +func doPivotOrdered[Elem constraints.Ordered](data []Elem, lo, hi int) (midlo, midhi int) { + m := int(uint(lo+hi) >> 1) // Written like this to avoid integer overflow. + if hi-lo > 40 { + // Tukey's "Ninther" median of three medians of three. + s := (hi - lo) / 8 + medianOfThreeOrdered(data, lo, lo+s, lo+2*s) + medianOfThreeOrdered(data, m, m-s, m+s) + medianOfThreeOrdered(data, hi-1, hi-1-s, hi-1-2*s) + } + medianOfThreeOrdered(data, lo, m, hi-1) + + // Invariants are: + // data[lo] = pivot (set up by ChoosePivot) + // data[lo < i < a] < pivot + // data[a <= i < b] <= pivot + // data[b <= i < c] unexamined + // data[c <= i < hi-1] > pivot + // data[hi-1] >= pivot + pivot := lo + a, c := lo+1, hi-1 + + for ; a < c && (data[a] < data[pivot]); a++ { + } + b := a + for { + for ; b < c && !(data[pivot] < data[b]); b++ { // data[b] <= pivot + } + for ; b < c && (data[pivot] < data[c-1]); c-- { // data[c-1] > pivot + } + if b >= c { + break + } + // data[b] > pivot; data[c-1] <= pivot + data[b], data[c-1] = data[c-1], data[b] + b++ + c-- + } + // If hi-c<3 then there are duplicates (by property of median of nine). + // Let's be a bit more conservative, and set border to 5. + protect := hi-c < 5 + if !protect && hi-c < (hi-lo)/4 { + // Lets test some points for equality to pivot + dups := 0 + if !(data[pivot] < data[hi-1]) { // data[hi-1] = pivot + data[c], data[hi-1] = data[hi-1], data[c] + c++ + dups++ + } + if !(data[b-1] < data[pivot]) { // data[b-1] = pivot + b-- + dups++ + } + // m-lo = (hi-lo)/2 > 6 + // b-lo > (hi-lo)*3/4-1 > 8 + // ==> m < b ==> data[m] <= pivot + if !(data[m] < data[pivot]) { // data[m] = pivot + data[m], data[b-1] = data[b-1], data[m] + b-- + dups++ + } + // if at least 2 points are equal to pivot, assume skewed distribution + protect = dups > 1 + } + if protect { + // Protect against a lot of duplicates + // Add invariant: + // data[a <= i < b] unexamined + // data[b <= i < c] = pivot + for { + for ; a < b && !(data[b-1] < data[pivot]); b-- { // data[b] == pivot + } + for ; a < b && (data[a] < data[pivot]); a++ { // data[a] < pivot + } + if a >= b { + break + } + // data[a] == pivot; data[b-1] < pivot + data[a], data[b-1] = data[b-1], data[a] + a++ + b-- + } + } + // Swap pivot into middle + data[pivot], data[b-1] = data[b-1], data[pivot] + return b - 1, c +} + +func quickSortOrdered[Elem constraints.Ordered](data []Elem, a, b, maxDepth int) { + for b-a > 12 { // Use ShellSort for slices <= 12 elements + if maxDepth == 0 { + heapSortOrdered(data, a, b) + return + } + maxDepth-- + mlo, mhi := doPivotOrdered(data, a, b) + // Avoiding recursion on the larger subproblem guarantees + // a stack depth of at most lg(b-a). + if mlo-a < b-mhi { + quickSortOrdered(data, a, mlo, maxDepth) + a = mhi // i.e., quickSortOrdered(data, mhi, b) + } else { + quickSortOrdered(data, mhi, b, maxDepth) + b = mlo // i.e., quickSortOrdered(data, a, mlo) + } + } + if b-a > 1 { + // Do ShellSort pass with gap 6 + // It could be written in this simplified form cause b-a <= 12 + for i := a + 6; i < b; i++ { + if data[i] < data[i-6] { + data[i], data[i-6] = data[i-6], data[i] + } + } + insertionSortOrdered(data, a, b) + } +} + +func stableOrdered[Elem constraints.Ordered](data []Elem, n int) { + blockSize := 20 // must be > 0 + a, b := 0, blockSize + for b <= n { + insertionSortOrdered(data, a, b) + a = b + b += blockSize + } + insertionSortOrdered(data, a, n) + + for blockSize < n { + a, b = 0, 2*blockSize + for b <= n { + symMergeOrdered(data, a, a+blockSize, b) + a = b + b += 2 * blockSize + } + if m := a + blockSize; m < n { + symMergeOrdered(data, a, m, n) + } + blockSize *= 2 + } +} + +// symMergeOrdered merges the two sorted subsequences data[a:m] and data[m:b] using +// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum +// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz +// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in +// Computer Science, pages 714-723. Springer, 2004. +// +// Let M = m-a and N = b-n. Wolog M < N. +// The recursion depth is bound by ceil(log(N+M)). +// The algorithm needs O(M*log(N/M + 1)) calls to data.Less. +// The algorithm needs O((M+N)*log(M)) calls to data.Swap. +// +// The paper gives O((M+N)*log(M)) as the number of assignments assuming a +// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation +// in the paper carries through for Swap operations, especially as the block +// swapping rotate uses only O(M+N) Swaps. +// +// symMerge assumes non-degenerate arguments: a < m && m < b. +// Having the caller check this condition eliminates many leaf recursion calls, +// which improves performance. +func symMergeOrdered[Elem constraints.Ordered](data []Elem, a, m, b int) { + // Avoid unnecessary recursions of symMerge + // by direct insertion of data[a] into data[m:b] + // if data[a:m] only contains one element. + if m-a == 1 { + // Use binary search to find the lowest index i + // such that data[i] >= data[a] for m <= i < b. + // Exit the search loop with i == b in case no such index exists. + i := m + j := b + for i < j { + h := int(uint(i+j) >> 1) + if data[h] < data[a] { + i = h + 1 + } else { + j = h + } + } + // Swap values until data[a] reaches the position before i. + for k := a; k < i-1; k++ { + data[k], data[k+1] = data[k+1], data[k] + } + return + } + + // Avoid unnecessary recursions of symMerge + // by direct insertion of data[m] into data[a:m] + // if data[m:b] only contains one element. + if b-m == 1 { + // Use binary search to find the lowest index i + // such that data[i] > data[m] for a <= i < m. + // Exit the search loop with i == m in case no such index exists. + i := a + j := m + for i < j { + h := int(uint(i+j) >> 1) + if !(data[m] < data[h]) { + i = h + 1 + } else { + j = h + } + } + // Swap values until data[m] reaches the position i. + for k := m; k > i; k-- { + data[k], data[k-1] = data[k-1], data[k] + } + return + } + + mid := int(uint(a+b) >> 1) + n := mid + m + var start, r int + if m > mid { + start = n - b + r = mid + } else { + start = a + r = m + } + p := n - 1 + + for start < r { + c := int(uint(start+r) >> 1) + if !(data[p-c] < data[c]) { + start = c + 1 + } else { + r = c + } + } + + end := n - start + if start < m && m < end { + rotateOrdered(data, start, m, end) + } + if a < start && start < mid { + symMergeOrdered(data, a, start, mid) + } + if mid < end && end < b { + symMergeOrdered(data, mid, end, b) + } +} + +// rotateOrdered rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data: +// Data of the form 'x u v y' is changed to 'x v u y'. +// rotate performs at most b-a many calls to data.Swap, +// and it assumes non-degenerate arguments: a < m && m < b. +func rotateOrdered[Elem constraints.Ordered](data []Elem, a, m, b int) { + i := m - a + j := b - m + + for i != j { + if i > j { + swapRangeOrdered(data, m-i, m, j) + i -= j + } else { + swapRangeOrdered(data, m-i, m+j-i, i) + j -= i + } + } + // i == j + swapRangeOrdered(data, m-i, m, i) +} diff --git a/vendor/gopkg.in/yaml.v3/apic.go b/vendor/gopkg.in/yaml.v3/apic.go index 65846e674..ae7d049f1 100644 --- a/vendor/gopkg.in/yaml.v3/apic.go +++ b/vendor/gopkg.in/yaml.v3/apic.go @@ -108,6 +108,7 @@ func yaml_emitter_initialize(emitter *yaml_emitter_t) { raw_buffer: make([]byte, 0, output_raw_buffer_size), states: make([]yaml_emitter_state_t, 0, initial_stack_size), events: make([]yaml_event_t, 0, initial_queue_size), + best_width: -1, } } diff --git a/vendor/gopkg.in/yaml.v3/decode.go b/vendor/gopkg.in/yaml.v3/decode.go index be63169b7..df36e3a30 100644 --- a/vendor/gopkg.in/yaml.v3/decode.go +++ b/vendor/gopkg.in/yaml.v3/decode.go @@ -35,6 +35,7 @@ type parser struct { doc *Node anchors map[string]*Node doneInit bool + textless bool } func newParser(b []byte) *parser { @@ -108,14 +109,18 @@ func (p *parser) peek() yaml_event_type_t { func (p *parser) fail() { var where string var line int - if p.parser.problem_mark.line != 0 { + if p.parser.context_mark.line != 0 { + line = p.parser.context_mark.line + // Scanner errors don't iterate line before returning error + if p.parser.error == yaml_SCANNER_ERROR { + line++ + } + } else if p.parser.problem_mark.line != 0 { line = p.parser.problem_mark.line // Scanner errors don't iterate line before returning error if p.parser.error == yaml_SCANNER_ERROR { line++ } - } else if p.parser.context_mark.line != 0 { - line = p.parser.context_mark.line } if line != 0 { where = "line " + strconv.Itoa(line) + ": " @@ -169,17 +174,20 @@ func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node { } else if kind == ScalarNode { tag, _ = resolve("", value) } - return &Node{ - Kind: kind, - Tag: tag, - Value: value, - Style: style, - Line: p.event.start_mark.line + 1, - Column: p.event.start_mark.column + 1, - HeadComment: string(p.event.head_comment), - LineComment: string(p.event.line_comment), - FootComment: string(p.event.foot_comment), + n := &Node{ + Kind: kind, + Tag: tag, + Value: value, + Style: style, } + if !p.textless { + n.Line = p.event.start_mark.line + 1 + n.Column = p.event.start_mark.column + 1 + n.HeadComment = string(p.event.head_comment) + n.LineComment = string(p.event.line_comment) + n.FootComment = string(p.event.foot_comment) + } + return n } func (p *parser) parseChild(parent *Node) *Node { @@ -497,8 +505,13 @@ func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) { good = d.mapping(n, out) case SequenceNode: good = d.sequence(n, out) + case 0: + if n.IsZero() { + return d.null(out) + } + fallthrough default: - panic("internal error: unknown node kind: " + strconv.Itoa(int(n.Kind))) + failf("cannot decode node with unknown kind %d", n.Kind) } return good } @@ -533,6 +546,17 @@ func resetMap(out reflect.Value) { } } +func (d *decoder) null(out reflect.Value) bool { + if out.CanAddr() { + switch out.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: + out.Set(reflect.Zero(out.Type())) + return true + } + } + return false +} + func (d *decoder) scalar(n *Node, out reflect.Value) bool { var tag string var resolved interface{} @@ -550,14 +574,7 @@ func (d *decoder) scalar(n *Node, out reflect.Value) bool { } } if resolved == nil { - if out.CanAddr() { - switch out.Kind() { - case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: - out.Set(reflect.Zero(out.Type())) - return true - } - } - return false + return d.null(out) } if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { // We've resolved to exactly the type we want, so use that. @@ -791,8 +808,10 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { } } + mapIsNew := false if out.IsNil() { out.Set(reflect.MakeMap(outt)) + mapIsNew = true } for i := 0; i < l; i += 2 { if isMerge(n.Content[i]) { @@ -809,7 +828,7 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { failf("invalid map key: %#v", k.Interface()) } e := reflect.New(et).Elem() - if d.unmarshal(n.Content[i+1], e) { + if d.unmarshal(n.Content[i+1], e) || n.Content[i+1].ShortTag() == nullTag && (mapIsNew || !out.MapIndex(k).IsValid()) { out.SetMapIndex(k, e) } } diff --git a/vendor/gopkg.in/yaml.v3/emitterc.go b/vendor/gopkg.in/yaml.v3/emitterc.go index ab2a06619..0f47c9ca8 100644 --- a/vendor/gopkg.in/yaml.v3/emitterc.go +++ b/vendor/gopkg.in/yaml.v3/emitterc.go @@ -235,10 +235,13 @@ func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool emitter.indent = 0 } } else if !indentless { - emitter.indent += emitter.best_indent - // [Go] If inside a block sequence item, discount the space taken by the indicator. - if emitter.best_indent > 2 && emitter.states[len(emitter.states)-1] == yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE { - emitter.indent -= 2 + // [Go] This was changed so that indentations are more regular. + if emitter.states[len(emitter.states)-1] == yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE { + // The first indent inside a sequence will just skip the "- " indicator. + emitter.indent += 2 + } else { + // Everything else aligns to the chosen indentation. + emitter.indent = emitter.best_indent*((emitter.indent+emitter.best_indent)/emitter.best_indent) } } return true @@ -725,16 +728,9 @@ func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_e // Expect a block item node. func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { if first { - // [Go] The original logic here would not indent the sequence when inside a mapping. - // In Go we always indent it, but take the sequence indicator out of the indentation. - indentless := emitter.best_indent == 2 && emitter.mapping_context && (emitter.column == 0 || !emitter.indention) - original := emitter.indent - if !yaml_emitter_increase_indent(emitter, false, indentless) { + if !yaml_emitter_increase_indent(emitter, false, false) { return false } - if emitter.indent > original+2 { - emitter.indent -= 2 - } } if event.typ == yaml_SEQUENCE_END_EVENT { emitter.indent = emitter.indents[len(emitter.indents)-1] @@ -785,6 +781,13 @@ func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_ev if !yaml_emitter_write_indent(emitter) { return false } + if len(emitter.line_comment) > 0 { + // [Go] A line comment was provided for the key. That's unusual as the + // scanner associates line comments with the value. Either way, + // save the line comment and render it appropriately later. + emitter.key_line_comment = emitter.line_comment + emitter.line_comment = nil + } if yaml_emitter_check_simple_key(emitter) { emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE) return yaml_emitter_emit_node(emitter, event, false, false, true, true) @@ -810,6 +813,27 @@ func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_ return false } } + if len(emitter.key_line_comment) > 0 { + // [Go] Line comments are generally associated with the value, but when there's + // no value on the same line as a mapping key they end up attached to the + // key itself. + if event.typ == yaml_SCALAR_EVENT { + if len(emitter.line_comment) == 0 { + // A scalar is coming and it has no line comments by itself yet, + // so just let it handle the line comment as usual. If it has a + // line comment, we can't have both so the one from the key is lost. + emitter.line_comment = emitter.key_line_comment + emitter.key_line_comment = nil + } + } else if event.sequence_style() != yaml_FLOW_SEQUENCE_STYLE && (event.typ == yaml_MAPPING_START_EVENT || event.typ == yaml_SEQUENCE_START_EVENT) { + // An indented block follows, so write the comment right now. + emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment + if !yaml_emitter_process_line_comment(emitter) { + return false + } + emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment + } + } emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE) if !yaml_emitter_emit_node(emitter, event, false, false, true, false) { return false @@ -823,6 +847,10 @@ func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_ return true } +func yaml_emitter_silent_nil_event(emitter *yaml_emitter_t, event *yaml_event_t) bool { + return event.typ == yaml_SCALAR_EVENT && event.implicit && !emitter.canonical && len(emitter.scalar_data.value) == 0 +} + // Expect a node. func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t, root bool, sequence bool, mapping bool, simple_key bool) bool { @@ -1866,7 +1894,7 @@ func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bo if !yaml_emitter_write_block_scalar_hints(emitter, value) { return false } - if !put_break(emitter) { + if !yaml_emitter_process_line_comment(emitter) { return false } //emitter.indention = true @@ -1903,10 +1931,10 @@ func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) boo if !yaml_emitter_write_block_scalar_hints(emitter, value) { return false } - - if !put_break(emitter) { + if !yaml_emitter_process_line_comment(emitter) { return false } + //emitter.indention = true emitter.whitespace = true diff --git a/vendor/gopkg.in/yaml.v3/encode.go b/vendor/gopkg.in/yaml.v3/encode.go index 1f37271ce..de9e72a3e 100644 --- a/vendor/gopkg.in/yaml.v3/encode.go +++ b/vendor/gopkg.in/yaml.v3/encode.go @@ -119,6 +119,14 @@ func (e *encoder) marshal(tag string, in reflect.Value) { case *Node: e.nodev(in) return + case Node: + if !in.CanAddr() { + var n = reflect.New(in.Type()).Elem() + n.Set(in) + in = n + } + e.nodev(in.Addr()) + return case time.Time: e.timev(tag, in) return @@ -422,18 +430,23 @@ func (e *encoder) nodev(in reflect.Value) { } func (e *encoder) node(node *Node, tail string) { + // Zero nodes behave as nil. + if node.Kind == 0 && node.IsZero() { + e.nilv() + return + } + // If the tag was not explicitly requested, and dropping it won't change the // implicit tag of the value, don't include it in the presentation. var tag = node.Tag var stag = shortTag(tag) - var rtag string var forceQuoting bool if tag != "" && node.Style&TaggedStyle == 0 { if node.Kind == ScalarNode { if stag == strTag && node.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0 { tag = "" } else { - rtag, _ = resolve("", node.Value) + rtag, _ := resolve("", node.Value) if rtag == stag { tag = "" } else if stag == strTag { @@ -442,6 +455,7 @@ func (e *encoder) node(node *Node, tail string) { } } } else { + var rtag string switch node.Kind { case MappingNode: rtag = mapTag @@ -471,7 +485,7 @@ func (e *encoder) node(node *Node, tail string) { if node.Style&FlowStyle != 0 { style = yaml_FLOW_SEQUENCE_STYLE } - e.must(yaml_sequence_start_event_initialize(&e.event, []byte(node.Anchor), []byte(tag), tag == "", style)) + e.must(yaml_sequence_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style)) e.event.head_comment = []byte(node.HeadComment) e.emit() for _, node := range node.Content { @@ -487,7 +501,7 @@ func (e *encoder) node(node *Node, tail string) { if node.Style&FlowStyle != 0 { style = yaml_FLOW_MAPPING_STYLE } - yaml_mapping_start_event_initialize(&e.event, []byte(node.Anchor), []byte(tag), tag == "", style) + yaml_mapping_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style) e.event.tail_comment = []byte(tail) e.event.head_comment = []byte(node.HeadComment) e.emit() @@ -528,11 +542,11 @@ func (e *encoder) node(node *Node, tail string) { case ScalarNode: value := node.Value if !utf8.ValidString(value) { - if tag == binaryTag { + if stag == binaryTag { failf("explicitly tagged !!binary data must be base64-encoded") } - if tag != "" { - failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag)) + if stag != "" { + failf("cannot marshal invalid UTF-8 data as %s", stag) } // It can't be encoded directly as YAML so use a binary tag // and encode it as base64. @@ -557,5 +571,7 @@ func (e *encoder) node(node *Node, tail string) { } e.emitScalar(value, node.Anchor, tag, style, []byte(node.HeadComment), []byte(node.LineComment), []byte(node.FootComment), []byte(tail)) + default: + failf("cannot encode node with unknown kind %d", node.Kind) } } diff --git a/vendor/gopkg.in/yaml.v3/parserc.go b/vendor/gopkg.in/yaml.v3/parserc.go index aea9050b8..ac66fccc0 100644 --- a/vendor/gopkg.in/yaml.v3/parserc.go +++ b/vendor/gopkg.in/yaml.v3/parserc.go @@ -648,6 +648,10 @@ func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, i implicit: implicit, style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE), } + if parser.stem_comment != nil { + event.head_comment = parser.stem_comment + parser.stem_comment = nil + } return true } if len(anchor) > 0 || len(tag) > 0 { @@ -694,25 +698,13 @@ func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_e if token.typ == yaml_BLOCK_ENTRY_TOKEN { mark := token.end_mark - prior_head := len(parser.head_comment) + prior_head_len := len(parser.head_comment) skip_token(parser) + yaml_parser_split_stem_comment(parser, prior_head_len) token = peek_token(parser) if token == nil { return false } - if prior_head > 0 && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN { - // [Go] It's a sequence under a sequence entry, so the former head comment - // is for the list itself, not the first list item under it. - parser.stem_comment = parser.head_comment[:prior_head] - if len(parser.head_comment) == prior_head { - parser.head_comment = nil - } else { - // Copy suffix to prevent very strange bugs if someone ever appends - // further bytes to the prefix in the stem_comment slice above. - parser.head_comment = append([]byte(nil), parser.head_comment[prior_head+1:]...) - } - - } if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN { parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE) return yaml_parser_parse_node(parser, event, true, false) @@ -754,7 +746,9 @@ func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *y if token.typ == yaml_BLOCK_ENTRY_TOKEN { mark := token.end_mark + prior_head_len := len(parser.head_comment) skip_token(parser) + yaml_parser_split_stem_comment(parser, prior_head_len) token = peek_token(parser) if token == nil { return false @@ -780,6 +774,32 @@ func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *y return true } +// Split stem comment from head comment. +// +// When a sequence or map is found under a sequence entry, the former head comment +// is assigned to the underlying sequence or map as a whole, not the individual +// sequence or map entry as would be expected otherwise. To handle this case the +// previous head comment is moved aside as the stem comment. +func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) { + if stem_len == 0 { + return + } + + token := peek_token(parser) + if token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN { + return + } + + parser.stem_comment = parser.head_comment[:stem_len] + if len(parser.head_comment) == stem_len { + parser.head_comment = nil + } else { + // Copy suffix to prevent very strange bugs if someone ever appends + // further bytes to the prefix in the stem_comment slice above. + parser.head_comment = append([]byte(nil), parser.head_comment[stem_len+1:]...) + } +} + // Parse the productions: // block_mapping ::= BLOCK-MAPPING_START // ******************* diff --git a/vendor/gopkg.in/yaml.v3/scannerc.go b/vendor/gopkg.in/yaml.v3/scannerc.go index 57e954ca5..ca0070108 100644 --- a/vendor/gopkg.in/yaml.v3/scannerc.go +++ b/vendor/gopkg.in/yaml.v3/scannerc.go @@ -749,6 +749,11 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) (ok bool) { if !ok { return } + if len(parser.tokens) > 0 && parser.tokens[len(parser.tokens)-1].typ == yaml_BLOCK_ENTRY_TOKEN { + // Sequence indicators alone have no line comments. It becomes + // a head comment for whatever follows. + return + } if !yaml_parser_scan_line_comment(parser, comment_mark) { ok = false return @@ -2255,10 +2260,9 @@ func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, l } } if parser.buffer[parser.buffer_pos] == '#' { - // TODO Test this and then re-enable it. - //if !yaml_parser_scan_line_comment(parser, start_mark) { - // return false - //} + if !yaml_parser_scan_line_comment(parser, start_mark) { + return false + } for !is_breakz(parser.buffer, parser.buffer_pos) { skip(parser) if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { @@ -2856,13 +2860,12 @@ func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t return false } skip_line(parser) - } else { - if parser.mark.index >= seen { - if len(text) == 0 { - start_mark = parser.mark - } - text = append(text, parser.buffer[parser.buffer_pos]) + } else if parser.mark.index >= seen { + if len(text) == 0 { + start_mark = parser.mark } + text = read(parser, text) + } else { skip(parser) } } @@ -2888,6 +2891,10 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo var token_mark = token.start_mark var start_mark yaml_mark_t + var next_indent = parser.indent + if next_indent < 0 { + next_indent = 0 + } var recent_empty = false var first_empty = parser.newlines <= 1 @@ -2919,15 +2926,18 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo continue } c := parser.buffer[parser.buffer_pos+peek] - if is_breakz(parser.buffer, parser.buffer_pos+peek) || parser.flow_level > 0 && (c == ']' || c == '}') { + var close_flow = parser.flow_level > 0 && (c == ']' || c == '}') + if close_flow || is_breakz(parser.buffer, parser.buffer_pos+peek) { // Got line break or terminator. - if !recent_empty { - if first_empty && (start_mark.line == foot_line || start_mark.column-1 < parser.indent) { + if close_flow || !recent_empty { + if close_flow || first_empty && (start_mark.line == foot_line && token.typ != yaml_VALUE_TOKEN || start_mark.column-1 < next_indent) { // This is the first empty line and there were no empty lines before, // so this initial part of the comment is a foot of the prior token // instead of being a head for the following one. Split it up. + // Alternatively, this might also be the last comment inside a flow + // scope, so it must be a footer. if len(text) > 0 { - if start_mark.column-1 < parser.indent { + if start_mark.column-1 < next_indent { // If dedented it's unrelated to the prior token. token_mark = start_mark } @@ -2958,7 +2968,7 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo continue } - if len(text) > 0 && column < parser.indent+1 && column != start_mark.column { + if len(text) > 0 && (close_flow || column-1 < next_indent && column != start_mark.column) { // The comment at the different indentation is a foot of the // preceding data rather than a head of the upcoming one. parser.comments = append(parser.comments, yaml_comment_t{ @@ -2999,10 +3009,9 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo return false } skip_line(parser) + } else if parser.mark.index >= seen { + text = read(parser, text) } else { - if parser.mark.index >= seen { - text = append(text, parser.buffer[parser.buffer_pos]) - } skip(parser) } } @@ -3010,6 +3019,10 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo peek = 0 column = 0 line = parser.mark.line + next_indent = parser.indent + if next_indent < 0 { + next_indent = 0 + } } if len(text) > 0 { diff --git a/vendor/gopkg.in/yaml.v3/yaml.go b/vendor/gopkg.in/yaml.v3/yaml.go index b5d35a50d..8cec6da48 100644 --- a/vendor/gopkg.in/yaml.v3/yaml.go +++ b/vendor/gopkg.in/yaml.v3/yaml.go @@ -89,7 +89,7 @@ func Unmarshal(in []byte, out interface{}) (err error) { return unmarshal(in, out, false) } -// A Decorder reads and decodes YAML values from an input stream. +// A Decoder reads and decodes YAML values from an input stream. type Decoder struct { parser *parser knownFields bool @@ -194,7 +194,7 @@ func unmarshal(in []byte, out interface{}, strict bool) (err error) { // Zero valued structs will be omitted if all their public // fields are zero, unless they implement an IsZero // method (see the IsZeroer interface type), in which -// case the field will be included if that method returns true. +// case the field will be excluded if IsZero returns true. // // flow Marshal using a flow style (useful for structs, // sequences and maps). @@ -252,6 +252,24 @@ func (e *Encoder) Encode(v interface{}) (err error) { return nil } +// Encode encodes value v and stores its representation in n. +// +// See the documentation for Marshal for details about the +// conversion of Go values into YAML. +func (n *Node) Encode(v interface{}) (err error) { + defer handleErr(&err) + e := newEncoder() + defer e.destroy() + e.marshalDoc("", reflect.ValueOf(v)) + e.finish() + p := newParser(e.out) + p.textless = true + defer p.destroy() + doc := p.parse() + *n = *doc.Content[0] + return nil +} + // SetIndent changes the used indentation used when encoding. func (e *Encoder) SetIndent(spaces int) { if spaces < 0 { @@ -328,6 +346,12 @@ const ( // and maps, Node is an intermediate representation that allows detailed // control over the content being decoded or encoded. // +// It's worth noting that although Node offers access into details such as +// line numbers, colums, and comments, the content when re-encoded will not +// have its original textual representation preserved. An effort is made to +// render the data plesantly, and to preserve comments near the data they +// describe, though. +// // Values that make use of the Node type interact with the yaml package in the // same way any other type would do, by encoding and decoding yaml data // directly or indirectly into them. @@ -391,6 +415,13 @@ type Node struct { Column int } +// IsZero returns whether the node has all of its fields unset. +func (n *Node) IsZero() bool { + return n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" && n.Anchor == "" && n.Alias == nil && n.Content == nil && + n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0 +} + + // LongTag returns the long form of the tag that indicates the data type for // the node. If the Tag field isn't explicitly defined, one will be computed // based on the node properties. @@ -418,6 +449,11 @@ func (n *Node) ShortTag() string { case ScalarNode: tag, _ := resolve("", n.Value) return tag + case 0: + // Special case to make the zero value convenient. + if n.IsZero() { + return nullTag + } } return "" } diff --git a/vendor/gopkg.in/yaml.v3/yamlh.go b/vendor/gopkg.in/yaml.v3/yamlh.go index 2719cfbb0..7c6d00770 100644 --- a/vendor/gopkg.in/yaml.v3/yamlh.go +++ b/vendor/gopkg.in/yaml.v3/yamlh.go @@ -787,6 +787,8 @@ type yaml_emitter_t struct { foot_comment []byte tail_comment []byte + key_line_comment []byte + // Dumper stuff opened bool // If the stream was already opened? diff --git a/vendor/modules.txt b/vendor/modules.txt index 95470036a..f24c14661 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -262,6 +262,10 @@ golang.org/x/crypto/ssh golang.org/x/crypto/ssh/agent golang.org/x/crypto/ssh/internal/bcrypt_pbkdf golang.org/x/crypto/ssh/knownhosts +# golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 +## explicit; go 1.18 +golang.org/x/exp/constraints +golang.org/x/exp/slices # golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c ## explicit; go 1.11 golang.org/x/net/context @@ -288,6 +292,6 @@ gopkg.in/ozeidan/fuzzy-patricia.v3/patricia # gopkg.in/warnings.v0 v0.1.2 ## explicit gopkg.in/warnings.v0 -# gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c +# gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ## explicit gopkg.in/yaml.v3 From ac687a5a2a52aa4aa60d03bd8bc42f611a2ac931 Mon Sep 17 00:00:00 2001 From: Moritz Haase Date: Tue, 22 Mar 2022 14:25:56 +0100 Subject: [PATCH 105/385] docs: Add section about code formatting to contributors guide Explain that gofumpt is used instead of gofmt and how to configure VSCode to use it. --- CONTRIBUTING.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a1a4a3ea7..0b9a6ee5d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,6 +50,21 @@ var _ MyInterface = &MyStruct{} This makes the intent clearer and means that if we fail to satisfy the interface we'll get an error in the file that needs fixing. +### Code Formatting + +To check code formatting [gofumpt](https://pkg.go.dev/mvdan.cc/gofumpt#section-readme) (which is a bit stricter than [gofmt](https://pkg.go.dev/cmd/gofmt)) is used. +VSCode will format the code correctly if you tell the Go extension to use `gofumpt` via your [`settings.json`](https://code.visualstudio.com/docs/getstarted/settings#_settingsjson) +by setting [`formatting.gofumpt`](https://github.com/golang/tools/blob/master/gopls/doc/settings.md#gofumpt-bool) to `true`: + +```jsonc +// .vscode/settings.json +{ + "gopls": { + "formatting.gofumpt": true + } +} +``` + ## Internationalisation Boy that's a hard word to spell. Anyway, lazygit is translated into several languages within the pkg/i18n package. If you need to render text to the user, you should add a new field to the TranslationSet struct in `pkg/i18n/english.go` and add the actual content within the `EnglishTranslationSet()` method in the same file. Although it is appreciated if you translate the text into other languages, it's not expected of you (google translate will likely do a bad job anyway!). From 8fb47fb7d6a0bda59652ded5cb5a3731421ad40d Mon Sep 17 00:00:00 2001 From: Moritz Haase Date: Mon, 21 Mar 2022 13:29:34 +0100 Subject: [PATCH 106/385] pkg/commands: Don't duplicate line breaks when retrieving commit message When using the "copy commit message to clipboard" action, the message will end up in the clipboard with duplicate line breaks. The same issue also affects the "Reword Commit" command. GetCommitMessage(), the function used to retrieve the commit message first splits the output returned by git into separate lines - without removing the line breaks. After removing the first line (which contains the commit SHA), it joins the lines of the message itself back together - adding a second set of line breaks along the way. Stop this from happening. Fixes #1808. --- pkg/commands/git_commands/commit.go | 2 +- pkg/commands/git_commands/commit_test.go | 46 ++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/pkg/commands/git_commands/commit.go b/pkg/commands/git_commands/commit.go index 38f50bdda..75256878f 100644 --- a/pkg/commands/git_commands/commit.go +++ b/pkg/commands/git_commands/commit.go @@ -70,7 +70,7 @@ func (self *CommitCommands) GetHeadCommitMessage() (string, error) { func (self *CommitCommands) GetCommitMessage(commitSha string) (string, error) { cmdStr := "git rev-list --format=%B --max-count=1 " + commitSha messageWithHeader, err := self.cmd.New(cmdStr).DontLog().RunWithOutput() - message := strings.Join(strings.SplitAfter(messageWithHeader, "\n")[1:], "\n") + message := strings.Join(strings.SplitAfter(messageWithHeader, "\n")[1:], "") return strings.TrimSpace(message), err } diff --git a/pkg/commands/git_commands/commit_test.go b/pkg/commands/git_commands/commit_test.go index 08ee7e5cc..96a46ecf4 100644 --- a/pkg/commands/git_commands/commit_test.go +++ b/pkg/commands/git_commands/commit_test.go @@ -161,3 +161,49 @@ func TestCommitShowCmdObj(t *testing.T) { }) } } + +func TestGetCommitMsg(t *testing.T) { + type scenario struct { + testName string + input string + expectedOutput string + } + scenarios := []scenario{ + { + "empty", + ` commit deadbeef`, + ``, + }, + { + "no line breaks (single line)", + `commit deadbeef +use generics to DRY up context code`, + `use generics to DRY up context code`, + }, + { + "with line breaks", + `commit deadbeef +Merge pull request #1750 from mark2185/fix-issue-template + +'git-rev parse' should be 'git rev-parse'`, + `Merge pull request #1750 from mark2185/fix-issue-template + +'git-rev parse' should be 'git rev-parse'`, + }, + } + + for _, s := range scenarios { + s := s + t.Run(s.testName, func(t *testing.T) { + instance := buildCommitCommands(commonDeps{ + runner: oscommands.NewFakeRunner(t).Expect("git rev-list --format=%B --max-count=1 deadbeef", s.input, nil), + }) + + output, err := instance.GetCommitMessage("deadbeef") + + assert.NoError(t, err) + + assert.Equal(t, s.expectedOutput, output) + }) + } +} From 5ded030a884b6358da34ddd5b855e0f2cb005d24 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Wed, 23 Mar 2022 18:38:28 +1100 Subject: [PATCH 107/385] diff colour for reflog commits --- pkg/gui/presentation/reflog_commits.go | 48 +++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/pkg/gui/presentation/reflog_commits.go b/pkg/gui/presentation/reflog_commits.go index fd843d884..5437af8b5 100644 --- a/pkg/gui/presentation/reflog_commits.go +++ b/pkg/gui/presentation/reflog_commits.go @@ -11,7 +11,7 @@ import ( func GetReflogCommitListDisplayStrings(commits []*models.Commit, fullDescription bool, cherryPickedCommitShaMap map[string]bool, diffName string, parseEmoji bool) [][]string { lines := make([][]string, len(commits)) - var displayFunc func(*models.Commit, map[string]bool, bool, bool) []string + var displayFunc func(*models.Commit, bool, bool, bool) []string if fullDescription { displayFunc = getFullDescriptionDisplayStringsForReflogCommit } else { @@ -20,47 +20,47 @@ func GetReflogCommitListDisplayStrings(commits []*models.Commit, fullDescription for i := range commits { diffed := commits[i].Sha == diffName - lines[i] = displayFunc(commits[i], cherryPickedCommitShaMap, diffed, parseEmoji) + cherryPicked := cherryPickedCommitShaMap[commits[i].Sha] + lines[i] = displayFunc(commits[i], cherryPicked, diffed, parseEmoji) } return lines } -func coloredReflogSha(c *models.Commit, cherryPickedCommitShaMap map[string]bool) string { +func reflogShaColor(cherryPicked, diffed bool) style.TextStyle { + if diffed { + return theme.DiffTerminalColor + } + shaColor := style.FgBlue - if cherryPickedCommitShaMap[c.Sha] { + if cherryPicked { shaColor = theme.CherryPickedCommitTextStyle } - return shaColor.Sprint(c.ShortSha()) + return shaColor } -func getFullDescriptionDisplayStringsForReflogCommit(c *models.Commit, cherryPickedCommitShaMap map[string]bool, diffed, parseEmoji bool) []string { - colorAttr := theme.DefaultTextColor - if diffed { - colorAttr = theme.DiffTerminalColor - } - +func getFullDescriptionDisplayStringsForReflogCommit(c *models.Commit, cherryPicked, diffed, parseEmoji bool) []string { name := c.Name if parseEmoji { name = emoji.Sprint(name) } return []string{ - coloredReflogSha(c, cherryPickedCommitShaMap), + reflogShaColor(cherryPicked, diffed).Sprint(c.ShortSha()), style.FgMagenta.Sprint(utils.UnixToDate(c.UnixTimestamp)), - colorAttr.Sprint(name), - } -} - -func getDisplayStringsForReflogCommit(c *models.Commit, cherryPickedCommitShaMap map[string]bool, diffed, parseEmoji bool) []string { - name := c.Name - if parseEmoji { - name = emoji.Sprint(name) - } - - return []string{ - coloredReflogSha(c, cherryPickedCommitShaMap), + theme.DefaultTextColor.Sprint(name), + } +} + +func getDisplayStringsForReflogCommit(c *models.Commit, cherryPicked, diffed, parseEmoji bool) []string { + name := c.Name + if parseEmoji { + name = emoji.Sprint(name) + } + + return []string{ + reflogShaColor(cherryPicked, diffed).Sprint(c.ShortSha()), theme.DefaultTextColor.Sprint(name), } } From cc5d13c833daaba4a27507ce33e5de90ed8b1567 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Wed, 23 Mar 2022 23:15:54 +1100 Subject: [PATCH 108/385] allow adding whole diff to patch this was causing a panic add integration test for toggling all commit files --- docs/keybindings/Keybindings_en.md | 1 + docs/keybindings/Keybindings_nl.md | 1 + docs/keybindings/Keybindings_pl.md | 1 + docs/keybindings/Keybindings_zh.md | 1 + .../controllers/commits_files_controller.go | 65 +++++++++++------- pkg/i18n/english.go | 4 ++ pkg/integration/integration.go | 3 +- .../expected/.git_keep/COMMIT_EDITMSG | 1 + .../expected/.git_keep/FETCH_HEAD | 0 .../expected/.git_keep/HEAD | 1 + .../expected/.git_keep/config | 10 +++ .../expected/.git_keep/description | 1 + .../expected/.git_keep/index | Bin 0 -> 163 bytes .../expected/.git_keep/info/exclude | 7 ++ .../expected/.git_keep/logs/HEAD | 2 + .../expected/.git_keep/logs/refs/heads/master | 2 + .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin 0 -> 21 bytes .../41/05b6da4ccc191a4abd24b1ffac6a2031534c0b | Bin 0 -> 45 bytes .../44/eb4bd0e7419049a8e4176945786c20dae60d7c | Bin 0 -> 126 bytes .../4b/825dc642cb6eb9a060e54bf8d69288fbee4904 | Bin 0 -> 15 bytes .../4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f | Bin 0 -> 21 bytes .../68/bbd52379d849022495dcfd11b13f2fb3103d37 | Bin 0 -> 46 bytes .../70/28eaec19b2723b62690974057c92ba7d8c1b11 | Bin 0 -> 121 bytes .../83/90c32b5e687b97e242da46498b574ace0e1eb5 | Bin 0 -> 21 bytes .../98/1651deb012f8e684dd306c1f5bf8edd5c3db67 | Bin 0 -> 106 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin 0 -> 21 bytes .../cf/149a94a18c990b2c5cdd0cf15ec4880f51c8b0 | 4 ++ .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin 0 -> 21 bytes .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin 0 -> 21 bytes .../expected/.git_keep/refs/heads/master | 1 + .../expected/one/two/three/file3 | 1 + .../patchBuildingToggleAll/recording.json | 1 + .../patchBuildingToggleAll/setup.sh | 23 +++++++ .../patchBuildingToggleAll/test.json | 1 + 34 files changed, 103 insertions(+), 28 deletions(-) create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/COMMIT_EDITMSG create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/FETCH_HEAD create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/HEAD create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/config create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/description create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/index create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/info/exclude create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/logs/HEAD create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/logs/refs/heads/master create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/objects/41/05b6da4ccc191a4abd24b1ffac6a2031534c0b create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/objects/44/eb4bd0e7419049a8e4176945786c20dae60d7c create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/objects/68/bbd52379d849022495dcfd11b13f2fb3103d37 create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/objects/70/28eaec19b2723b62690974057c92ba7d8c1b11 create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/objects/98/1651deb012f8e684dd306c1f5bf8edd5c3db67 create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/objects/cf/149a94a18c990b2c5cdd0cf15ec4880f51c8b0 create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b create mode 100644 test/integration/patchBuildingToggleAll/expected/.git_keep/refs/heads/master create mode 100644 test/integration/patchBuildingToggleAll/expected/one/two/three/file3 create mode 100644 test/integration/patchBuildingToggleAll/recording.json create mode 100644 test/integration/patchBuildingToggleAll/setup.sh create mode 100644 test/integration/patchBuildingToggleAll/test.json diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index acac130a4..662631386 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -123,6 +123,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct o: open file e: edit file space: toggle file included in patch + a: toggle all files included in patch enter: enter file to add selected聽lines to the patch (or toggle directory collapsed) `: toggle file tree view 90UFB0$V`Kbu$kOxd$H z{HGKSsS9}dYwS8A%^;kgm#SY 6UGC(>&Oarc?3yyPmeeUHbdQ!3BfN08|tA<%=0J-ZfZ~y=R literal 0 HcmV?d00001 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/info/exclude b/test/integration/patchBuildingToggleAll/expected/.git_keep/info/exclude new file mode 100644 index 000000000..8e9f2071f --- /dev/null +++ b/test/integration/patchBuildingToggleAll/expected/.git_keep/info/exclude @@ -0,0 +1,7 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ +.DS_Store diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/logs/HEAD b/test/integration/patchBuildingToggleAll/expected/.git_keep/logs/HEAD new file mode 100644 index 000000000..30dd712e1 --- /dev/null +++ b/test/integration/patchBuildingToggleAll/expected/.git_keep/logs/HEAD @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 7028eaec19b2723b62690974057c92ba7d8c1b11 CI 1648038005 +1100 commit (initial): first commit +7028eaec19b2723b62690974057c92ba7d8c1b11 cf149a94a18c990b2c5cdd0cf15ec4880f51c8b0 CI 1648038005 +1100 commit: blah diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/logs/refs/heads/master b/test/integration/patchBuildingToggleAll/expected/.git_keep/logs/refs/heads/master new file mode 100644 index 000000000..30dd712e1 --- /dev/null +++ b/test/integration/patchBuildingToggleAll/expected/.git_keep/logs/refs/heads/master @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 7028eaec19b2723b62690974057c92ba7d8c1b11 CI 1648038005 +1100 commit (initial): first commit +7028eaec19b2723b62690974057c92ba7d8c1b11 cf149a94a18c990b2c5cdd0cf15ec4880f51c8b0 CI 1648038005 +1100 commit: blah diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 new file mode 100644 index 0000000000000000000000000000000000000000..f74bf2335bbc5999ad0faff94fb04165d8ab5c7d GIT binary patch literal 21 ccmb ~ZE#08nZNMgRZ+ literal 0 HcmV?d00001 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/41/05b6da4ccc191a4abd24b1ffac6a2031534c0b b/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/41/05b6da4ccc191a4abd24b1ffac6a2031534c0b new file mode 100644 index 0000000000000000000000000000000000000000..a35700d0e194beeac2dbf4a54a84aa39ea6a1bc3 GIT binary patch literal 45 zcmb 7HexU|FfcPQQAo?oNi}3xy65p<)zlkbB0{5h@|`XOc(rt2 zMN(kIAi?v)s6lDpxtFUJg;({rywaX;p^l`$nBjglulAX;XK(mVDI8K4@bcH#bwnCT gfeFJUlcNv9{}~-CdzJp;w8fXC*jukd0F1skmKlsaH2?qr literal 0 HcmV?d00001 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 b/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 new file mode 100644 index 0000000000000000000000000000000000000000..adf64119a33d7621aeeaa505d30adb58afaa5559 GIT binary patch literal 15 Wcmb {;fo08o?%QUCw| literal 0 HcmV?d00001 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/68/bbd52379d849022495dcfd11b13f2fb3103d37 b/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/68/bbd52379d849022495dcfd11b13f2fb3103d37 new file mode 100644 index 0000000000000000000000000000000000000000..15e2a131e84692e3d53bfa3c48d999c254444784 GIT binary patch literal 46 zcmb HR*A?9DejUHPx;=k6GsE9o0-*qn C^b>mk literal 0 HcmV?d00001 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/70/28eaec19b2723b62690974057c92ba7d8c1b11 b/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/70/28eaec19b2723b62690974057c92ba7d8c1b11 new file mode 100644 index 0000000000000000000000000000000000000000..a3f20d2e948191e2afb72611db44508657965d60 GIT binary patch literal 121 zcmV-<0EYi~0ga783c@fD06pgwdlzIAH(>)JLQj20l5VhIh{P58{1*Ix*I|Y!y|q=r zdVA6#0+iYLr37*%2gxyEK=G6-FCjYSnnfrgne^3XA27{uo92gXsl8uvDZSmn24cK2 bqKC7!h~}WjMCDK2)OCCmewEn)8D1{oTiiGJ literal 0 HcmV?d00001 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 b/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 new file mode 100644 index 0000000000000000000000000000000000000000..be495f3991a70f570da18905f0d6f17de4d85e73 GIT binary patch literal 21 ccmb #rs)x-b@6iPCH1~Rz3_P+4kaf0WHC*ql|6*&sG Mp7GWI01x&lI9Dz+CjbBd literal 0 HcmV?d00001 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 new file mode 100644 index 0000000000000000000000000000000000000000..285df3e5fbab12262e28d85e78af8a31cd0024c1 GIT binary patch literal 21 ccmb `~^A08nuUMF0Q* literal 0 HcmV?d00001 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/cf/149a94a18c990b2c5cdd0cf15ec4880f51c8b0 b/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/cf/149a94a18c990b2c5cdd0cf15ec4880f51c8b0 new file mode 100644 index 000000000..5d9dcc080 --- /dev/null +++ b/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/cf/149a94a18c990b2c5cdd0cf15ec4880f51c8b0 @@ -0,0 +1,4 @@ +x嵨M +翤@a譻娰捥AD瑾荋覕 +[9傐欠x沧鷍即S勅i "=R 瀅`\扗 }lpN08nuUO8@`> literal 0 HcmV?d00001 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b new file mode 100644 index 0000000000000000000000000000000000000000..9b771fc2f6f41f91b00976b4ff3f8f9935f7931e GIT binary patch literal 21 ccmb >`CU&08otwO#lD@ literal 0 HcmV?d00001 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/refs/heads/master b/test/integration/patchBuildingToggleAll/expected/.git_keep/refs/heads/master new file mode 100644 index 000000000..6e12466a8 --- /dev/null +++ b/test/integration/patchBuildingToggleAll/expected/.git_keep/refs/heads/master @@ -0,0 +1 @@ +cf149a94a18c990b2c5cdd0cf15ec4880f51c8b0 diff --git a/test/integration/patchBuildingToggleAll/expected/one/two/three/file3 b/test/integration/patchBuildingToggleAll/expected/one/two/three/file3 new file mode 100644 index 000000000..df6b0d2bc --- /dev/null +++ b/test/integration/patchBuildingToggleAll/expected/one/two/three/file3 @@ -0,0 +1 @@ +test3 diff --git a/test/integration/patchBuildingToggleAll/recording.json b/test/integration/patchBuildingToggleAll/recording.json new file mode 100644 index 000000000..52feb4966 --- /dev/null +++ b/test/integration/patchBuildingToggleAll/recording.json @@ -0,0 +1 @@ +{"KeyEvents":[{"Timestamp":624,"Mod":0,"Key":259,"Ch":0},{"Timestamp":813,"Mod":0,"Key":259,"Ch":0},{"Timestamp":1216,"Mod":0,"Key":13,"Ch":13},{"Timestamp":1841,"Mod":0,"Key":256,"Ch":97},{"Timestamp":2456,"Mod":0,"Key":258,"Ch":0},{"Timestamp":2624,"Mod":0,"Key":258,"Ch":0},{"Timestamp":2841,"Mod":0,"Key":256,"Ch":32},{"Timestamp":3600,"Mod":2,"Key":16,"Ch":16},{"Timestamp":4795,"Mod":0,"Key":258,"Ch":0},{"Timestamp":5193,"Mod":0,"Key":258,"Ch":0},{"Timestamp":5696,"Mod":0,"Key":13,"Ch":13},{"Timestamp":7345,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":272,"Height":74}]} \ No newline at end of file diff --git a/test/integration/patchBuildingToggleAll/setup.sh b/test/integration/patchBuildingToggleAll/setup.sh new file mode 100644 index 000000000..c552b9e56 --- /dev/null +++ b/test/integration/patchBuildingToggleAll/setup.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +set -e + +cd $1 + +git init + +git config user.email "CI@example.com" +git config user.name "CI" + +git commit --allow-empty -m "first commit" + +mkdir -p one/two/three +echo test1 > one/two/three/file1 +echo test2 > one/two/three/file2 +echo test3 > one/two/three/file3 +echo test4 > one/two/three/file4 +echo test5 > one/two/file1 +echo test6 > one/two/file2 + +git add . +git commit -m "blah" diff --git a/test/integration/patchBuildingToggleAll/test.json b/test/integration/patchBuildingToggleAll/test.json new file mode 100644 index 000000000..1804ea8aa --- /dev/null +++ b/test/integration/patchBuildingToggleAll/test.json @@ -0,0 +1 @@ +{ "description": "messing with our patch building flow in both flat and tree view", "speed": 10 } From 12ecd665c8f69e45e00629b05c2b3af72f3e3b51 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Wed, 23 Mar 2022 23:37:15 +1100 Subject: [PATCH 109/385] safe reword --- .../controllers/local_commits_controller.go | 28 +++++++++++-------- pkg/i18n/english.go | 5 ++++ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index d45e3ed56..45c65e7ee 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -267,18 +267,24 @@ func (self *LocalCommitsController) rewordEditor(commit *models.Commit) error { return nil } - self.c.LogAction(self.c.Tr.Actions.RewordCommit) - subProcess, err := self.git.Rebase.RewordCommitInEditor( - self.model.Commits, self.context().GetSelectedLineIdx(), - ) - if err != nil { - return self.c.Error(err) - } - if subProcess != nil { - return self.c.RunSubprocessAndRefresh(subProcess) - } + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.RewordInEditorTitle, + Prompt: self.c.Tr.RewordInEditorPrompt, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.RewordCommit) + subProcess, err := self.git.Rebase.RewordCommitInEditor( + self.model.Commits, self.context().GetSelectedLineIdx(), + ) + if err != nil { + return self.c.Error(err) + } + if subProcess != nil { + return self.c.RunSubprocessAndRefresh(subProcess) + } - return nil + return nil + }, + }) } func (self *LocalCommitsController) drop(commit *models.Commit) error { diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index db25cf0a6..c7965e6a9 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -454,6 +454,8 @@ type TranslationSet struct { LcOpenCommitInBrowser string LcViewBisectOptions string ConfirmRevertCommit string + RewordInEditorTitle string + RewordInEditorPrompt string Actions Actions Bisect Bisect } @@ -1027,6 +1029,9 @@ func EnglishTranslationSet() TranslationSet { LcOpenCommitInBrowser: "open commit in browser", LcViewBisectOptions: "view bisect options", ConfirmRevertCommit: "Are you sure you want to revert {{.selectedCommit}}?", + RewordInEditorTitle: "Reword in editor", + RewordInEditorPrompt: "Are you sure you want to reword this commit in your editor?", + Actions: Actions{ // TODO: combine this with the original keybinding descriptions (those are all in lowercase atm) CheckoutCommit: "Checkout commit", From f113ff21bff22bc9e3dc683a4f52822233b76b95 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Thu, 24 Mar 2022 09:25:51 +1100 Subject: [PATCH 110/385] add confirmation before performing undo or redo action --- pkg/gui/controllers/undo_controller.go | 60 +++++++++++++++++++------- pkg/i18n/english.go | 5 ++- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/pkg/gui/controllers/undo_controller.go b/pkg/gui/controllers/undo_controller.go index bfd6dc444..ba54f4201 100644 --- a/pkg/gui/controllers/undo_controller.go +++ b/pkg/gui/controllers/undo_controller.go @@ -1,6 +1,8 @@ package controllers import ( + "fmt" + "github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -83,17 +85,30 @@ func (self *UndoController) reflogUndo() error { switch action.kind { case COMMIT, REBASE: - self.c.LogAction(self.c.Tr.Actions.Undo) - return true, self.hardResetWithAutoStash(action.from, hardResetOptions{ - EnvVars: undoEnvVars, - WaitingStatus: undoingStatus, + return true, self.c.Ask(types.AskOpts{ + Title: self.c.Tr.Actions.Undo, + Prompt: fmt.Sprintf(self.c.Tr.HardResetAutostashPrompt, action.from), + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.Undo) + return self.hardResetWithAutoStash(action.from, hardResetOptions{ + EnvVars: undoEnvVars, + WaitingStatus: undoingStatus, + }) + }, }) case CHECKOUT: - self.c.LogAction(self.c.Tr.Actions.Undo) - return true, self.helpers.Refs.CheckoutRef(action.from, types.CheckoutRefOptions{ - EnvVars: undoEnvVars, - WaitingStatus: undoingStatus, + return true, self.c.Ask(types.AskOpts{ + Title: self.c.Tr.Actions.Undo, + Prompt: fmt.Sprintf(self.c.Tr.CheckoutPrompt, action.from), + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.Undo) + return self.helpers.Refs.CheckoutRef(action.from, types.CheckoutRefOptions{ + EnvVars: undoEnvVars, + WaitingStatus: undoingStatus, + }) + }, }) + case CURRENT_REBASE: // do nothing } @@ -121,16 +136,29 @@ func (self *UndoController) reflogRedo() error { switch action.kind { case COMMIT, REBASE: - self.c.LogAction(self.c.Tr.Actions.Redo) - return true, self.hardResetWithAutoStash(action.to, hardResetOptions{ - EnvVars: redoEnvVars, - WaitingStatus: redoingStatus, + return true, self.c.Ask(types.AskOpts{ + Title: self.c.Tr.Actions.Redo, + Prompt: fmt.Sprintf(self.c.Tr.HardResetAutostashPrompt, action.to), + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.Redo) + return self.hardResetWithAutoStash(action.to, hardResetOptions{ + EnvVars: redoEnvVars, + WaitingStatus: redoingStatus, + }) + }, }) + case CHECKOUT: - self.c.LogAction(self.c.Tr.Actions.Redo) - return true, self.helpers.Refs.CheckoutRef(action.to, types.CheckoutRefOptions{ - EnvVars: redoEnvVars, - WaitingStatus: redoingStatus, + return true, self.c.Ask(types.AskOpts{ + Title: self.c.Tr.Actions.Redo, + Prompt: fmt.Sprintf(self.c.Tr.CheckoutPrompt, action.to), + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.Redo) + return self.helpers.Refs.CheckoutRef(action.to, types.CheckoutRefOptions{ + EnvVars: redoEnvVars, + WaitingStatus: redoingStatus, + }) + }, }) case CURRENT_REBASE: // do nothing diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index c7965e6a9..e72fe7d06 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -456,6 +456,8 @@ type TranslationSet struct { ConfirmRevertCommit string RewordInEditorTitle string RewordInEditorPrompt string + CheckoutPrompt string + HardResetAutostashPrompt string Actions Actions Bisect Bisect } @@ -1031,7 +1033,8 @@ func EnglishTranslationSet() TranslationSet { ConfirmRevertCommit: "Are you sure you want to revert {{.selectedCommit}}?", RewordInEditorTitle: "Reword in editor", RewordInEditorPrompt: "Are you sure you want to reword this commit in your editor?", - + HardResetAutostashPrompt: "Are you sure you want to hard reset to '%s'? An auto-stash will be performed if necessary.", + CheckoutPrompt: "Are you sure you want to checkout '%s'?", Actions: Actions{ // TODO: combine this with the original keybinding descriptions (those are all in lowercase atm) CheckoutCommit: "Checkout commit", From 13a9bbb984601d19f1aabe7abfbf58fbe91cf621 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Thu, 24 Mar 2022 09:35:08 +1100 Subject: [PATCH 111/385] skip flakey bisect test --- test/integration/bisect/test.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/integration/bisect/test.json b/test/integration/bisect/test.json index 2bf2b418b..58263936d 100644 --- a/test/integration/bisect/test.json +++ b/test/integration/bisect/test.json @@ -1,4 +1,5 @@ { "description": "Basic git bisect usage", - "speed": 5 + "speed": 5, + "skip": true } From dde30fa104347ab9c01f82b7886864b473e6f51c Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Thu, 24 Mar 2022 17:49:25 +1100 Subject: [PATCH 112/385] add gone branches status --- pkg/commands/loaders/branches.go | 78 +++++++++++++++------------ pkg/commands/loaders/branches_test.go | 52 ++++++++++++++++++ pkg/commands/models/branch.go | 11 ++-- pkg/gui/list_context_config.go | 2 +- pkg/gui/presentation/branches.go | 24 +++++---- pkg/gui/refresh.go | 2 +- pkg/gui/status_panel.go | 2 +- pkg/i18n/english.go | 2 + 8 files changed, 121 insertions(+), 52 deletions(-) create mode 100644 pkg/commands/loaders/branches_test.go diff --git a/pkg/commands/loaders/branches.go b/pkg/commands/loaders/branches.go index c54e65ee9..1f78908a8 100644 --- a/pkg/commands/loaders/branches.go +++ b/pkg/commands/loaders/branches.go @@ -106,6 +106,49 @@ outer: return branches, nil } +// Obtain branch information from parsed line output of getRawBranches() +// split contains the '|' separated tokens in the line of output +func obtainBranch(split []string) *models.Branch { + name := strings.TrimPrefix(split[1], "heads/") + branch := &models.Branch{ + Name: name, + Pullables: "?", + Pushables: "?", + Head: split[0] == "*", + } + + upstreamName := split[2] + if upstreamName == "" { + // if we're here then it means we do not have a local version of the remote. + // The branch might still be tracking a remote though, we just don't know + // how many commits ahead/behind it is + return branch + } + + track := split[3] + if track == "[gone]" { + branch.UpstreamGone = true + } else { + re := regexp.MustCompile(`ahead (\d+)`) + match := re.FindStringSubmatch(track) + if len(match) > 1 { + branch.Pushables = match[1] + } else { + branch.Pushables = "0" + } + + re = regexp.MustCompile(`behind (\d+)`) + match = re.FindStringSubmatch(track) + if len(match) > 1 { + branch.Pullables = match[1] + } else { + branch.Pullables = "0" + } + } + + return branch +} + func (self *BranchLoader) obtainBranches() []*models.Branch { output, err := self.getRawBranches() if err != nil { @@ -128,40 +171,7 @@ func (self *BranchLoader) obtainBranches() []*models.Branch { continue } - name := strings.TrimPrefix(split[1], "heads/") - branch := &models.Branch{ - Name: name, - Pullables: "?", - Pushables: "?", - Head: split[0] == "*", - } - - upstreamName := split[2] - if upstreamName == "" { - // if we're here then it means we do not have a local version of the remote. - // The branch might still be tracking a remote though, we just don't know - // how many commits ahead/behind it is - branches = append(branches, branch) - continue - } - - track := split[3] - re := regexp.MustCompile(`ahead (\d+)`) - match := re.FindStringSubmatch(track) - if len(match) > 1 { - branch.Pushables = match[1] - } else { - branch.Pushables = "0" - } - - re = regexp.MustCompile(`behind (\d+)`) - match = re.FindStringSubmatch(track) - if len(match) > 1 { - branch.Pullables = match[1] - } else { - branch.Pullables = "0" - } - + branch := obtainBranch(split) branches = append(branches, branch) } diff --git a/pkg/commands/loaders/branches_test.go b/pkg/commands/loaders/branches_test.go new file mode 100644 index 000000000..70f02dcf7 --- /dev/null +++ b/pkg/commands/loaders/branches_test.go @@ -0,0 +1,52 @@ +package loaders + +// "*|feat/detect-purge|origin/feat/detect-purge|[ahead 1]" +import ( + "testing" + + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/stretchr/testify/assert" +) + +func TestObtainBanch(t *testing.T) { + type scenario struct { + testName string + input []string + expectedBranch *models.Branch + } + + scenarios := []scenario{ + { + testName: "TrimHeads", + input: []string{"", "heads/a_branch", "", ""}, + expectedBranch: &models.Branch{Name: "a_branch", Pushables: "?", Pullables: "?", Head: false}, + }, + { + testName: "NoUpstream", + input: []string{"", "a_branch", "", ""}, + expectedBranch: &models.Branch{Name: "a_branch", Pushables: "?", Pullables: "?", Head: false}, + }, + { + testName: "IsHead", + input: []string{"*", "a_branch", "", ""}, + expectedBranch: &models.Branch{Name: "a_branch", Pushables: "?", Pullables: "?", Head: true}, + }, + { + testName: "IsBehindAndAhead", + input: []string{"", "a_branch", "a_remote/a_branch", "[behind 2, ahead 3]"}, + expectedBranch: &models.Branch{Name: "a_branch", Pushables: "3", Pullables: "2", Head: false}, + }, + { + testName: "RemoteBranchIsGone", + input: []string{"", "a_branch", "a_remote/a_branch", "[gone]"}, + expectedBranch: &models.Branch{Name: "a_branch", UpstreamGone: true, Pushables: "?", Pullables: "?", Head: false}, + }, + } + + for _, s := range scenarios { + t.Run(s.testName, func(t *testing.T) { + branch := obtainBranch(s.input) + assert.EqualValues(t, s.expectedBranch, branch) + }) + } +} diff --git a/pkg/commands/models/branch.go b/pkg/commands/models/branch.go index 3cdf5ad6d..dae934fdf 100644 --- a/pkg/commands/models/branch.go +++ b/pkg/commands/models/branch.go @@ -5,11 +5,12 @@ package models type Branch struct { Name string // the displayname is something like '(HEAD detached at 123asdf)', whereas in that case the name would be '123asdf' - DisplayName string - Recency string - Pushables string - Pullables string - Head bool + DisplayName string + Recency string + Pushables string + Pullables string + UpstreamGone bool + Head bool // if we have a named remote locally this will be the name of that remote e.g. // 'origin' or 'tiwood'. If we don't have the remote locally it'll look like // 'git@github.com:tiwood/lazygit.git' diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index 89e1461b8..010a2f0b1 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -47,7 +47,7 @@ func (gui *Gui) branchesListContext() *context.BranchesContext { func() []*models.Branch { return gui.State.Model.Branches }, gui.Views.Branches, func(startIdx int, length int) [][]string { - return presentation.GetBranchListDisplayStrings(gui.State.Model.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref) + return presentation.GetBranchListDisplayStrings(gui.State.Model.Branches, gui.State.ScreenMode != SCREEN_NORMAL, gui.State.Modes.Diffing.Ref, gui.Tr) }, nil, OnFocusWrapper(gui.withDiffModeCheck(gui.branchesRenderToMain)), diff --git a/pkg/gui/presentation/branches.go b/pkg/gui/presentation/branches.go index e31c823ce..9062eface 100644 --- a/pkg/gui/presentation/branches.go +++ b/pkg/gui/presentation/branches.go @@ -6,25 +6,26 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/style" + "github.com/jesseduffield/lazygit/pkg/i18n" "github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/utils" ) var branchPrefixColorCache = make(map[string]style.TextStyle) -func GetBranchListDisplayStrings(branches []*models.Branch, fullDescription bool, diffName string) [][]string { +func GetBranchListDisplayStrings(branches []*models.Branch, fullDescription bool, diffName string, tr *i18n.TranslationSet) [][]string { lines := make([][]string, len(branches)) for i := range branches { diffed := branches[i].Name == diffName - lines[i] = getBranchDisplayStrings(branches[i], fullDescription, diffed) + lines[i] = getBranchDisplayStrings(branches[i], fullDescription, diffed, tr) } return lines } // getBranchDisplayStrings returns the display string of branch -func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool) []string { +func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool, tr *i18n.TranslationSet) []string { displayName := b.Name if b.DisplayName != "" { displayName = b.DisplayName @@ -36,7 +37,7 @@ func getBranchDisplayStrings(b *models.Branch, fullDescription bool, diffed bool } coloredName := nameTextStyle.Sprint(displayName) if b.IsTrackingRemote() { - coloredName = fmt.Sprintf("%s %s", coloredName, ColoredBranchStatus(b)) + coloredName = fmt.Sprintf("%s %s", coloredName, ColoredBranchStatus(b, tr)) } recencyColor := style.FgCyan @@ -77,18 +78,21 @@ func GetBranchTextStyle(name string) style.TextStyle { } } -func ColoredBranchStatus(branch *models.Branch) string { +func ColoredBranchStatus(branch *models.Branch, tr *i18n.TranslationSet) string { colour := style.FgYellow - if branch.MatchesUpstream() { - colour = style.FgGreen - } else if !branch.IsTrackingRemote() { + if !branch.IsTrackingRemote() || branch.UpstreamGone { colour = style.FgRed + } else if branch.MatchesUpstream() { + colour = style.FgGreen } - return colour.Sprint(BranchStatus(branch)) + return colour.Sprint(BranchStatus(branch, tr)) } -func BranchStatus(branch *models.Branch) string { +func BranchStatus(branch *models.Branch, tr *i18n.TranslationSet) string { + if branch.UpstreamGone { + return tr.UpstreamGone + } return fmt.Sprintf("鈫%s鈫%s", branch.Pushables, branch.Pullables) } diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go index d9d661cff..2a47efc7a 100644 --- a/pkg/gui/refresh.go +++ b/pkg/gui/refresh.go @@ -534,7 +534,7 @@ func (gui *Gui) refreshStatus() { status := "" if currentBranch.IsRealBranch() { - status += presentation.ColoredBranchStatus(currentBranch) + " " + status += presentation.ColoredBranchStatus(currentBranch, gui.Tr) + " " } workingTreeState := gui.git.Status.WorkingTreeState() diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go index 072f41da9..6ca6e6996 100644 --- a/pkg/gui/status_panel.go +++ b/pkg/gui/status_panel.go @@ -41,7 +41,7 @@ func (gui *Gui) handleStatusClick() error { } cx, _ := gui.Views.Status.Cursor() - upstreamStatus := presentation.BranchStatus(currentBranch) + upstreamStatus := presentation.BranchStatus(currentBranch, gui.Tr) repoName := utils.GetCurrentRepoName() workingTreeState := gui.git.Status.WorkingTreeState() switch workingTreeState { diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index e72fe7d06..4724abcab 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -458,6 +458,7 @@ type TranslationSet struct { RewordInEditorPrompt string CheckoutPrompt string HardResetAutostashPrompt string + UpstreamGone string Actions Actions Bisect Bisect } @@ -1035,6 +1036,7 @@ func EnglishTranslationSet() TranslationSet { RewordInEditorPrompt: "Are you sure you want to reword this commit in your editor?", HardResetAutostashPrompt: "Are you sure you want to hard reset to '%s'? An auto-stash will be performed if necessary.", CheckoutPrompt: "Are you sure you want to checkout '%s'?", + UpstreamGone: "鈫慻one", Actions: Actions{ // TODO: combine this with the original keybinding descriptions (those are all in lowercase atm) CheckoutCommit: "Checkout commit", From c7a629c4401ae0d4aad06767c88ce1e9e418dbf3 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 19 Mar 2022 12:26:30 +1100 Subject: [PATCH 113/385] make more use of generics --- go.mod | 2 + go.sum | 5 + pkg/commands/git_commands/rebase_test.go | 4 +- pkg/commands/loaders/branches.go | 7 +- pkg/commands/loaders/files.go | 10 +- pkg/commands/patch/hunk.go | 3 +- pkg/commands/patch/patch_manager.go | 6 +- pkg/commands/patch/patch_parser.go | 3 +- pkg/gui/controllers/global_controller.go | 8 +- .../controllers/helpers/cherry_pick_helper.go | 34 +- pkg/gui/filetree/collapsed_paths.go | 32 +- pkg/gui/filetree/commit_file_node.go | 8 +- pkg/gui/filetree/commit_file_tree.go | 6 +- pkg/gui/filetree/file_node.go | 8 +- pkg/gui/filetree/file_tree.go | 8 +- pkg/gui/filetree/inode.go | 18 +- pkg/gui/list_context_config.go | 6 +- pkg/gui/options_menu_panel.go | 18 +- pkg/gui/patch_building_panel.go | 6 +- pkg/gui/presentation/commits.go | 13 +- pkg/gui/presentation/commits_test.go | 5 +- pkg/gui/presentation/files.go | 2 +- pkg/gui/presentation/reflog_commits.go | 5 +- pkg/gui/refresh.go | 27 +- pkg/utils/slice.go | 83 -- pkg/utils/slice_test.go | 76 -- .../github.com/jesseduffield/generics/LICENSE | 21 + .../generics/hashmap/functions.go | 35 + .../generics/list/comparable_list.go | 49 + .../jesseduffield/generics/list/functions.go | 72 ++ .../jesseduffield/generics/list/list.go | 117 +++ .../jesseduffield/generics/set/set.go | 49 + vendor/github.com/samber/lo/.gitignore | 36 + vendor/github.com/samber/lo/CHANGELOG.md | 71 ++ vendor/github.com/samber/lo/Dockerfile | 8 + vendor/github.com/samber/lo/LICENSE | 21 + vendor/github.com/samber/lo/Makefile | 51 + vendor/github.com/samber/lo/README.md | 981 ++++++++++++++++++ vendor/github.com/samber/lo/condition.go | 99 ++ vendor/github.com/samber/lo/constraints.go | 6 + .../github.com/samber/lo/docker-compose.yml | 9 + vendor/github.com/samber/lo/drop.go | 65 ++ vendor/github.com/samber/lo/find.go | 157 +++ vendor/github.com/samber/lo/intersect.go | 131 +++ vendor/github.com/samber/lo/map.go | 72 ++ vendor/github.com/samber/lo/pointers.go | 19 + vendor/github.com/samber/lo/retry.go | 19 + vendor/github.com/samber/lo/slice.go | 242 +++++ vendor/github.com/samber/lo/tuples.go | 413 ++++++++ vendor/github.com/samber/lo/types.go | 83 ++ vendor/github.com/samber/lo/util.go | 50 + vendor/modules.txt | 8 + 52 files changed, 3013 insertions(+), 274 deletions(-) create mode 100644 vendor/github.com/jesseduffield/generics/LICENSE create mode 100644 vendor/github.com/jesseduffield/generics/hashmap/functions.go create mode 100644 vendor/github.com/jesseduffield/generics/list/comparable_list.go create mode 100644 vendor/github.com/jesseduffield/generics/list/functions.go create mode 100644 vendor/github.com/jesseduffield/generics/list/list.go create mode 100644 vendor/github.com/jesseduffield/generics/set/set.go create mode 100644 vendor/github.com/samber/lo/.gitignore create mode 100644 vendor/github.com/samber/lo/CHANGELOG.md create mode 100644 vendor/github.com/samber/lo/Dockerfile create mode 100644 vendor/github.com/samber/lo/LICENSE create mode 100644 vendor/github.com/samber/lo/Makefile create mode 100644 vendor/github.com/samber/lo/README.md create mode 100644 vendor/github.com/samber/lo/condition.go create mode 100644 vendor/github.com/samber/lo/constraints.go create mode 100644 vendor/github.com/samber/lo/docker-compose.yml create mode 100644 vendor/github.com/samber/lo/drop.go create mode 100644 vendor/github.com/samber/lo/find.go create mode 100644 vendor/github.com/samber/lo/intersect.go create mode 100644 vendor/github.com/samber/lo/map.go create mode 100644 vendor/github.com/samber/lo/pointers.go create mode 100644 vendor/github.com/samber/lo/retry.go create mode 100644 vendor/github.com/samber/lo/slice.go create mode 100644 vendor/github.com/samber/lo/tuples.go create mode 100644 vendor/github.com/samber/lo/types.go create mode 100644 vendor/github.com/samber/lo/util.go diff --git a/go.mod b/go.mod index 3e7598384..afdf377ed 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/gookit/color v1.4.2 github.com/imdario/mergo v0.3.11 github.com/integrii/flaggy v1.4.0 + github.com/jesseduffield/generics v0.0.0-20220318214805-3397e5e19e9f github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e @@ -25,6 +26,7 @@ require ( github.com/mgutz/str v1.2.0 github.com/pmezard/go-difflib v1.0.0 github.com/sahilm/fuzzy v0.1.0 + github.com/samber/lo v1.10.1 github.com/sanity-io/litter v1.5.2 github.com/sirupsen/logrus v1.4.2 github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad diff --git a/go.sum b/go.sum index fc2d2400d..c06b0aef1 100644 --- a/go.sum +++ b/go.sum @@ -66,6 +66,8 @@ github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jesseduffield/generics v0.0.0-20220318214805-3397e5e19e9f h1:9USuZttmg5ioHsjFyXboiGSbncpAqcKkq9qb4ga5PD0= +github.com/jesseduffield/generics v0.0.0-20220318214805-3397e5e19e9f/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 h1:9N08i5kjvOfkzMj6THmIM110wPTQLdVYEOHMHT2DFiI= @@ -129,6 +131,8 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= +github.com/samber/lo v1.10.1 h1:0D3h7i0U3hRAbaCeQ82DLe67n0A7Bbl0/cEoWqFGp+U= +github.com/samber/lo v1.10.1/go.mod h1:2I7tgIv8Q1SG2xEIkRq0F2i2zgxVpnyPOP0d3Gj2r+A= github.com/sanity-io/litter v1.5.2 h1:AnC8s9BMORWH5a4atZ4D6FPVvKGzHcnc5/IVTa87myw= github.com/sanity-io/litter v1.5.2/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= @@ -146,6 +150,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= github.com/urfave/cli v1.20.1-0.20180226030253-8e01ec4cd3e2/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= diff --git a/pkg/commands/git_commands/rebase_test.go b/pkg/commands/git_commands/rebase_test.go index 56df77a86..4e7b5c2c6 100644 --- a/pkg/commands/git_commands/rebase_test.go +++ b/pkg/commands/git_commands/rebase_test.go @@ -8,7 +8,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/git_config" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" - "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" "github.com/stretchr/testify/assert" ) @@ -64,7 +64,7 @@ func TestRebaseSkipEditorCommand(t *testing.T) { "^LAZYGIT_CLIENT_COMMAND=EXIT_IMMEDIATELY$", } { regexStr := regexStr - foundMatch := utils.IncludesStringFunc(envVars, func(envVar string) bool { + foundMatch := lo.ContainsBy(envVars, func(envVar string) bool { return regexp.MustCompile(regexStr).MatchString(envVar) }) if !foundMatch { diff --git a/pkg/commands/loaders/branches.go b/pkg/commands/loaders/branches.go index 1f78908a8..9fa1e80f4 100644 --- a/pkg/commands/loaders/branches.go +++ b/pkg/commands/loaders/branches.go @@ -4,6 +4,7 @@ import ( "regexp" "strings" + "github.com/jesseduffield/generics/set" "github.com/jesseduffield/go-git/v5/config" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/common" @@ -181,15 +182,15 @@ func (self *BranchLoader) obtainBranches() []*models.Branch { // TODO: only look at the new reflog commits, and otherwise store the recencies in // int form against the branch to recalculate the time ago func (self *BranchLoader) obtainReflogBranches(reflogCommits []*models.Commit) []*models.Branch { - foundBranchesMap := map[string]bool{} + foundBranches := set.New[string]() re := regexp.MustCompile(`checkout: moving from ([\S]+) to ([\S]+)`) reflogBranches := make([]*models.Branch, 0, len(reflogCommits)) for _, commit := range reflogCommits { if match := re.FindStringSubmatch(commit.Name); len(match) == 3 { recency := utils.UnixToTimeAgo(commit.UnixTimestamp) for _, branchName := range match[1:] { - if !foundBranchesMap[branchName] { - foundBranchesMap[branchName] = true + if !foundBranches.Includes(branchName) { + foundBranches.Add(branchName) reflogBranches = append(reflogBranches, &models.Branch{ Recency: recency, Name: branchName, diff --git a/pkg/commands/loaders/files.go b/pkg/commands/loaders/files.go index f5becdb92..8ab727453 100644 --- a/pkg/commands/loaders/files.go +++ b/pkg/commands/loaders/files.go @@ -7,7 +7,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/common" - "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" ) type FileLoaderConfig interface { @@ -57,10 +57,10 @@ func (self *FileLoader) GetStatusFiles(opts GetStatusFileOptions) []*models.File change := status.Change stagedChange := change[0:1] unstagedChange := change[1:2] - untracked := utils.IncludesString([]string{"??", "A ", "AM"}, change) - hasNoStagedChanges := utils.IncludesString([]string{" ", "U", "?"}, stagedChange) - hasInlineMergeConflicts := utils.IncludesString([]string{"UU", "AA"}, change) - hasMergeConflicts := hasInlineMergeConflicts || utils.IncludesString([]string{"DD", "AU", "UA", "UD", "DU"}, change) + untracked := lo.Contains([]string{"??", "A ", "AM"}, change) + hasNoStagedChanges := lo.Contains([]string{" ", "U", "?"}, stagedChange) + hasInlineMergeConflicts := lo.Contains([]string{"UU", "AA"}, change) + hasMergeConflicts := hasInlineMergeConflicts || lo.Contains([]string{"DD", "AU", "UA", "UD", "DU"}, change) file := &models.File{ Name: status.Name, diff --git a/pkg/commands/patch/hunk.go b/pkg/commands/patch/hunk.go index bbb2d54ff..98d932126 100644 --- a/pkg/commands/patch/hunk.go +++ b/pkg/commands/patch/hunk.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" ) type PatchHunk struct { @@ -54,7 +55,7 @@ func (hunk *PatchHunk) updatedLines(lineIndices []int, reverse bool) []string { if line == "" { break } - isLineSelected := utils.IncludesInt(lineIndices, lineIdx) + isLineSelected := lo.Contains(lineIndices, lineIdx) firstChar, content := line[:1], line[1:] transformedFirstChar := transformedFirstChar(firstChar, reverse, isLineSelected) diff --git a/pkg/commands/patch/patch_manager.go b/pkg/commands/patch/patch_manager.go index cbdf7b2d4..1282356f8 100644 --- a/pkg/commands/patch/patch_manager.go +++ b/pkg/commands/patch/patch_manager.go @@ -4,7 +4,7 @@ import ( "sort" "strings" - "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" "github.com/sirupsen/logrus" ) @@ -140,7 +140,7 @@ func (p *PatchManager) AddFileLineRange(filename string, firstLineIdx, lastLineI return err } info.mode = PART - info.includedLineIndices = utils.UnionInt(info.includedLineIndices, getIndicesForRange(firstLineIdx, lastLineIdx)) + info.includedLineIndices = lo.Union(info.includedLineIndices, getIndicesForRange(firstLineIdx, lastLineIdx)) return nil } @@ -151,7 +151,7 @@ func (p *PatchManager) RemoveFileLineRange(filename string, firstLineIdx, lastLi return err } info.mode = PART - info.includedLineIndices = utils.DifferenceInt(info.includedLineIndices, getIndicesForRange(firstLineIdx, lastLineIdx)) + info.includedLineIndices, _ = lo.Difference(info.includedLineIndices, getIndicesForRange(firstLineIdx, lastLineIdx)) if len(info.includedLineIndices) == 0 { p.removeFile(info) } diff --git a/pkg/commands/patch/patch_parser.go b/pkg/commands/patch/patch_parser.go index c2be120c9..3810d8a29 100644 --- a/pkg/commands/patch/patch_parser.go +++ b/pkg/commands/patch/patch_parser.go @@ -7,6 +7,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" "github.com/sirupsen/logrus" ) @@ -186,7 +187,7 @@ func (p *PatchParser) Render(firstLineIndex int, lastLineIndex int, incLineIndic renderedLines := make([]string, len(p.PatchLines)) for index, patchLine := range p.PatchLines { selected := index >= firstLineIndex && index <= lastLineIndex - included := utils.IncludesInt(incLineIndices, index) + included := lo.Contains(incLineIndices, index) renderedLines[index] = patchLine.render(selected, included) } result := strings.Join(renderedLines, "\n") diff --git a/pkg/gui/controllers/global_controller.go b/pkg/gui/controllers/global_controller.go index 487c1e10b..c45e98d85 100644 --- a/pkg/gui/controllers/global_controller.go +++ b/pkg/gui/controllers/global_controller.go @@ -1,9 +1,11 @@ package controllers import ( + "github.com/jesseduffield/generics/list" "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" ) type GlobalController struct { @@ -36,9 +38,7 @@ func (self *GlobalController) customCommand() error { FindSuggestionsFunc: self.GetCustomCommandsHistorySuggestionsFunc(), HandleConfirm: func(command string) error { self.c.GetAppState().CustomCommandsHistory = utils.Limit( - utils.Uniq( - append(self.c.GetAppState().CustomCommandsHistory, command), - ), + lo.Uniq(append(self.c.GetAppState().CustomCommandsHistory, command)), 1000, ) @@ -57,7 +57,7 @@ func (self *GlobalController) customCommand() error { func (self *GlobalController) GetCustomCommandsHistorySuggestionsFunc() func(string) []*types.Suggestion { // reversing so that we display the latest command first - history := utils.Reverse(self.c.GetAppState().CustomCommandsHistory) + history := list.Reverse(self.c.GetAppState().CustomCommandsHistory) return helpers.FuzzySearchFunc(history) } diff --git a/pkg/gui/controllers/helpers/cherry_pick_helper.go b/pkg/gui/controllers/helpers/cherry_pick_helper.go index badbf0dfe..e4a9b3e81 100644 --- a/pkg/gui/controllers/helpers/cherry_pick_helper.go +++ b/pkg/gui/controllers/helpers/cherry_pick_helper.go @@ -1,11 +1,13 @@ package helpers import ( + "github.com/jesseduffield/generics/set" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking" "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/samber/lo" ) type CherryPickHelper struct { @@ -63,13 +65,13 @@ func (self *CherryPickHelper) CopyRange(selectedIndex int, commitsList []*models return err } - commitShaMap := self.CherryPickedCommitShaMap() + commitSet := self.CherryPickedCommitShaSet() // find the last commit that is copied that's above our position // if there are none, startIndex = 0 startIndex := 0 for index, commit := range commitsList[0:selectedIndex] { - if commitShaMap[commit.Sha] { + if commitSet.Includes(commit.Sha) { startIndex = index } } @@ -105,25 +107,23 @@ func (self *CherryPickHelper) Reset() error { return self.rerender() } -func (self *CherryPickHelper) CherryPickedCommitShaMap() map[string]bool { - commitShaMap := map[string]bool{} - for _, commit := range self.getData().CherryPickedCommits { - commitShaMap[commit.Sha] = true - } - return commitShaMap +func (self *CherryPickHelper) CherryPickedCommitShaSet() *set.Set[string] { + shas := lo.Map(self.getData().CherryPickedCommits, func(commit *models.Commit, _ int) string { + return commit.Sha + }) + return set.NewFromSlice(shas) } func (self *CherryPickHelper) add(selectedCommit *models.Commit, commitsList []*models.Commit) { - commitShaMap := self.CherryPickedCommitShaMap() - commitShaMap[selectedCommit.Sha] = true + commitSet := self.CherryPickedCommitShaSet() + commitSet.Add(selectedCommit.Sha) - newCommits := []*models.Commit{} - for _, commit := range commitsList { - if commitShaMap[commit.Sha] { - // duplicating just the things we need to put in the rebase TODO list - newCommits = append(newCommits, &models.Commit{Name: commit.Name, Sha: commit.Sha}) - } - } + commitsInSet := lo.Filter(commitsList, func(commit *models.Commit, _ int) bool { + return commitSet.Includes(commit.Sha) + }) + newCommits := lo.Map(commitsInSet, func(commit *models.Commit, _ int) *models.Commit { + return &models.Commit{Name: commit.Name, Sha: commit.Sha} + }) self.getData().CherryPickedCommits = newCommits } diff --git a/pkg/gui/filetree/collapsed_paths.go b/pkg/gui/filetree/collapsed_paths.go index 02c0b4303..903999b37 100644 --- a/pkg/gui/filetree/collapsed_paths.go +++ b/pkg/gui/filetree/collapsed_paths.go @@ -1,20 +1,38 @@ package filetree -type CollapsedPaths map[string]bool +import "github.com/jesseduffield/generics/set" -func (cp CollapsedPaths) ExpandToPath(path string) { +type CollapsedPaths struct { + collapsedPaths *set.Set[string] +} + +func NewCollapsedPaths() *CollapsedPaths { + return &CollapsedPaths{ + collapsedPaths: set.New[string](), + } +} + +func (self *CollapsedPaths) ExpandToPath(path string) { // need every directory along the way splitPath := split(path) for i := range splitPath { dir := join(splitPath[0 : i+1]) - cp[dir] = false + self.collapsedPaths.Remove(dir) } } -func (cp CollapsedPaths) IsCollapsed(path string) bool { - return cp[path] +func (self *CollapsedPaths) IsCollapsed(path string) bool { + return self.collapsedPaths.Includes(path) } -func (cp CollapsedPaths) ToggleCollapsed(path string) { - cp[path] = !cp[path] +func (self *CollapsedPaths) Collapse(path string) { + self.collapsedPaths.Add(path) +} + +func (self *CollapsedPaths) ToggleCollapsed(path string) { + if self.collapsedPaths.Includes(path) { + self.collapsedPaths.Remove(path) + } else { + self.collapsedPaths.Add(path) + } } diff --git a/pkg/gui/filetree/commit_file_node.go b/pkg/gui/filetree/commit_file_node.go index a8f7d0a95..ac2057da5 100644 --- a/pkg/gui/filetree/commit_file_node.go +++ b/pkg/gui/filetree/commit_file_node.go @@ -100,7 +100,7 @@ func (s *CommitFileNode) EveryFile(test func(file *models.CommitFile) bool) bool }) } -func (n *CommitFileNode) Flatten(collapsedPaths map[string]bool) []*CommitFileNode { +func (n *CommitFileNode) Flatten(collapsedPaths *CollapsedPaths) []*CommitFileNode { results := flatten(n, collapsedPaths) nodes := make([]*CommitFileNode, len(results)) for i, result := range results { @@ -110,7 +110,7 @@ func (n *CommitFileNode) Flatten(collapsedPaths map[string]bool) []*CommitFileNo return nodes } -func (node *CommitFileNode) GetNodeAtIndex(index int, collapsedPaths map[string]bool) *CommitFileNode { +func (node *CommitFileNode) GetNodeAtIndex(index int, collapsedPaths *CollapsedPaths) *CommitFileNode { if node == nil { return nil } @@ -124,11 +124,11 @@ func (node *CommitFileNode) GetNodeAtIndex(index int, collapsedPaths map[string] return result.(*CommitFileNode) } -func (node *CommitFileNode) GetIndexForPath(path string, collapsedPaths map[string]bool) (int, bool) { +func (node *CommitFileNode) GetIndexForPath(path string, collapsedPaths *CollapsedPaths) (int, bool) { return getIndexForPath(node, path, collapsedPaths) } -func (node *CommitFileNode) Size(collapsedPaths map[string]bool) int { +func (node *CommitFileNode) Size(collapsedPaths *CollapsedPaths) int { if node == nil { return 0 } diff --git a/pkg/gui/filetree/commit_file_tree.go b/pkg/gui/filetree/commit_file_tree.go index 055e273f3..e539c9dea 100644 --- a/pkg/gui/filetree/commit_file_tree.go +++ b/pkg/gui/filetree/commit_file_tree.go @@ -19,7 +19,7 @@ type CommitFileTree struct { tree *CommitFileNode showTree bool log *logrus.Entry - collapsedPaths CollapsedPaths + collapsedPaths *CollapsedPaths } var _ ICommitFileTree = &CommitFileTree{} @@ -29,7 +29,7 @@ func NewCommitFileTree(getFiles func() []*models.CommitFile, log *logrus.Entry, getFiles: getFiles, log: log, showTree: showTree, - collapsedPaths: CollapsedPaths{}, + collapsedPaths: NewCollapsedPaths(), } } @@ -88,7 +88,7 @@ func (self *CommitFileTree) Tree() INode { return self.tree } -func (self *CommitFileTree) CollapsedPaths() CollapsedPaths { +func (self *CommitFileTree) CollapsedPaths() *CollapsedPaths { return self.collapsedPaths } diff --git a/pkg/gui/filetree/file_node.go b/pkg/gui/filetree/file_node.go index 841f723fc..e73504321 100644 --- a/pkg/gui/filetree/file_node.go +++ b/pkg/gui/filetree/file_node.go @@ -87,7 +87,7 @@ func (s *FileNode) Any(test func(node *FileNode) bool) bool { }) } -func (n *FileNode) Flatten(collapsedPaths map[string]bool) []*FileNode { +func (n *FileNode) Flatten(collapsedPaths *CollapsedPaths) []*FileNode { results := flatten(n, collapsedPaths) nodes := make([]*FileNode, len(results)) for i, result := range results { @@ -97,7 +97,7 @@ func (n *FileNode) Flatten(collapsedPaths map[string]bool) []*FileNode { return nodes } -func (node *FileNode) GetNodeAtIndex(index int, collapsedPaths map[string]bool) *FileNode { +func (node *FileNode) GetNodeAtIndex(index int, collapsedPaths *CollapsedPaths) *FileNode { if node == nil { return nil } @@ -111,11 +111,11 @@ func (node *FileNode) GetNodeAtIndex(index int, collapsedPaths map[string]bool) return result.(*FileNode) } -func (node *FileNode) GetIndexForPath(path string, collapsedPaths map[string]bool) (int, bool) { +func (node *FileNode) GetIndexForPath(path string, collapsedPaths *CollapsedPaths) (int, bool) { return getIndexForPath(node, path, collapsedPaths) } -func (node *FileNode) Size(collapsedPaths map[string]bool) int { +func (node *FileNode) Size(collapsedPaths *CollapsedPaths) int { if node == nil { return 0 } diff --git a/pkg/gui/filetree/file_tree.go b/pkg/gui/filetree/file_tree.go index 0d0524470..47d7f32f2 100644 --- a/pkg/gui/filetree/file_tree.go +++ b/pkg/gui/filetree/file_tree.go @@ -27,7 +27,7 @@ type ITree interface { IsCollapsed(path string) bool ToggleCollapsed(path string) Tree() INode - CollapsedPaths() CollapsedPaths + CollapsedPaths() *CollapsedPaths } type IFileTree interface { @@ -48,7 +48,7 @@ type FileTree struct { showTree bool log *logrus.Entry filter FileTreeDisplayFilter - collapsedPaths CollapsedPaths + collapsedPaths *CollapsedPaths } func NewFileTree(getFiles func() []*models.File, log *logrus.Entry, showTree bool) *FileTree { @@ -57,7 +57,7 @@ func NewFileTree(getFiles func() []*models.File, log *logrus.Entry, showTree boo log: log, showTree: showTree, filter: DisplayAll, - collapsedPaths: CollapsedPaths{}, + collapsedPaths: NewCollapsedPaths(), } } @@ -164,7 +164,7 @@ func (self *FileTree) Tree() INode { return self.tree } -func (self *FileTree) CollapsedPaths() CollapsedPaths { +func (self *FileTree) CollapsedPaths() *CollapsedPaths { return self.collapsedPaths } diff --git a/pkg/gui/filetree/inode.go b/pkg/gui/filetree/inode.go index 7d9035fe3..7c8b9fb75 100644 --- a/pkg/gui/filetree/inode.go +++ b/pkg/gui/filetree/inode.go @@ -90,11 +90,11 @@ func every(node INode, test func(INode) bool) bool { return true } -func flatten(node INode, collapsedPaths map[string]bool) []INode { +func flatten(node INode, collapsedPaths *CollapsedPaths) []INode { result := []INode{} result = append(result, node) - if !collapsedPaths[node.GetPath()] { + if !collapsedPaths.IsCollapsed(node.GetPath()) { for _, child := range node.GetChildren() { result = append(result, flatten(child, collapsedPaths)...) } @@ -103,20 +103,20 @@ func flatten(node INode, collapsedPaths map[string]bool) []INode { return result } -func getNodeAtIndex(node INode, index int, collapsedPaths map[string]bool) INode { +func getNodeAtIndex(node INode, index int, collapsedPaths *CollapsedPaths) INode { foundNode, _ := getNodeAtIndexAux(node, index, collapsedPaths) return foundNode } -func getNodeAtIndexAux(node INode, index int, collapsedPaths map[string]bool) (INode, int) { +func getNodeAtIndexAux(node INode, index int, collapsedPaths *CollapsedPaths) (INode, int) { offset := 1 if index == 0 { return node, offset } - if !collapsedPaths[node.GetPath()] { + if !collapsedPaths.IsCollapsed(node.GetPath()) { for _, child := range node.GetChildren() { foundNode, offsetChange := getNodeAtIndexAux(child, index-offset, collapsedPaths) offset += offsetChange @@ -129,14 +129,14 @@ func getNodeAtIndexAux(node INode, index int, collapsedPaths map[string]bool) (I return nil, offset } -func getIndexForPath(node INode, path string, collapsedPaths map[string]bool) (int, bool) { +func getIndexForPath(node INode, path string, collapsedPaths *CollapsedPaths) (int, bool) { offset := 0 if node.GetPath() == path { return offset, true } - if !collapsedPaths[node.GetPath()] { + if !collapsedPaths.IsCollapsed(node.GetPath()) { for _, child := range node.GetChildren() { offsetChange, found := getIndexForPath(child, path, collapsedPaths) offset += offsetChange + 1 @@ -149,10 +149,10 @@ func getIndexForPath(node INode, path string, collapsedPaths map[string]bool) (i return offset, false } -func size(node INode, collapsedPaths map[string]bool) int { +func size(node INode, collapsedPaths *CollapsedPaths) int { output := 1 - if !collapsedPaths[node.GetPath()] { + if !collapsedPaths.IsCollapsed(node.GetPath()) { for _, child := range node.GetChildren() { output += size(child, collapsedPaths) } diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index 010a2f0b1..dcea5a936 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -123,7 +123,7 @@ func (gui *Gui) branchCommitsListContext() *context.LocalCommitsContext { return presentation.GetCommitListDisplayStrings( gui.State.Model.Commits, gui.State.ScreenMode != SCREEN_NORMAL, - gui.helpers.CherryPick.CherryPickedCommitShaMap(), + gui.helpers.CherryPick.CherryPickedCommitShaSet(), gui.State.Modes.Diffing.Ref, gui.c.UserConfig.Git.ParseEmoji, selectedCommitSha, @@ -155,7 +155,7 @@ func (gui *Gui) subCommitsListContext() *context.SubCommitsContext { return presentation.GetCommitListDisplayStrings( gui.State.Model.SubCommits, gui.State.ScreenMode != SCREEN_NORMAL, - gui.helpers.CherryPick.CherryPickedCommitShaMap(), + gui.helpers.CherryPick.CherryPickedCommitShaSet(), gui.State.Modes.Diffing.Ref, gui.c.UserConfig.Git.ParseEmoji, selectedCommitSha, @@ -199,7 +199,7 @@ func (gui *Gui) reflogCommitsListContext() *context.ReflogCommitsContext { return presentation.GetReflogCommitListDisplayStrings( gui.State.Model.FilteredReflogCommits, gui.State.ScreenMode != SCREEN_NORMAL, - gui.helpers.CherryPick.CherryPickedCommitShaMap(), + gui.helpers.CherryPick.CherryPickedCommitShaSet(), gui.State.Modes.Diffing.Ref, gui.c.UserConfig.Git.ParseEmoji, ) diff --git a/pkg/gui/options_menu_panel.go b/pkg/gui/options_menu_panel.go index 0073bb041..54f08ed50 100644 --- a/pkg/gui/options_menu_panel.go +++ b/pkg/gui/options_menu_panel.go @@ -7,7 +7,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" ) func (gui *Gui) getBindings(context types.Context) []*types.Binding { @@ -26,7 +26,7 @@ func (gui *Gui) getBindings(context types.Context) []*types.Binding { bindingsGlobal = append(bindingsGlobal, binding) } else if binding.Tag == "navigation" { bindingsNavigation = append(bindingsNavigation, binding) - } else if utils.IncludesString(binding.Contexts, string(context.GetKey())) { + } else if lo.Contains(binding.Contexts, string(context.GetKey())) { bindingsPanel = append(bindingsPanel, binding) } } @@ -45,17 +45,9 @@ func (gui *Gui) getBindings(context types.Context) []*types.Binding { // We shouldn't really need to do this. We should define alternative keys for the same // handler in the keybinding struct. func uniqueBindings(bindings []*types.Binding) []*types.Binding { - keys := make(map[string]bool) - result := make([]*types.Binding, 0) - - for _, binding := range bindings { - if _, ok := keys[binding.Description]; !ok { - keys[binding.Description] = true - result = append(result, binding) - } - } - - return result + return lo.UniqBy(bindings, func(binding *types.Binding) string { + return binding.Description + }) } func (gui *Gui) displayDescription(binding *types.Binding) string { diff --git a/pkg/gui/patch_building_panel.go b/pkg/gui/patch_building_panel.go index e734433c4..cae6167a4 100644 --- a/pkg/gui/patch_building_panel.go +++ b/pkg/gui/patch_building_panel.go @@ -1,8 +1,6 @@ package gui -import ( - "github.com/jesseduffield/lazygit/pkg/utils" -) +import "github.com/samber/lo" func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error { if !gui.git.Patch.PatchManager.Active() { @@ -68,7 +66,7 @@ func (gui *Gui) handleToggleSelectionForPatch() error { if err != nil { return err } - currentLineIsStaged := utils.IncludesInt(includedLineIndices, state.GetSelectedLineIdx()) + currentLineIsStaged := lo.Contains(includedLineIndices, state.GetSelectedLineIdx()) if currentLineIsStaged { toggleFunc = gui.git.Patch.PatchManager.RemoveFileLineRange } diff --git a/pkg/gui/presentation/commits.go b/pkg/gui/presentation/commits.go index 2d5262e89..7ec4e78af 100644 --- a/pkg/gui/presentation/commits.go +++ b/pkg/gui/presentation/commits.go @@ -4,6 +4,7 @@ import ( "strings" "sync" + "github.com/jesseduffield/generics/set" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/presentation/authors" @@ -32,7 +33,7 @@ type bisectBounds struct { func GetCommitListDisplayStrings( commits []*models.Commit, fullDescription bool, - cherryPickedCommitShaMap map[string]bool, + cherryPickedCommitShaSet *set.Set[string], diffName string, parseEmoji bool, selectedCommitSha string, @@ -94,7 +95,7 @@ func GetCommitListDisplayStrings( bisectStatus = getBisectStatus(unfilteredIdx, commit.Sha, bisectInfo, bisectBounds) lines = append(lines, displayCommit( commit, - cherryPickedCommitShaMap, + cherryPickedCommitShaSet, diffName, parseEmoji, getGraphLine(unfilteredIdx), @@ -237,7 +238,7 @@ func getBisectStatusText(bisectStatus BisectStatus, bisectInfo *git_commands.Bis func displayCommit( commit *models.Commit, - cherryPickedCommitShaMap map[string]bool, + cherryPickedCommitShaSet *set.Set[string], diffName string, parseEmoji bool, graphLine string, @@ -245,7 +246,7 @@ func displayCommit( bisectStatus BisectStatus, bisectInfo *git_commands.BisectInfo, ) []string { - shaColor := getShaColor(commit, diffName, cherryPickedCommitShaMap, bisectStatus, bisectInfo) + shaColor := getShaColor(commit, diffName, cherryPickedCommitShaSet, bisectStatus, bisectInfo) bisectString := getBisectStatusText(bisectStatus, bisectInfo) actionString := "" @@ -313,7 +314,7 @@ func getBisectStatusColor(status BisectStatus) style.TextStyle { func getShaColor( commit *models.Commit, diffName string, - cherryPickedCommitShaMap map[string]bool, + cherryPickedCommitShaSet *set.Set[string], bisectStatus BisectStatus, bisectInfo *git_commands.BisectInfo, ) style.TextStyle { @@ -338,7 +339,7 @@ func getShaColor( if diffed { shaColor = theme.DiffTerminalColor - } else if cherryPickedCommitShaMap[commit.Sha] { + } else if cherryPickedCommitShaSet.Includes(commit.Sha) { shaColor = theme.CherryPickedCommitTextStyle } diff --git a/pkg/gui/presentation/commits_test.go b/pkg/gui/presentation/commits_test.go index b7fd23468..846d50d19 100644 --- a/pkg/gui/presentation/commits_test.go +++ b/pkg/gui/presentation/commits_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/gookit/color" + "github.com/jesseduffield/generics/set" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/utils" @@ -25,7 +26,7 @@ func TestGetCommitListDisplayStrings(t *testing.T) { testName string commits []*models.Commit fullDescription bool - cherryPickedCommitShaMap map[string]bool + cherryPickedCommitShaSet *set.Set[string] diffName string parseEmoji bool selectedCommitSha string @@ -209,7 +210,7 @@ func TestGetCommitListDisplayStrings(t *testing.T) { result := GetCommitListDisplayStrings( s.commits, s.fullDescription, - s.cherryPickedCommitShaMap, + s.cherryPickedCommitShaSet, s.diffName, s.parseEmoji, s.selectedCommitSha, diff --git a/pkg/gui/presentation/files.go b/pkg/gui/presentation/files.go index be57a3510..13b2a64b0 100644 --- a/pkg/gui/presentation/files.go +++ b/pkg/gui/presentation/files.go @@ -66,7 +66,7 @@ func RenderCommitFileTree( func renderAux( s filetree.INode, - collapsedPaths filetree.CollapsedPaths, + collapsedPaths *filetree.CollapsedPaths, prefix string, depth int, renderLine func(filetree.INode, int) string, diff --git a/pkg/gui/presentation/reflog_commits.go b/pkg/gui/presentation/reflog_commits.go index 5437af8b5..72bb80ef6 100644 --- a/pkg/gui/presentation/reflog_commits.go +++ b/pkg/gui/presentation/reflog_commits.go @@ -1,6 +1,7 @@ package presentation import ( + "github.com/jesseduffield/generics/set" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/theme" @@ -8,7 +9,7 @@ import ( "github.com/kyokomi/emoji/v2" ) -func GetReflogCommitListDisplayStrings(commits []*models.Commit, fullDescription bool, cherryPickedCommitShaMap map[string]bool, diffName string, parseEmoji bool) [][]string { +func GetReflogCommitListDisplayStrings(commits []*models.Commit, fullDescription bool, cherryPickedCommitShaSet *set.Set[string], diffName string, parseEmoji bool) [][]string { lines := make([][]string, len(commits)) var displayFunc func(*models.Commit, bool, bool, bool) []string @@ -20,7 +21,7 @@ func GetReflogCommitListDisplayStrings(commits []*models.Commit, fullDescription for i := range commits { diffed := commits[i].Sha == diffName - cherryPicked := cherryPickedCommitShaMap[commits[i].Sha] + cherryPicked := cherryPickedCommitShaSet.Includes(commits[i].Sha) lines[i] = displayFunc(commits[i], cherryPicked, diffed, parseEmoji) } diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go index 2a47efc7a..5252d7ec9 100644 --- a/pkg/gui/refresh.go +++ b/pkg/gui/refresh.go @@ -5,6 +5,7 @@ import ( "strings" "sync" + "github.com/jesseduffield/generics/set" "github.com/jesseduffield/lazygit/pkg/commands/loaders" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" @@ -52,14 +53,6 @@ func getModeName(mode types.RefreshMode) string { } } -func arrToMap(arr []types.RefreshableView) map[types.RefreshableView]bool { - output := map[types.RefreshableView]bool{} - for _, el := range arr { - output[el] = true - } - return output -} - func (gui *Gui) Refresh(options types.RefreshOptions) error { if options.Scope == nil { gui.c.Log.Infof( @@ -77,9 +70,9 @@ func (gui *Gui) Refresh(options types.RefreshOptions) error { wg := sync.WaitGroup{} f := func() { - var scopeMap map[types.RefreshableView]bool + var scopeSet *set.Set[types.RefreshableView] if len(options.Scope) == 0 { - scopeMap = arrToMap([]types.RefreshableView{ + scopeSet = set.NewFromSlice([]types.RefreshableView{ types.COMMITS, types.BRANCHES, types.FILES, @@ -91,7 +84,7 @@ func (gui *Gui) Refresh(options types.RefreshOptions) error { types.BISECT_INFO, }) } else { - scopeMap = arrToMap(options.Scope) + scopeSet = set.NewFromSlice(options.Scope) } refresh := func(f func()) { @@ -106,27 +99,27 @@ func (gui *Gui) Refresh(options types.RefreshOptions) error { }() } - if scopeMap[types.COMMITS] || scopeMap[types.BRANCHES] || scopeMap[types.REFLOG] || scopeMap[types.BISECT_INFO] { + if scopeSet.Includes(types.COMMITS) || scopeSet.Includes(types.BRANCHES) || scopeSet.Includes(types.REFLOG) || scopeSet.Includes(types.BISECT_INFO) { refresh(gui.refreshCommits) - } else if scopeMap[types.REBASE_COMMITS] { + } else if scopeSet.Includes(types.REBASE_COMMITS) { // the above block handles rebase commits so we only need to call this one // if we've asked specifically for rebase commits and not those other things refresh(func() { _ = gui.refreshRebaseCommits() }) } - if scopeMap[types.FILES] || scopeMap[types.SUBMODULES] { + if scopeSet.Includes(types.FILES) || scopeSet.Includes(types.SUBMODULES) { refresh(func() { _ = gui.refreshFilesAndSubmodules() }) } - if scopeMap[types.STASH] { + if scopeSet.Includes(types.STASH) { refresh(func() { _ = gui.refreshStashEntries() }) } - if scopeMap[types.TAGS] { + if scopeSet.Includes(types.TAGS) { refresh(func() { _ = gui.refreshTags() }) } - if scopeMap[types.REMOTES] { + if scopeSet.Includes(types.REMOTES) { refresh(func() { _ = gui.refreshRemotes() }) } diff --git a/pkg/utils/slice.go b/pkg/utils/slice.go index 123fc7df9..6971c9367 100644 --- a/pkg/utils/slice.go +++ b/pkg/utils/slice.go @@ -1,29 +1,5 @@ package utils -// IncludesString if the list contains the string -func IncludesString(list []string, a string) bool { - return IncludesStringFunc(list, func(b string) bool { return b == a }) -} - -func IncludesStringFunc(list []string, fn func(string) bool) bool { - for _, b := range list { - if fn(b) { - return true - } - } - return false -} - -// IncludesInt if the list contains the Int -func IncludesInt(list []int, a int) bool { - for _, b := range list { - if b == a { - return true - } - } - return false -} - // NextIndex returns the index of the element that comes after the given number func NextIndex(numbers []int, currentNumber int) int { for index, number := range numbers { @@ -45,44 +21,6 @@ func PrevIndex(numbers []int, currentNumber int) int { return 0 } -// UnionInt returns the union of two int arrays -func UnionInt(a, b []int) []int { - m := make(map[int]bool) - - for _, item := range a { - m[item] = true - } - - for _, item := range b { - if _, ok := m[item]; !ok { - // this does not mutate the original a slice - // though it does mutate the backing array I believe - // but that doesn't matter because if you later want to append to the - // original a it must see that the backing array has been changed - // and create a new one - a = append(a, item) - } - } - return a -} - -// DifferenceInt returns the difference of two int arrays -func DifferenceInt(a, b []int) []int { - result := []int{} - m := make(map[int]bool) - - for _, item := range b { - m[item] = true - } - - for _, item := range a { - if _, ok := m[item]; !ok { - result = append(result, item) - } - } - return result -} - // NextIntInCycle returns the next int in a slice, returning to the first index if we've reached the end func NextIntInCycle(sl []int, current int) int { for i, val := range sl { @@ -121,19 +59,6 @@ func StringArraysOverlap(strArrA []string, strArrB []string) bool { return false } -func Uniq(values []string) []string { - added := make(map[string]bool) - result := make([]string, 0, len(values)) - for _, value := range values { - if added[value] { - continue - } - added[value] = true - result = append(result, value) - } - return result -} - func Limit(values []string, limit int) []string { if len(values) > limit { return values[:limit] @@ -141,14 +66,6 @@ func Limit(values []string, limit int) []string { return values } -func Reverse(values []string) []string { - result := make([]string, len(values)) - for i, val := range values { - result[len(values)-i-1] = val - } - return result -} - func LimitStr(value string, limit int) string { n := 0 for i := range value { diff --git a/pkg/utils/slice_test.go b/pkg/utils/slice_test.go index fc80a46d7..e66edcd61 100644 --- a/pkg/utils/slice_test.go +++ b/pkg/utils/slice_test.go @@ -6,42 +6,6 @@ import ( "github.com/stretchr/testify/assert" ) -// TestIncludesString is a function. -func TestIncludesString(t *testing.T) { - type scenario struct { - list []string - element string - expected bool - } - - scenarios := []scenario{ - { - []string{"a", "b"}, - "a", - true, - }, - { - []string{"a", "b"}, - "c", - false, - }, - { - []string{"a", "b"}, - "", - false, - }, - { - []string{""}, - "", - true, - }, - } - - for _, s := range scenarios { - assert.EqualValues(t, s.expected, IncludesString(s.list, s.element)) - } -} - func TestNextIndex(t *testing.T) { type scenario struct { testName string @@ -169,26 +133,6 @@ func TestEscapeSpecialChars(t *testing.T) { } } -func TestUniq(t *testing.T) { - for _, test := range []struct { - values []string - want []string - }{ - { - values: []string{"a", "b", "c"}, - want: []string{"a", "b", "c"}, - }, - { - values: []string{"a", "b", "a", "b", "c"}, - want: []string{"a", "b", "c"}, - }, - } { - if got := Uniq(test.values); !assert.EqualValues(t, got, test.want) { - t.Errorf("Uniq(%v) = %v; want %v", test.values, got, test.want) - } - } -} - func TestLimit(t *testing.T) { for _, test := range []struct { values []string @@ -232,26 +176,6 @@ func TestLimit(t *testing.T) { } } -func TestReverse(t *testing.T) { - for _, test := range []struct { - values []string - want []string - }{ - { - values: []string{"a", "b", "c"}, - want: []string{"c", "b", "a"}, - }, - { - values: []string{}, - want: []string{}, - }, - } { - if got := Reverse(test.values); !assert.EqualValues(t, got, test.want) { - t.Errorf("Reverse(%v) = %v; want %v", test.values, got, test.want) - } - } -} - func TestLimitStr(t *testing.T) { for _, test := range []struct { values string diff --git a/vendor/github.com/jesseduffield/generics/LICENSE b/vendor/github.com/jesseduffield/generics/LICENSE new file mode 100644 index 000000000..2a7175dcc --- /dev/null +++ b/vendor/github.com/jesseduffield/generics/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Jesse Duffield + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/jesseduffield/generics/hashmap/functions.go b/vendor/github.com/jesseduffield/generics/hashmap/functions.go new file mode 100644 index 000000000..526222b1f --- /dev/null +++ b/vendor/github.com/jesseduffield/generics/hashmap/functions.go @@ -0,0 +1,35 @@ +package hashmap + +func Keys[Key comparable, Value any](m map[Key]Value) []Key { + keys := make([]Key, 0, len(m)) + for key := range m { + keys = append(keys, key) + } + return keys +} + +func Values[Key comparable, Value any](m map[Key]Value) []Value { + values := make([]Value, 0, len(m)) + for _, value := range m { + values = append(values, value) + } + return values +} + +func TransformValues[Key comparable, Value any, NewValue any]( + m map[Key]Value, fn func(Value) NewValue, +) map[Key]NewValue { + output := make(map[Key]NewValue) + for key, value := range m { + output[key] = fn(value) + } + return output +} + +func TransformKeys[Key comparable, Value any, NewKey comparable](m map[Key]Value, fn func(Key) NewKey) map[NewKey]Value { + output := make(map[NewKey]Value) + for key, value := range m { + output[fn(key)] = value + } + return output +} diff --git a/vendor/github.com/jesseduffield/generics/list/comparable_list.go b/vendor/github.com/jesseduffield/generics/list/comparable_list.go new file mode 100644 index 000000000..21d56a80b --- /dev/null +++ b/vendor/github.com/jesseduffield/generics/list/comparable_list.go @@ -0,0 +1,49 @@ +package list + +import ( + "golang.org/x/exp/slices" +) + +type ComparableList[T comparable] struct { + *List[T] +} + +func NewComparable[T comparable]() *ComparableList[T] { + return &ComparableList[T]{List: New[T]()} +} + +func NewComparableFromSlice[T comparable](slice []T) *ComparableList[T] { + return &ComparableList[T]{List: NewFromSlice(slice)} +} + +func (l *ComparableList[T]) Equal(other *ComparableList[T]) bool { + return l.EqualSlice(other.ToSlice()) +} + +func (l *ComparableList[T]) EqualSlice(other []T) bool { + return slices.Equal(l.ToSlice(), other) +} + +func (l *ComparableList[T]) Compact() { + l.slice = slices.Compact(l.slice) +} + +func (l *ComparableList[T]) Index(needle T) int { + return slices.Index(l.slice, needle) +} + +func (l *ComparableList[T]) Contains(needle T) bool { + return slices.Contains(l.slice, needle) +} + +func (l *ComparableList[T]) SortFuncInPlace(test func(a T, b T) bool) { + slices.SortFunc(l.slice, test) +} + +func (l *ComparableList[T]) SortFunc(test func(a T, b T) bool) *ComparableList[T] { + newSlice := slices.Clone(l.slice) + + slices.SortFunc(newSlice, test) + + return NewComparableFromSlice(newSlice) +} diff --git a/vendor/github.com/jesseduffield/generics/list/functions.go b/vendor/github.com/jesseduffield/generics/list/functions.go new file mode 100644 index 000000000..21578b82f --- /dev/null +++ b/vendor/github.com/jesseduffield/generics/list/functions.go @@ -0,0 +1,72 @@ +package list + +func Some[T any](slice []T, test func(T) bool) bool { + for _, value := range slice { + if test(value) { + return true + } + } + + return false +} + +func Every[T any](slice []T, test func(T) bool) bool { + for _, value := range slice { + if !test(value) { + return false + } + } + + return true +} + +func Map[T any, V any](slice []T, f func(T) V) []V { + result := make([]V, len(slice)) + for i, value := range slice { + result[i] = f(value) + } + + return result +} + +func MapInPlace[T any](slice []T, f func(T) T) { + for i, value := range slice { + slice[i] = f(value) + } +} + +func Filter[T any](slice []T, test func(T) bool) []T { + result := make([]T, 0) + for _, element := range slice { + if test(element) { + result = append(result, element) + } + } + return result +} + +func FilterInPlace[T any](slice []T, test func(T) bool) []T { + newLength := 0 + for _, element := range slice { + if test(element) { + slice[newLength] = element + newLength++ + } + } + + return slice[:newLength] +} + +func Reverse[T any](slice []T) []T { + result := make([]T, len(slice)) + for i := range slice { + result[i] = slice[len(slice)-1-i] + } + return result +} + +func ReverseInPlace[T any](slice []T) { + for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 { + slice[i], slice[j] = slice[j], slice[i] + } +} diff --git a/vendor/github.com/jesseduffield/generics/list/list.go b/vendor/github.com/jesseduffield/generics/list/list.go new file mode 100644 index 000000000..2b0f43010 --- /dev/null +++ b/vendor/github.com/jesseduffield/generics/list/list.go @@ -0,0 +1,117 @@ +package list + +import ( + "golang.org/x/exp/slices" +) + +type List[T any] struct { + slice []T +} + +func New[T any]() *List[T] { + return &List[T]{} +} + +func NewFromSlice[T any](slice []T) *List[T] { + return &List[T]{slice: slice} +} + +func (l *List[T]) ToSlice() []T { + return l.slice +} + +// Mutative methods + +func (l *List[T]) Push(v T) { + l.slice = append(l.slice, v) +} + +func (l *List[T]) Pop() { + l.slice = l.slice[0 : len(l.slice)-1] +} + +func (l *List[T]) Insert(index int, values ...T) { + l.slice = slices.Insert(l.slice, index, values...) +} + +func (l *List[T]) Append(values ...T) { + l.slice = append(l.slice, values...) +} + +func (l *List[T]) Prepend(values ...T) { + l.slice = append(values, l.slice...) +} + +func (l *List[T]) Remove(index int) { + l.Delete(index, index+1) +} + +func (l *List[T]) Delete(from int, to int) { + l.slice = slices.Delete(l.slice, from, to) +} + +func (l *List[T]) FilterInPlace(test func(value T) bool) { + l.slice = FilterInPlace(l.slice, test) +} + +func (l *List[T]) MapInPlace(f func(value T) T) { + MapInPlace(l.slice, f) +} + +func (l *List[T]) ReverseInPlace() { + ReverseInPlace(l.slice) +} + +// Non-mutative methods + +// Similar to Append but we leave the original slice untouched and return a new list +func (l *List[T]) Concat(values ...T) *List[T] { + newSlice := make([]T, 0, len(l.slice)+len(values)) + newSlice = append(newSlice, l.slice...) + newSlice = append(newSlice, values...) + return &List[T]{slice: newSlice} +} + +func (l *List[T]) Filter(test func(value T) bool) *List[T] { + return NewFromSlice(Filter(l.slice, test)) +} + +// Unfortunately this does not support mapping from one type to another +// because Go does not yet (and may never) support methods defining their own +// type parameters. For that functionality you'll need to use the standalone +// Map function instead +func (l *List[T]) Map(f func(value T) T) *List[T] { + return NewFromSlice(Map(l.slice, f)) +} + +func (l *List[T]) Clone() *List[T] { + return NewFromSlice(slices.Clone(l.slice)) +} + +func (l *List[T]) Some(test func(value T) bool) bool { + return Some(l.slice, test) +} + +func (l *List[T]) Every(test func(value T) bool) bool { + return Every(l.slice, test) +} + +func (l *List[T]) IndexFunc(f func(T) bool) int { + return slices.IndexFunc(l.slice, f) +} + +func (l *List[T]) ContainsFunc(f func(T) bool) bool { + return l.IndexFunc(f) != -1 +} + +func (l *List[T]) Reverse() *List[T] { + return NewFromSlice(Reverse(l.slice)) +} + +func (l *List[T]) IsEmpty() bool { + return len(l.slice) == 0 +} + +func (l *List[T]) Len() int { + return len(l.slice) +} diff --git a/vendor/github.com/jesseduffield/generics/set/set.go b/vendor/github.com/jesseduffield/generics/set/set.go new file mode 100644 index 000000000..3e9b9d9bf --- /dev/null +++ b/vendor/github.com/jesseduffield/generics/set/set.go @@ -0,0 +1,49 @@ +package set + +import "github.com/jesseduffield/generics/hashmap" + +type Set[T comparable] struct { + hashMap map[T]bool +} + +func New[T comparable]() *Set[T] { + return &Set[T]{hashMap: make(map[T]bool)} +} + +func NewFromSlice[T comparable](slice []T) *Set[T] { + hashMap := make(map[T]bool) + for _, value := range slice { + hashMap[value] = true + } + + return &Set[T]{hashMap: hashMap} +} + +func (s *Set[T]) Add(value T) { + s.hashMap[value] = true +} + +func (s *Set[T]) AddSlice(slice []T) { + for _, value := range slice { + s.Add(value) + } +} + +func (s *Set[T]) Remove(value T) { + delete(s.hashMap, value) +} + +func (s *Set[T]) RemoveSlice(slice []T) { + for _, value := range slice { + s.Remove(value) + } +} + +func (s *Set[T]) Includes(value T) bool { + return s.hashMap[value] +} + +// output slice is not necessarily in the same order that items were added +func (s *Set[T]) ToSlice() []T { + return hashmap.Keys(s.hashMap) +} diff --git a/vendor/github.com/samber/lo/.gitignore b/vendor/github.com/samber/lo/.gitignore new file mode 100644 index 000000000..3aa3a0ad4 --- /dev/null +++ b/vendor/github.com/samber/lo/.gitignore @@ -0,0 +1,36 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/go +# Edit at https://www.toptal.com/developers/gitignore?templates=go + +### Go ### +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +### Go Patch ### +/vendor/ +/Godeps/ + +# End of https://www.toptal.com/developers/gitignore/api/go + +cover.out +cover.html +.vscode diff --git a/vendor/github.com/samber/lo/CHANGELOG.md b/vendor/github.com/samber/lo/CHANGELOG.md new file mode 100644 index 000000000..aabeed120 --- /dev/null +++ b/vendor/github.com/samber/lo/CHANGELOG.md @@ -0,0 +1,71 @@ +# Changelog + +## 1.3.0 (2022-03-03) + +Last and Nth return errors + +## 1.2.0 (2022-03-03) + +Adding `lop.Map` and `lop.ForEach`. + +## 1.1.0 (2022-03-03) + +Adding `i int` param to `lo.Map()`, `lo.Filter()`, `lo.ForEach()` and `lo.Reduce()` predicates. + +## 1.0.0 (2022-03-02) + +*Initial release* + +Supported helpers for slices: + +- Filter +- Map +- Reduce +- ForEach +- Uniq +- UniqBy +- GroupBy +- Chunk +- Flatten +- Shuffle +- Reverse +- Fill +- ToMap + +Supported helpers for maps: + +- Keys +- Values +- Entries +- FromEntries +- Assign (maps merge) + +Supported intersection helpers: + +- Contains +- Every +- Some +- Intersect +- Difference + +Supported search helpers: + +- IndexOf +- LastIndexOf +- Find +- Min +- Max +- Last +- Nth + +Other functional programming helpers: + +- Ternary (1 line if/else statement) +- If / ElseIf / Else +- Switch / Case / Default +- ToPtr +- ToSlicePtr + +Constraints: + +- Clonable diff --git a/vendor/github.com/samber/lo/Dockerfile b/vendor/github.com/samber/lo/Dockerfile new file mode 100644 index 000000000..9f9f87192 --- /dev/null +++ b/vendor/github.com/samber/lo/Dockerfile @@ -0,0 +1,8 @@ + +FROM golang:1.18rc1-bullseye + +WORKDIR /go/src/github.com/samber/lo + +COPY Makefile go.* /go/src/github.com/samber/lo/ + +RUN make tools diff --git a/vendor/github.com/samber/lo/LICENSE b/vendor/github.com/samber/lo/LICENSE new file mode 100644 index 000000000..c3dc72d9a --- /dev/null +++ b/vendor/github.com/samber/lo/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Samuel Berthe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/samber/lo/Makefile b/vendor/github.com/samber/lo/Makefile new file mode 100644 index 000000000..11b09cd25 --- /dev/null +++ b/vendor/github.com/samber/lo/Makefile @@ -0,0 +1,51 @@ + +BIN=go +# BIN=go1.18beta1 + +go1.18beta1: + go install golang.org/dl/go1.18beta1@latest + go1.18beta1 download + +build: + ${BIN} build -v ./... + +test: + go test -race -v ./... +watch-test: + reflex -R assets.go -t 50ms -s -- sh -c 'gotest -race -v ./...' + +bench: + go test -benchmem -count 3 -bench ./... +watch-bench: + reflex -R assets.go -t 50ms -s -- sh -c 'go test -benchmem -count 3 -bench ./...' + +coverage: + ${BIN} test -v -coverprofile cover.out . + ${BIN} tool cover -html=cover.out -o cover.html + +# tools +tools: + ${BIN} install github.com/cespare/reflex@latest + ${BIN} install github.com/rakyll/gotest@latest + ${BIN} install github.com/psampaz/go-mod-outdated@latest + ${BIN} install github.com/jondot/goweight@latest + ${BIN} install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + ${BIN} get -t -u golang.org/x/tools/cmd/cover + ${BIN} get -t -u github.com/sonatype-nexus-community/nancy@latest + go mod tidy + +lint: + golangci-lint run --timeout 60s --max-same-issues 50 ./... +lint-fix: + golangci-lint run --timeout 60s --max-same-issues 50 --fix ./... + +audit: tools + ${BIN} mod tidy + ${BIN} list -json -m all | nancy sleuth + +outdated: tools + ${BIN} mod tidy + ${BIN} list -u -m -json all | go-mod-outdated -update -direct + +weight: tools + goweight diff --git a/vendor/github.com/samber/lo/README.md b/vendor/github.com/samber/lo/README.md new file mode 100644 index 000000000..48dfdc004 --- /dev/null +++ b/vendor/github.com/samber/lo/README.md @@ -0,0 +1,981 @@ +# lo + + +[](https://pkg.go.dev/github.com/samber/lo) +[](https://goreportcard.com/report/github.com/samber/lo) + +鉁 **`lo` is a Lodash-style Go library based on Go 1.18+ Generics.** + +This project started as an experiment with the new generics implementation. It may look like [Lodash](https://github.com/lodash/lodash) in some aspects. I used to code with the fantastic ["go-funk"](https://github.com/thoas/go-funk) package, but "go-funk" uses reflection and therefore is not typesafe. + +As expected, benchmarks demonstrate that generics will be much faster than implementations based on the "reflect" package. Benchmarks also show similar performance gains compared to pure `for` loops. [See below](#-benchmark). + +In the future, 5 to 10 helpers will overlap with those coming into the Go standard library (under package names `slices` and `maps`). I feel this library is legitimate and offers many more valuable abstractions. + +### Why this name? + +I wanted a **short name**, similar to "Lodash" and no Go package currently uses this name. + +## 馃殌 Install + +```sh +go get github.com/samber/lo +``` + +## 馃挕 Usage + +You can import `lo` using: + +```go +import ( + "github.com/samber/lo" + lop "github.com/samber/lo/parallel" +) +``` + +Then use one of the helpers below: + +```go +names := lo.Uniq[string]([]string{"Samuel", "Marc", "Samuel"}) +// []string{"Samuel", "Marc"} +``` + +Most of the time, the compiler will be able to infer the type so that you can call: `lo.Uniq([]string{...})`. + +## 馃 Spec + +GoDoc: [https://godoc.org/github.com/samber/lo](https://godoc.org/github.com/samber/lo) + +Supported helpers for slices: + +- Filter +- Map +- FlatMap +- Reduce +- ForEach +- Times +- Uniq +- UniqBy +- GroupBy +- Chunk +- PartitionBy +- Flatten +- Shuffle +- Reverse +- Fill +- Repeat +- KeyBy +- Drop +- DropRight +- DropWhile +- DropRightWhile + +Supported helpers for maps: + +- Keys +- Values +- Entries +- FromEntries +- Assign (merge of maps) +- MapValues + +Supported helpers for tuples: + +- Zip2 -> Zip9 +- Unzip2 -> Unzip9 + +Supported intersection helpers: + +- Contains +- ContainsBy +- Every +- Some +- Intersect +- Difference +- Union + +Supported search helpers: + +- IndexOf +- LastIndexOf +- Find +- Min +- Max +- Last +- Nth +- Sample +- Samples + +Other functional programming helpers: + +- Ternary (1 line if/else statement) +- If / ElseIf / Else +- Switch / Case / Default +- ToPtr +- ToSlicePtr +- Attempt +- Range / RangeFrom / RangeWithSteps + +Constraints: + +- Clonable + +### Map + +Manipulates a slice of one type and transforms it into a slice of another type: + +```go +import "github.com/samber/lo" + +lo.Map[int64, string]([]int64{1, 2, 3, 4}, func(x int64, _ int) string { + return strconv.FormatInt(x, 10) +}) +// []string{"1", "2", "3", "4"} +``` + +Parallel processing: like `lo.Map()`, but the mapper function is called in a goroutine. Results are returned in the same order. + +```go +import lop "github.com/samber/lo/parallel" + +lop.Map[int64, string]([]int64{1, 2, 3, 4}, func(x int64, _ int) string { + return strconv.FormatInt(x, 10) +}) +// []string{"1", "2", "3", "4"} +``` + +### FlatMap + +Manipulates a slice and transforms and flattens it to a slice of another type. + +```go +lo.FlatMap[int, string]([]int{0, 1, 2}, func(x int, _ int) []string { + return []string{ + strconv.FormatInt(x, 10), + strconv.FormatInt(x, 10), + } +}) +// []string{"0", "0", "1", "1", "2", "2"} +``` + +### Filter + +Iterates over a collection and returns an array of all the elements the predicate function returns `true` for. + +```go +even := lo.Filter[int]([]int{1, 2, 3, 4}, func(x int, _ int) bool { + return x%2 == 0 +}) +// []int{2, 4} +``` + +### Contains + +Returns true if an element is present in a collection. + +```go +present := lo.Contains[int]([]int{0, 1, 2, 3, 4, 5}, 5) +// true +``` + +### Contains + +Returns true if the predicate function returns `true`. + +```go +present := lo.ContainsBy[int]([]int{0, 1, 2, 3, 4, 5}, func(x int) bool { + return x == 3 +}) +// true +``` + +### Reduce + +Reduces a collection to a single value. The value is calculated by accumulating the result of running each element in the collection through an accumulator function. Each successive invocation is supplied with the return value returned by the previous call. + +```go +sum := lo.Reduce[int, int]([]int{1, 2, 3, 4}, func(agg int, item int, _ int) int { + return agg + item +}, 0) +// 10 +``` + +### ForEach + +Iterates over elements of a collection and invokes the function over each element. + +```go +import "github.com/samber/lo" + +lo.ForEach[string]([]string{"hello", "world"}, func(x string, _ int) { + println(x) +}) +// prints "hello\nworld\n" +``` + +Parallel processing: like `lo.ForEach()`, but the callback is called as a goroutine. + +```go +import lop "github.com/samber/lo/parallel" + +lop.ForEach[string]([]string{"hello", "world"}, func(x string, _ int) { + println(x) +}) +// prints "hello\nworld\n" or "world\nhello\n" +``` + +### Times + +Times invokes the iteratee n times, returning an array of the results of each invocation. The iteratee is invoked with index as argument. + +```go +import "github.com/samber/lo" + +lo.Times[string](3, func(i int) string { + return strconv.FormatInt(int64(i), 10) +}) +// []string{"0", "1", "2"} +``` + +Parallel processing: like `lo.Times()`, but callback is called in goroutine. + +```go +import lop "github.com/samber/lo/parallel" + +lop.Times[string](3, func(i int) string { + return strconv.FormatInt(int64(i), 10) +}) +// []string{"0", "1", "2"} +``` + +### Uniq + +Returns a duplicate-free version of an array, in which only the first occurrence of each element is kept. The order of result values is determined by the order they occur in the array. + +```go +uniqValues := lo.Uniq[int]([]int{1, 2, 2, 1}) +// []int{1, 2} +``` + +### UniqBy + +Returns a duplicate-free version of an array, in which only the first occurrence of each element is kept. The order of result values is determined by the order they occur in the array. It accepts `iteratee` which is invoked for each element in array to generate the criterion by which uniqueness is computed. + +```go +uniqValues := lo.UniqBy[int, int]([]int{0, 1, 2, 3, 4, 5}, func(i int) int { + return i%3 +}) +// []int{0, 1, 2} +``` + +### GroupBy + +Returns an object composed of keys generated from the results of running each element of collection through iteratee. + +```go +import lo "github.com/samber/lo" + +groups := lo.GroupBy[int, int]([]int{0, 1, 2, 3, 4, 5}, func(i int) int { + return i%3 +}) +// map[int][]int{0: []int{0, 3}, 1: []int{1, 4}, 2: []int{2, 5}} +``` + +Parallel processing: like `lo.GroupBy()`, but callback is called in goroutine. + +```go +import lop "github.com/samber/lo/parallel" + +lop.GroupBy[int, int]([]int{0, 1, 2, 3, 4, 5}, func(i int) int { + return i%3 +}) +// map[int][]int{0: []int{0, 3}, 1: []int{1, 4}, 2: []int{2, 5}} +``` + +### Chunk + +Returns an array of elements split into groups the length of size. If array can't be split evenly, the final chunk will be the remaining elements. + +```go +lo.Chunk[int]([]int{0, 1, 2, 3, 4, 5}, 2) +// [][]int{{0, 1}, {2, 3}, {4, 5}} + +lo.Chunk[int]([]int{0, 1, 2, 3, 4, 5, 6}, 2) +// [][]int{{0, 1}, {2, 3}, {4, 5}, {6}} + +lo.Chunk[int]([]int{}, 2) +// [][]int{} + +lo.Chunk[int]([]int{0}, 2) +// [][]int{{0}} +``` + +### PartitionBy + +Returns an array of elements split into groups. The order of grouped values is determined by the order they occur in collection. The grouping is generated from the results of running each element of collection through iteratee. + +```go +import lo "github.com/samber/lo" + +partitions := lo.PartitionBy[int, string]([]int{-2, -1, 0, 1, 2, 3, 4, 5}, func(x int) string { + if x < 0 { + return "negative" + } else if x%2 == 0 { + return "even" + } + return "odd" +}) +// [][]int{{-2, -1}, {0, 2, 4}, {1, 3, 5}} +``` + +Parallel processing: like `lo.PartitionBy()`, but callback is called in goroutine. Results are returned in the same order. + +```go +import lop "github.com/samber/lo/parallel" + +partitions := lo.PartitionBy[int, string]([]int{-2, -1, 0, 1, 2, 3, 4, 5}, func(x int) string { + if x < 0 { + return "negative" + } else if x%2 == 0 { + return "even" + } + return "odd" +}) +// [][]int{{-2, -1}, {0, 2, 4}, {1, 3, 5}} +``` + +### Flatten + +Returns an array a single level deep. + +```go +flat := lo.Flatten[int]([][]int{{0, 1}, {2, 3, 4, 5}}) +// []int{0, 1, 2, 3, 4, 5} +``` + +### Shuffle + +Returns an array of shuffled values. Uses the Fisher-Yates shuffle algorithm. + +```go +randomOrder := lo.Shuffle[int]([]int{0, 1, 2, 3, 4, 5}) +// []int{0, 1, 2, 3, 4, 5} +``` + +### Reverse + +Reverses array so that the first element becomes the last, the second element becomes the second to last, and so on. + +```go +reverseOder := lo.Reverse[int]([]int{0, 1, 2, 3, 4, 5}) +// []int{5, 4, 3, 2, 1, 0} +``` + +### Fill + +Fills elements of array with `initial` value. + +```go +type foo struct { + bar string +} + +func (f foo) Clone() foo { + return foo{f.bar} +} + +initializedSlice := lo.Fill[foo]([]foo{foo{"a"}, foo{"a"}}, foo{"b"}) +// []foo{foo{"b"}, foo{"b"}} +``` + +### Repeat + +Builds a slice with N copies of initial value. + +```go +type foo struct { + bar string +} + +func (f foo) Clone() foo { + return foo{f.bar} +} + +initializedSlice := lo.Repeat[foo](2, foo{"a"}) +// []foo{foo{"a"}, foo{"a"}} +``` + +### KeyBy + +Transforms a slice or an array of structs to a map based on a pivot callback. + +```go +m := lo.KeyBy[int, string]([]string{"a", "aa", "aaa"}, func(str string) int { + return len(str) +}) +// map[int]string{1: "a", 2: "aa", 3: "aaa"} + +type Character struct { + dir string + code int +} +characters := []Character{ + {dir: "left", code: 97}, + {dir: "right", code: 100}, +} +result := KeyBy[Character, string](characters, func(char Character) string { + return string(rune(char.code)) +}) +//map[a:{dir:left code:97} d:{dir:right code:100}] +``` + +### Drop + +Drops n elements from the beginning of a slice or array. + +```go +l := lo.Drop[int]([]int{0, 1, 2, 3, 4, 5}, 2) +// []int{2, 3, 4, 5} +``` + +### DropRight + +Drops n elements from the end of a slice or array. + +```go +l := lo.DropRight[int]([]int{0, 1, 2, 3, 4, 5}, 2) +// []int{0, 1, 2, 3} +``` + +### DropWhile + +Drop elements from the beginning of a slice or array while the predicate returns true. + +```go +l := lo.DropWhile[string]([]string{"a", "aa", "aaa", "aa", "aa"}, func(val string) bool { + return len(val) <= 2 +}) +// []string{"aaa", "aa", "a"} +``` + +### DropRightWhile + +Drop elements from the end of a slice or array while the predicate returns true. + +```go +l := lo.DropRightWhile[string]([]string{"a", "aa", "aaa", "aa", "aa"}, func(val string) bool { + return len(val) <= 2 +}) +// []string{"a", "aa", "aaa"} +``` + +### Keys + +Creates an array of the map keys. + +```go +keys := lo.Keys[string, int](map[string]int{"foo": 1, "bar": 2}) +// []string{"bar", "foo"} +``` + +### Values + +Creates an array of the map values. + +```go +values := lo.Values[string, int](map[string]int{"foo": 1, "bar": 2}) +// []int{1, 2} +``` + +### Entries + +Transforms a map into array of key/value pairs. + +```go +entries := lo.Entries[string, int](map[string]int{"foo": 1, "bar": 2}) +// []lo.Entry[string, int]{ +// { +// Key: "foo", +// Value: 1, +// }, +// { +// Key: "bar", +// Value: 2, +// }, +// } +``` + +### FromEntries + +Transforms an array of key/value pairs into a map. + +```go +m := lo.FromEntries[string, int]([]lo.Entry[string, int]{ + { + Key: "foo", + Value: 1, + }, + { + Key: "bar", + Value: 2, + }, +}) +// map[string]int{"foo": 1, "bar": 2} +``` + +### Assign + +Merges multiple maps from left to right. + +```go +mergedMaps := lo.Assign[string, int]( + map[string]int{"a": 1, "b": 2}, + map[string]int{"b": 3, "c": 4}, +) +// map[string]int{"a": 1, "b": 3, "c": 4} +``` + +### MapValues + +Manipulates a map values and transforms it to a map of another type. + +```go +m1 := map[int]int64{1: 1, 2: 2, 3: 3} + +m2 := lo.MapValues[int, int64, string](m, func(x int64, _ int) string { + return strconv.FormatInt(x, 10) +}) +// map[int]string{1: "1", 2: "2", 3: "3"} +``` + +### Zip2 -> Zip9 + +Zip creates a slice of grouped elements, the first of which contains the first elements of the given arrays, the second of which contains the second elements of the given arrays, and so on. + +When collections have different size, the Tuple attributes are filled with zero value. + +```go +tuples := lo.Zip2[string, int]([]string{"a", "b"}, []int{1, 2}) +// []Tuple2[string, int]{{A: "a", B: 1}, {A: "b", B: 2}} +``` + +### Unzip2 -> Unzip9 + +Unzip accepts an array of grouped elements and creates an array regrouping the elements to their pre-zip configuration. + +```go +a, b := lo.Unzip2[string, int]([]Tuple2[string, int]{{A: "a", B: 1}, {A: "b", B: 2}}) +// []string{"a", "b"} +// []int{1, 2} +``` + +### Every + +Returns true if all elements of a subset are contained into a collection. + +```go +ok := lo.Every[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 2}) +// true + +ok := lo.Every[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 6}) +// false +``` + +### Some + +Returns true if at least 1 element of a subset is contained into a collection. + +```go +ok := lo.Some[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 2}) +// true + +ok := lo.Some[int]([]int{0, 1, 2, 3, 4, 5}, []int{-1, 6}) +// false +``` + +### Intersect + +Returns the intersection between two collections. + +```go +result1 := lo.Intersect[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 2}) +// []int{0, 2} + +result2 := lo.Intersect[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 6} +// []int{0} + +result3 := lo.Intersect[int]([]int{0, 1, 2, 3, 4, 5}, []int{-1, 6}) +// []int{} +``` + +### Difference + +Returns the difference between two collections. + +- The first value is the collection of element absent of list2. +- The second value is the collection of element absent of list1. + +```go +left, right := lo.Difference[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 2, 6}) +// []int{1, 3, 4, 5}, []int{6} + +left, right := Difference[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 1, 2, 3, 4, 5}) +// []int{}, []int{} +``` + +### Union + +Returns all distinct elements from both collections. Result will not change the order of elements relatively. + +```go +union := lo.Union[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 2, 10}) +// []int{0, 1, 2, 3, 4, 5, 10} +``` + +### IndexOf + +Returns the index at which the first occurrence of a value is found in an array or return -1 if the value cannot be found. + +```go +found := lo.IndexOf[int]([]int{0, 1, 2, 1, 2, 3}, 2) +// 2 + +notFound := lo.IndexOf[int]([]int{0, 1, 2, 1, 2, 3}, 6) +// -1 +``` + +### LastIndex + +Returns the index at which the last occurrence of a value is found in an array or return -1 if the value cannot be found. + +```go +found := lo.LastIndexOf[int]([]int{0, 1, 2, 1, 2, 3}, 2) +// 4 + +notFound := lo.LastIndexOf[int]([]int{0, 1, 2, 1, 2, 3}, 6) +// -1 +``` + +### Find + +Search an element in a slice based on a predicate. It returns element and true if element was found. + +```go +str, ok := lo.Find[string]([]string{"a", "b", "c", "d"}, func(i string) bool { + return i == "b" +}) +// "b", true + +str, ok := lo.Find[string]([]string{"foobar"}, func(i string) bool { + return i == "b" +}) +// "", false +``` + +### Min + +Search the minimum value of a collection. + +```go +min := lo.Min[int]([]int{1, 2, 3}) +// 1 + +min := lo.Min[int]([]int{}) +// 0 +``` + +### Max + +Search the maximum value of a collection. + +```go +max := lo.Max[int]([]int{1, 2, 3}) +// 3 + +max := lo.Max[int]([]int{}) +// 0 +``` + +### Last + +Returns the last element of a collection or error if empty. + +```go +last, err := lo.Last[int]([]int{1, 2, 3}) +// 3 +``` + +### Nth + +Returns the element at index `nth` of collection. If `nth` is negative, the nth element from the end is returned. An error is returned when nth is out of slice bounds. + +```go +nth, err := lo.Nth[int]([]int{0, 1, 2, 3}, 2) +// 2 + +nth, err := lo.Nth[int]([]int{0, 1, 2, 3}, -2) +// 2 +``` + +### Sample + +Returns a random item from collection. + +```go +lo.Sample[string]([]string{"a", "b", "c"}) +// a random string from []string{"a", "b", "c"} + +lo.Sample[string]([]string{}) +// "" +``` + +### Samples + +Returns N random unique items from collection. + +```go +lo.Samples[string]([]string{"a", "b", "c"}, 3) +// []string{"a", "b", "c"} in random order +``` + +### Ternary + +A 1 line if/else statement. + +```go +result := lo.Ternary[string](true, "a", "b") +// "a" + +result := lo.Ternary[string](false, "a", "b") +// "b" +``` + +### If / ElseIf / Else + +```go +result := lo.If[int](true, 1). + ElseIf(false, 2). + Else(3) +// 1 + +result := lo.If[int](false, 1). + ElseIf(true, 2). + Else(3) +// 2 + +result := lo.If[int](false, 1). + ElseIf(false, 2). + Else(3) +// 3 +``` + +### Switch / Case / Default + +```go +result := lo.Switch[int, string](1). + Case(1, "1"). + Case(2, "2"). + Default("3") +// "1" + +result := lo.Switch[int, string](2). + Case(1, "1"). + Case(2, "2"). + Default("3") +// "2" + +result := lo.Switch[int, string](42). + Case(1, "1"). + Case(2, "2"). + Default("3") +// "3" +``` + +Using callbacks: + +```go +result := lo.Switch[int, string](1). + CaseF(1, func() string { + return "1" + }). + CaseF(2, func() string { + return "2" + }). + DefaultF(func() string { + return "3" + }) +// "1" +``` + +### ToPtr + +Returns a pointer copy of value. + +```go +ptr := lo.ToPtr[string]("hello world") +// *string{"hello world"} +``` + +### ToSlicePtr + +Returns a slice of pointer copy of value. + +```go +ptr := lo.ToSlicePtr[string]([]string{"hello", "world"}) +// []*string{"hello", "world"} +``` + +### Attempt + +Invokes a function N times until it returns valid output. Returning either the caught error or nil. When first argument is less than `1`, the function runs until a sucessfull response is returned. + +```go +iter, err := lo.Attempt(42, func(i int) error { + if i == 5 { + return nil + } + + return fmt.Errorf("failed") +}) +// 6 +// nil + +iter, err := lo.Attempt(2, func(i int) error { + if i == 5 { + return nil + } + + return fmt.Errorf("failed") +}) +// 2 +// error "failed" + +iter, err := lo.Attempt(0, func(i int) error { + if i < 42 { + return fmt.Errorf("failed") + } + + return nil +}) +// 43 +// nil +``` + +### Range / RangeFrom / RangeWithSteps + +Creates an array of numbers (positive and/or negative) progressing from start up to, but not including end. + +```go +result := Range(4) +// [0, 1, 2, 3] + +result := Range(-4); +// [0, -1, -2, -3] + +result := RangeFrom(1, 5); +// [1, 2, 3, 4] + +result := RangeFrom[float64](1.0, 5); +// [1.0, 2.0, 3.0, 4.0] + +result := RangeWithSteps(0, 20, 5); +// [0, 5, 10, 15] + +result := RangeWithSteps[float32](-1.0, -4.0, -1.0); +// [-1.0, -2.0, -3.0] + +result := RangeWithSteps(1, 4, -1); +// [] + +result := Range(0); +// [] +``` + +For more advanced retry strategies (delay, exponential backoff...), please take a look on [cenkalti/backoff](https://github.com/cenkalti/backoff). + +## 馃洨 Benchmark + +We executed a simple benchmark with the a dead-simple `lo.Map` loop: + +See the full implementation [here](./benchmark_test.go). + +```go +_ = lo.Map[int64](arr, func(x int64, i int) string { + return strconv.FormatInt(x, 10) +}) +``` + +**Result:** + +Here is a comparison between `lo.Map`, `lop.Map`, `go-funk` library and a simple Go `for` loop. + +``` +$ go test -benchmem -bench ./... +goos: linux +goarch: amd64 +pkg: github.com/samber/lo +cpu: Intel(R) Core(TM) i5-7267U CPU @ 3.10GHz +cpu: Intel(R) Core(TM) i7 CPU 920 @ 2.67GHz +BenchmarkMap/lo.Map-8 8 132728237 ns/op 39998945 B/op 1000002 allocs/op +BenchmarkMap/lop.Map-8 2 503947830 ns/op 119999956 B/op 3000007 allocs/op +BenchmarkMap/reflect-8 2 826400560 ns/op 170326512 B/op 4000042 allocs/op +BenchmarkMap/for-8 9 126252954 ns/op 39998674 B/op 1000001 allocs/op +PASS +ok github.com/samber/lo 6.657s +``` + +- `lo.Map` is way faster (x7) than `go-funk`, a relection-based Map implementation. +- `lo.Map` have the same allocation profile than `for`. +- `lo.Map` is 4% slower than `for`. +- `lop.Map` is slower than `lo.Map` because it implies more memory allocation and locks. `lop.Map` will be usefull for long-running callbacks, such as i/o bound processing. +- `for` beats other implementations for memory and CPU. + +## 馃 Contributing + +- Ping me on twitter [@samuelberthe](https://twitter.com/samuelberthe) (DMs, mentions, whatever :)) +- Fork the [project](https://github.com/samber/lo) +- Fix [open issues](https://github.com/samber/lo/issues) or request new features + +Don't hesitate ;) + +### Install go 1.18 + +```bash +make go1.18beta1 +``` + +If your OS currently not default to Go 1.18, replace `BIN=go` by `BIN=go1.18beta1` in the Makefile. + +### With Docker + +```bash +docker-compose run --rm dev +``` + +### Without Docker + +```bash +# Install some dev dependencies +make tools + +# Run tests +make test +# or +make watch-test +``` + +## 馃懁 Authors + +- Samuel Berthe + +## 馃挮 Show your support + +Give a 猸愶笍 if this project helped you! + +[](https://www.patreon.com/samber) + +## 馃摑 License + +Copyright 漏 2022 [Samuel Berthe](https://github.com/samber). + +This project is [MIT](./LICENSE) licensed. diff --git a/vendor/github.com/samber/lo/condition.go b/vendor/github.com/samber/lo/condition.go new file mode 100644 index 000000000..2d9862cc5 --- /dev/null +++ b/vendor/github.com/samber/lo/condition.go @@ -0,0 +1,99 @@ +package lo + +// Ternary is a 1 line if/else statement. +func Ternary[T any](condition bool, ifOutput T, elseOutput T) T { + if condition { + return ifOutput + } + + return elseOutput +} + +type ifElse[T any] struct { + result T + done bool +} + +// If. +func If[T any](condition bool, result T) *ifElse[T] { + if condition { + return &ifElse[T]{result, true} + } + + var t T + return &ifElse[T]{t, false} +} + +// ElseIf. +func (i *ifElse[T]) ElseIf(condition bool, result T) *ifElse[T] { + if !i.done && condition { + i.result = result + i.done = true + } + + return i +} + +// Else. +func (i *ifElse[T]) Else(result T) T { + if i.done { + return i.result + } + + return result +} + +type switchCase[T comparable, R any] struct { + predicate T + result R + done bool +} + +// Switch is a pure functional switch/case/default statement. +func Switch[T comparable, R any](predicate T) *switchCase[T, R] { + var result R + + return &switchCase[T, R]{ + predicate, + result, + false, + } +} + +// Case. +func (s *switchCase[T, R]) Case(val T, result R) *switchCase[T, R] { + if !s.done && s.predicate == val { + s.result = result + s.done = true + } + + return s +} + +// CaseF. +func (s *switchCase[T, R]) CaseF(val T, cb func() R) *switchCase[T, R] { + if !s.done && s.predicate == val { + s.result = cb() + s.done = true + } + + return s +} + +// Default. +func (s *switchCase[T, R]) Default(result R) R { + if !s.done { + s.result = result + } + + return s.result +} + +// DefaultF. +func (s *switchCase[T, R]) DefaultF(cb func() R) R { + if !s.done { + s.result = cb() + } + + return s.result +} diff --git a/vendor/github.com/samber/lo/constraints.go b/vendor/github.com/samber/lo/constraints.go new file mode 100644 index 000000000..c1f352968 --- /dev/null +++ b/vendor/github.com/samber/lo/constraints.go @@ -0,0 +1,6 @@ +package lo + +// Clonable defines a constraint of types having Clone() T method. +type Clonable[T any] interface { + Clone() T +} diff --git a/vendor/github.com/samber/lo/docker-compose.yml b/vendor/github.com/samber/lo/docker-compose.yml new file mode 100644 index 000000000..c6f3f652b --- /dev/null +++ b/vendor/github.com/samber/lo/docker-compose.yml @@ -0,0 +1,9 @@ +version: '3' + +services: + dev: + build: . + volumes: + - ./:/go/src/github.com/samber/lo + working_dir: /go/src/github.com/samber/lo + command: bash -c 'make tools ; make watch-test' diff --git a/vendor/github.com/samber/lo/drop.go b/vendor/github.com/samber/lo/drop.go new file mode 100644 index 000000000..870b04aa3 --- /dev/null +++ b/vendor/github.com/samber/lo/drop.go @@ -0,0 +1,65 @@ +package lo + +//Drop drops n elements from the beginning of a slice or array. +func Drop[T any](collection []T, n int) []T { + if len(collection) <= n { + return make([]T, 0) + } + + result := make([]T, len(collection)-n) + for i := n; i < len(collection); i++ { + result[i-n] = collection[i] + } + + return result +} + +//DropWhile drops elements from the beginning of a slice or array while the predicate returns true. +func DropWhile[T any](collection []T, predicate func(T) bool) []T { + i := 0 + for ; i < len(collection); i++ { + if !predicate(collection[i]) { + break + } + } + + result := make([]T, len(collection)-i) + + for j := 0; i < len(collection); i, j = i+1, j+1 { + result[j] = collection[i] + } + + return result +} + +//DropRight drops n elements from the end of a slice or array. +func DropRight[T any](collection []T, n int) []T { + if len(collection) <= n { + return make([]T, 0) + } + + result := make([]T, len(collection)-n) + for i := len(collection) - 1 - n; i != 0; i-- { + result[i] = collection[i] + } + + return result +} + +//DropRightWhile drops elements from the end of a slice or array while the predicate returns true. +func DropRightWhile[T any](collection []T, predicate func(T) bool) []T { + i := len(collection) - 1 + for ; i >= 0; i-- { + if !predicate(collection[i]) { + break + } + } + + result := make([]T, i+1) + + for ; i >= 0; i-- { + result[i] = collection[i] + } + + return result +} diff --git a/vendor/github.com/samber/lo/find.go b/vendor/github.com/samber/lo/find.go new file mode 100644 index 000000000..e6d22ca05 --- /dev/null +++ b/vendor/github.com/samber/lo/find.go @@ -0,0 +1,157 @@ +package lo + +import ( + "fmt" + "math/rand" + "math" + "golang.org/x/exp/constraints" +) + +// import "golang.org/x/exp/constraints" + +// IndexOf returns the index at which the first occurrence of a value is found in an array or return -1 +// if the value cannot be found. +func IndexOf[T comparable](collection []T, element T) int { + for i, item := range collection { + if item == element { + return i + } + } + + return -1 +} + +// IndexOf returns the index at which the last occurrence of a value is found in an array or return -1 +// if the value cannot be found. +func LastIndexOf[T comparable](collection []T, element T) int { + length := len(collection) + + for i := length - 1; i >= 0; i-- { + if collection[i] == element { + return i + } + } + + return -1 +} + +// Find search an element in a slice based on a predicate. It returns element and true if element was found. +func Find[T any](collection []T, predicate func(T) bool) (T, bool) { + for _, item := range collection { + if predicate(item) { + return item, true + } + } + + var result T + return result, false +} + +// Min search the minimum value of a collection. +func Min[T constraints.Ordered](collection []T) T { + var min T + + if len(collection) == 0 { + return min + } + + min = collection[0] + + for i := 1; i < len(collection); i++ { + item := collection[i] + + // if item.Less(min) { + if item < min { + min = item + } + } + + return min +} + +// Max search the maximum value of a collection. +func Max[T constraints.Ordered](collection []T) T { + var max T + + if len(collection) == 0 { + return max + } + + max = collection[0] + + for i := 1; i < len(collection); i++ { + item := collection[i] + + if item > max { + max = item + } + } + + return max +} + +// Last returns the last element of a collection or error if empty. +func Last[T any](collection []T) (T, error) { + length := len(collection) + + if length == 0 { + var t T + return t, fmt.Errorf("last: cannot extract the last element of an empty slice") + } + + return collection[length-1], nil +} + +// Nth returns the element at index `nth` of collection. If `nth` is negative, the nth element +// from the end is returned. An error is returned when nth is out of slice bounds. +func Nth[T any](collection []T, nth int) (T, error) { + if int(math.Abs(float64(nth))) >= len(collection) { + var t T + return t, fmt.Errorf("nth: %d out of slice bounds", nth) + } + + length := len(collection) + + if nth >= 0 { + return collection[nth], nil + } + + return collection[length+nth], nil +} + +// Sample returns a random item from collection. +func Sample[T any](collection []T) T { + size := len(collection) + if size == 0 { + return Empty[T]() + } + + return collection[rand.Intn(size)] +} + +// Samples returns N random unique items from collection. +func Samples[T any](collection []T, count int) []T { + size := len(collection) + + // put values into a map, for faster deletion + cOpy := make([]T, 0, size) + for _, v := range collection { + cOpy = append(cOpy, v) + } + + results := []T{} + + for i := 0; i < size && i < count; i++ { + copyLength := size - i + + index := rand.Intn(size - i) + results = append(results, cOpy[index]) + + // Removes element. + // It is faster to swap with last element and remove it. + cOpy[index] = cOpy[copyLength-1] + cOpy = cOpy[:copyLength-1] + } + + return results +} diff --git a/vendor/github.com/samber/lo/intersect.go b/vendor/github.com/samber/lo/intersect.go new file mode 100644 index 000000000..f720d1a2f --- /dev/null +++ b/vendor/github.com/samber/lo/intersect.go @@ -0,0 +1,131 @@ +package lo + +// Contains returns true if an element is present in a collection. +func Contains[T comparable](collection []T, element T) bool { + for _, item := range collection { + if item == element { + return true + } + } + + return false +} + +// ContainsBy returns true if predicate function return true. +func ContainsBy[T any](collection []T, predicate func(T) bool) bool { + for _, item := range collection { + if predicate(item) { + return true + } + } + + return false +} + +// Every returns true if all elements of a subset are contained into a collection. +func Every[T comparable](collection []T, subset []T) bool { + for _, elem := range subset { + if !Contains(collection, elem) { + return false + } + } + + return true +} + +// Some returns true if at least 1 element of a subset is contained into a collection. +func Some[T comparable](collection []T, subset []T) bool { + for _, elem := range subset { + if Contains(collection, elem) { + return true + } + } + + return false +} + +// Intersect returns the intersection between two collections. +func Intersect[T comparable](list1 []T, list2 []T) []T { + result := []T{} + seen := map[T]struct{}{} + + for _, elem := range list1 { + seen[elem] = struct{}{} + } + + for _, elem := range list2 { + if _, ok := seen[elem]; ok { + result = append(result, elem) + } + } + + return result +} + +// Difference returns the difference between two collections. +// The first value is the collection of element absent of list2. +// The second value is the collection of element absent of list1. +func Difference[T comparable](list1 []T, list2 []T) ([]T, []T) { + left := []T{} + right := []T{} + + seenLeft := map[T]struct{}{} + seenRight := map[T]struct{}{} + + for _, elem := range list1 { + seenLeft[elem] = struct{}{} + } + + for _, elem := range list2 { + seenRight[elem] = struct{}{} + } + + for _, elem := range list1 { + if _, ok := seenRight[elem]; !ok { + left = append(left, elem) + } + } + + for _, elem := range list2 { + if _, ok := seenLeft[elem]; !ok { + right = append(right, elem) + } + } + + return left, right +} + +// Union returns all distinct elements from both collections. +// result returns will not change the order of elements relatively. +func Union[T comparable](list1 []T, list2 []T) []T { + result := []T{} + + seen := map[T]struct{}{} + hasAdd := map[T]struct{}{} + + for _, e := range list1 { + seen[e] = struct{}{} + } + + for _, e := range list2 { + seen[e] = struct{}{} + } + + for _, e := range list1 { + if _, ok := seen[e]; ok { + result = append(result, e) + hasAdd[e] = struct{}{} + } + } + + for _, e := range list2 { + if _, ok := hasAdd[e]; ok { + continue + } + if _, ok := seen[e]; ok { + result = append(result, e) + } + } + + return result +} diff --git a/vendor/github.com/samber/lo/map.go b/vendor/github.com/samber/lo/map.go new file mode 100644 index 000000000..92c77d8ba --- /dev/null +++ b/vendor/github.com/samber/lo/map.go @@ -0,0 +1,72 @@ +package lo + +// Keys creates an array of the map keys. +func Keys[K comparable, V any](in map[K]V) []K { + result := make([]K, 0, len(in)) + + for k, _ := range in { + result = append(result, k) + } + + return result +} + +// Values creates an array of the map values. +func Values[K comparable, V any](in map[K]V) []V { + result := make([]V, 0, len(in)) + + for _, v := range in { + result = append(result, v) + } + + return result +} + +// Entries transforms a map into array of key/value pairs. +func Entries[K comparable, V any](in map[K]V) []Entry[K, V] { + entries := make([]Entry[K, V], 0, len(in)) + + for k, v := range in { + entries = append(entries, Entry[K, V]{ + Key: k, + Value: v, + }) + } + + return entries +} + +// FromEntries transforms an array of key/value pairs into a map. +func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V { + out := map[K]V{} + + for _, v := range entries { + out[v.Key] = v.Value + } + + return out +} + +// Assign merges multiple maps from left to right. +func Assign[K comparable, V any](maps ...map[K]V) map[K]V { + out := map[K]V{} + + for _, m := range maps { + for k, v := range m { + out[k] = v + } + } + + return out +} + +// MapValues manipulates a map values and transforms it to a map of another type. +func MapValues[K comparable, V any, R any](in map[K]V, iteratee func(V, K) R) map[K]R { + result := map[K]R{} + + for k, v := range in { + result[k] = iteratee(v, k) + } + + return result +} \ No newline at end of file diff --git a/vendor/github.com/samber/lo/pointers.go b/vendor/github.com/samber/lo/pointers.go new file mode 100644 index 000000000..9c6f7fe33 --- /dev/null +++ b/vendor/github.com/samber/lo/pointers.go @@ -0,0 +1,19 @@ +package lo + +// ToPtr returns a pointer copy of value. +func ToPtr[T any](x T) *T { + return &x +} + +// ToPtr returns a slice of pointer copy of value. +func ToSlicePtr[T any](collection []T) []*T { + return Map(collection, func (x T, _ int) *T { + return &x + }) +} + +// Empty returns an empty value. +func Empty[T any]() T { + var t T + return t +} diff --git a/vendor/github.com/samber/lo/retry.go b/vendor/github.com/samber/lo/retry.go new file mode 100644 index 000000000..ebdb31d29 --- /dev/null +++ b/vendor/github.com/samber/lo/retry.go @@ -0,0 +1,19 @@ +package lo + +// Attempt invokes a function N times until it returns valid output. Returning either the caught error or nil. When first argument is less than `1`, the function runs until a sucessfull response is returned. +func Attempt(maxIteration int, f func(int) error) (int, error) { + var err error + + for i := 0; maxIteration <= 0 || i < maxIteration; i++ { + // for retries >= 0 { + err = f(i) + if err == nil { + return i + 1, nil + } + } + + return maxIteration, err +} + +// throttle ? +// debounce ? diff --git a/vendor/github.com/samber/lo/slice.go b/vendor/github.com/samber/lo/slice.go new file mode 100644 index 000000000..f5e989358 --- /dev/null +++ b/vendor/github.com/samber/lo/slice.go @@ -0,0 +1,242 @@ +package lo + +import ( + "math/rand" +) + +// Filter iterates over elements of collection, returning an array of all elements predicate returns truthy for. +func Filter[V any](collection []V, predicate func(V, int) bool) []V { + result := []V{} + + for i, item := range collection { + if predicate(item, i) { + result = append(result, item) + } + } + + return result +} + +// Map manipulates a slice and transforms it to a slice of another type. +func Map[T any, R any](collection []T, iteratee func(T, int) R) []R { + result := make([]R, len(collection)) + + for i, item := range collection { + result[i] = iteratee(item, i) + } + + return result +} + +// FlatMap manipulates a slice and transforms and flattens it to a slice of another type. +func FlatMap[T any, R any](collection []T, iteratee func(T, int) []R) []R { + result := []R{} + + for i, item := range collection { + result = append(result, iteratee(item, i)...) + } + + return result +} + +// Reduce reduces collection to a value which is the accumulated result of running each element in collection +// through accumulator, where each successive invocation is supplied the return value of the previous. +func Reduce[T any, R any](collection []T, accumulator func(R, T, int) R, initial R) R { + for i, item := range collection { + initial = accumulator(initial, item, i) + } + + return initial +} + +// ForEach iterates over elements of collection and invokes iteratee for each element. +func ForEach[T any](collection []T, iteratee func(T, int)) { + for i, item := range collection { + iteratee(item, i) + } +} + +// Times invokes the iteratee n times, returning an array of the results of each invocation. +// The iteratee is invoked with index as argument. +func Times[T any](count int, iteratee func(int) T) []T { + result := make([]T, count) + + for i := 0; i < count; i++ { + result[i] = iteratee(i) + } + + return result +} + +// Uniq returns a duplicate-free version of an array, in which only the first occurrence of each element is kept. +// The order of result values is determined by the order they occur in the array. +func Uniq[T comparable](collection []T) []T { + result := make([]T, 0, len(collection)) + seen := make(map[T]struct{}, len(collection)) + + for _, item := range collection { + if _, ok := seen[item]; ok { + continue + } + + seen[item] = struct{}{} + result = append(result, item) + } + + return result +} + +// Uniq returns a duplicate-free version of an array, in which only the first occurrence of each element is kept. +// The order of result values is determined by the order they occur in the array. It accepts `iteratee` which is +// invoked for each element in array to generate the criterion by which uniqueness is computed. +func UniqBy[T any, U comparable](collection []T, iteratee func(T) U) []T { + result := make([]T, 0, len(collection)) + seen := make(map[U]struct{}, len(collection)) + + for _, item := range collection { + key := iteratee(item) + + if _, ok := seen[key]; ok { + continue + } + + seen[key] = struct{}{} + result = append(result, item) + } + + return result +} + +// GroupBy returns an object composed of keys generated from the results of running each element of collection through iteratee. +func GroupBy[T any, U comparable](collection []T, iteratee func(T) U) map[U][]T { + result := map[U][]T{} + + for _, item := range collection { + key := iteratee(item) + + if _, ok := result[key]; !ok { + result[key] = []T{} + } + + result[key] = append(result[key], item) + } + + return result +} + +// Chunk returns an array of elements split into groups the length of size. If array can't be split evenly, +// the final chunk will be the remaining elements. +func Chunk[T any](collection []T, size int) [][]T { + if size <= 0 { + panic("Second parameter must be greater than 0") + } + + result := make([][]T, 0, len(collection)/2+1) + length := len(collection) + + for i := 0; i < length; i++ { + chunk := i / size + + if i%size == 0 { + result = append(result, make([]T, 0, size)) + } + + result[chunk] = append(result[chunk], collection[i]) + } + + return result +} + +// PartitionBy returns an array of elements split into groups. The order of grouped values is +// determined by the order they occur in collection. The grouping is generated from the results +// of running each element of collection through iteratee. +func PartitionBy[T any, K comparable](collection []T, iteratee func(x T) K) [][]T { + result := [][]T{} + seen := map[K]int{} + + for _, item := range collection { + key := iteratee(item) + + resultIndex, ok := seen[key] + if !ok { + resultIndex = len(result) + seen[key] = resultIndex + result = append(result, []T{}) + } + + result[resultIndex] = append(result[resultIndex], item) + } + + return result + + // unordered: + // groups := GroupBy[T, K](collection, iteratee) + // return Values[K, []T](groups) +} + +// Flattens returns an array a single level deep. +func Flatten[T any](collection [][]T) []T { + result := []T{} + + for _, item := range collection { + result = append(result, item...) + } + + return result +} + +// Shuffle returns an array of shuffled values. Uses the Fisher-Yates shuffle algorithm. +func Shuffle[T any](collection []T) []T { + rand.Shuffle(len(collection), func(i, j int) { + collection[i], collection[j] = collection[j], collection[i] + }) + + return collection +} + +// Reverse reverses array so that the first element becomes the last, the second element becomes the second to last, and so on. +func Reverse[T any](collection []T) []T { + length := len(collection) + half := length / 2 + + for i := 0; i < half; i = i + 1 { + j := length - 1 - i + collection[i], collection[j] = collection[j], collection[i] + } + + return collection +} + +// Fill fills elements of array with `initial` value. +func Fill[T Clonable[T]](collection []T, initial T) []T { + result := make([]T, 0, len(collection)) + + for _ = range collection { + result = append(result, initial.Clone()) + } + + return result +} + +// Repeat builds a slice with N copies of initial value. +func Repeat[T Clonable[T]](count int, initial T) []T { + result := make([]T, 0, count) + + for i := 0; i < count; i++ { + result = append(result, initial.Clone()) + } + + return result +} + +// KeyBy transforms a slice or an array of structs to a map based on a pivot callback. +func KeyBy[K comparable, V any](collection []V, iteratee func(V) K) map[K]V { + result := make(map[K]V, len(collection)) + + for _, v := range collection { + k := iteratee(v) + result[k] = v + } + + return result +} diff --git a/vendor/github.com/samber/lo/tuples.go b/vendor/github.com/samber/lo/tuples.go new file mode 100644 index 000000000..6439952b8 --- /dev/null +++ b/vendor/github.com/samber/lo/tuples.go @@ -0,0 +1,413 @@ +package lo + +func longestCollection(collections ...[]interface{}) int { + max := 0 + + for _, collection := range collections { + if len(collection) > max { + max = len(collection) + } + } + + return max +} + +// Zip2 creates a slice of grouped elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func Zip2[A any, B any](a []A, b []B) []Tuple2[A, B] { + size := Max[int]([]int{len(a), len(b)}) + + result := make([]Tuple2[A, B], 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth[A](a, index) + _b, _ := Nth[B](b, index) + + result = append(result, Tuple2[A, B]{ + A: _a, + B: _b, + }) + } + + return result +} + +// Zip3 creates a slice of grouped elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func Zip3[A any, B any, C any](a []A, b []B, c []C) []Tuple3[A, B, C] { + size := Max[int]([]int{len(a), len(b), len(c)}) + + result := make([]Tuple3[A, B, C], 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth[A](a, index) + _b, _ := Nth[B](b, index) + _c, _ := Nth[C](c, index) + + result = append(result, Tuple3[A, B, C]{ + A: _a, + B: _b, + C: _c, + }) + } + + return result +} + +// Zip4 creates a slice of grouped elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func Zip4[A any, B any, C any, D any](a []A, b []B, c []C, d []D) []Tuple4[A, B, C, D] { + size := Max[int]([]int{len(a), len(b), len(c), len(d)}) + + result := make([]Tuple4[A, B, C, D], 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth[A](a, index) + _b, _ := Nth[B](b, index) + _c, _ := Nth[C](c, index) + _d, _ := Nth[D](d, index) + + result = append(result, Tuple4[A, B, C, D]{ + A: _a, + B: _b, + C: _c, + D: _d, + }) + } + + return result +} + +// Zip5 creates a slice of grouped elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func Zip5[A any, B any, C any, D any, E any](a []A, b []B, c []C, d []D, e []E) []Tuple5[A, B, C, D, E] { + size := Max[int]([]int{len(a), len(b), len(c), len(d), len(e)}) + + result := make([]Tuple5[A, B, C, D, E], 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth[A](a, index) + _b, _ := Nth[B](b, index) + _c, _ := Nth[C](c, index) + _d, _ := Nth[D](d, index) + _e, _ := Nth[E](e, index) + + result = append(result, Tuple5[A, B, C, D, E]{ + A: _a, + B: _b, + C: _c, + D: _d, + E: _e, + }) + } + + return result +} + +// Zip6 creates a slice of grouped elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func Zip6[A any, B any, C any, D any, E any, F any](a []A, b []B, c []C, d []D, e []E, f []F) []Tuple6[A, B, C, D, E, F] { + size := Max[int]([]int{len(a), len(b), len(c), len(d), len(e), len(f)}) + + result := make([]Tuple6[A, B, C, D, E, F], 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth[A](a, index) + _b, _ := Nth[B](b, index) + _c, _ := Nth[C](c, index) + _d, _ := Nth[D](d, index) + _e, _ := Nth[E](e, index) + _f, _ := Nth[F](f, index) + + result = append(result, Tuple6[A, B, C, D, E, F]{ + A: _a, + B: _b, + C: _c, + D: _d, + E: _e, + F: _f, + }) + } + + return result +} + +// Zip7 creates a slice of grouped elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func Zip7[A any, B any, C any, D any, E any, F any, G any](a []A, b []B, c []C, d []D, e []E, f []F, g []G) []Tuple7[A, B, C, D, E, F, G] { + size := Max[int]([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g)}) + + result := make([]Tuple7[A, B, C, D, E, F, G], 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth[A](a, index) + _b, _ := Nth[B](b, index) + _c, _ := Nth[C](c, index) + _d, _ := Nth[D](d, index) + _e, _ := Nth[E](e, index) + _f, _ := Nth[F](f, index) + _g, _ := Nth[G](g, index) + + result = append(result, Tuple7[A, B, C, D, E, F, G]{ + A: _a, + B: _b, + C: _c, + D: _d, + E: _e, + F: _f, + G: _g, + }) + } + + return result +} + +// Zip8 creates a slice of grouped elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func Zip8[A any, B any, C any, D any, E any, F any, G any, H any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H) []Tuple8[A, B, C, D, E, F, G, H] { + size := Max[int]([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h)}) + + result := make([]Tuple8[A, B, C, D, E, F, G, H], 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth[A](a, index) + _b, _ := Nth[B](b, index) + _c, _ := Nth[C](c, index) + _d, _ := Nth[D](d, index) + _e, _ := Nth[E](e, index) + _f, _ := Nth[F](f, index) + _g, _ := Nth[G](g, index) + _h, _ := Nth[H](h, index) + + result = append(result, Tuple8[A, B, C, D, E, F, G, H]{ + A: _a, + B: _b, + C: _c, + D: _d, + E: _e, + F: _f, + G: _g, + H: _h, + }) + } + + return result +} + +// Zip9 creates a slice of grouped elements, the first of which contains the first elements +// of the given arrays, the second of which contains the second elements of the given arrays, and so on. +// When collections have different size, the Tuple attributes are filled with zero value. +func Zip9[A any, B any, C any, D any, E any, F any, G any, H any, I any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, i []I) []Tuple9[A, B, C, D, E, F, G, H, I] { + size := Max[int]([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h), len(i)}) + + result := make([]Tuple9[A, B, C, D, E, F, G, H, I], 0, size) + + for index := 0; index < size; index++ { + _a, _ := Nth[A](a, index) + _b, _ := Nth[B](b, index) + _c, _ := Nth[C](c, index) + _d, _ := Nth[D](d, index) + _e, _ := Nth[E](e, index) + _f, _ := Nth[F](f, index) + _g, _ := Nth[G](g, index) + _h, _ := Nth[H](h, index) + _i, _ := Nth[I](i, index) + + result = append(result, Tuple9[A, B, C, D, E, F, G, H, I]{ + A: _a, + B: _b, + C: _c, + D: _d, + E: _e, + F: _f, + G: _g, + H: _h, + I: _i, + }) + } + + return result +} + +// Unzip2 accepts an array of grouped elements and creates an array regrouping the elements +// to their pre-zip configuration. +func Unzip2[A any, B any](tuples []Tuple2[A, B]) ([]A, []B) { + size := len(tuples) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + + for _, tuple := range tuples { + r1 = append(r1, tuple.A) + r2 = append(r2, tuple.B) + } + + return r1, r2 +} + +// Unzip3 accepts an array of grouped elements and creates an array regrouping the elements +// to their pre-zip configuration. +func Unzip3[A any, B any, C any](tuples []Tuple3[A, B, C]) ([]A, []B, []C) { + size := len(tuples) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + + for _, tuple := range tuples { + r1 = append(r1, tuple.A) + r2 = append(r2, tuple.B) + r3 = append(r3, tuple.C) + } + + return r1, r2, r3 +} + +// Unzip4 accepts an array of grouped elements and creates an array regrouping the elements +// to their pre-zip configuration. +func Unzip4[A any, B any, C any, D any](tuples []Tuple4[A, B, C, D]) ([]A, []B, []C, []D) { + size := len(tuples) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + r4 := make([]D, 0, size) + + for _, tuple := range tuples { + r1 = append(r1, tuple.A) + r2 = append(r2, tuple.B) + r3 = append(r3, tuple.C) + r4 = append(r4, tuple.D) + } + + return r1, r2, r3, r4 +} + +// Unzip5 accepts an array of grouped elements and creates an array regrouping the elements +// to their pre-zip configuration. +func Unzip5[A any, B any, C any, D any, E any](tuples []Tuple5[A, B, C, D, E]) ([]A, []B, []C, []D, []E) { + size := len(tuples) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + r4 := make([]D, 0, size) + r5 := make([]E, 0, size) + + for _, tuple := range tuples { + r1 = append(r1, tuple.A) + r2 = append(r2, tuple.B) + r3 = append(r3, tuple.C) + r4 = append(r4, tuple.D) + r5 = append(r5, tuple.E) + } + + return r1, r2, r3, r4, r5 +} + +// Unzip6 accepts an array of grouped elements and creates an array regrouping the elements +// to their pre-zip configuration. +func Unzip6[A any, B any, C any, D any, E any, F any](tuples []Tuple6[A, B, C, D, E, F]) ([]A, []B, []C, []D, []E, []F) { + size := len(tuples) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + r4 := make([]D, 0, size) + r5 := make([]E, 0, size) + r6 := make([]F, 0, size) + + for _, tuple := range tuples { + r1 = append(r1, tuple.A) + r2 = append(r2, tuple.B) + r3 = append(r3, tuple.C) + r4 = append(r4, tuple.D) + r5 = append(r5, tuple.E) + r6 = append(r6, tuple.F) + } + + return r1, r2, r3, r4, r5, r6 +} + +// Unzip7 accepts an array of grouped elements and creates an array regrouping the elements +// to their pre-zip configuration. +func Unzip7[A any, B any, C any, D any, E any, F any, G any](tuples []Tuple7[A, B, C, D, E, F, G]) ([]A, []B, []C, []D, []E, []F, []G) { + size := len(tuples) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + r4 := make([]D, 0, size) + r5 := make([]E, 0, size) + r6 := make([]F, 0, size) + r7 := make([]G, 0, size) + + for _, tuple := range tuples { + r1 = append(r1, tuple.A) + r2 = append(r2, tuple.B) + r3 = append(r3, tuple.C) + r4 = append(r4, tuple.D) + r5 = append(r5, tuple.E) + r6 = append(r6, tuple.F) + r7 = append(r7, tuple.G) + } + + return r1, r2, r3, r4, r5, r6, r7 +} + +// Unzip8 accepts an array of grouped elements and creates an array regrouping the elements +// to their pre-zip configuration. +func Unzip8[A any, B any, C any, D any, E any, F any, G any, H any](tuples []Tuple8[A, B, C, D, E, F, G, H]) ([]A, []B, []C, []D, []E, []F, []G, []H) { + size := len(tuples) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + r4 := make([]D, 0, size) + r5 := make([]E, 0, size) + r6 := make([]F, 0, size) + r7 := make([]G, 0, size) + r8 := make([]H, 0, size) + + for _, tuple := range tuples { + r1 = append(r1, tuple.A) + r2 = append(r2, tuple.B) + r3 = append(r3, tuple.C) + r4 = append(r4, tuple.D) + r5 = append(r5, tuple.E) + r6 = append(r6, tuple.F) + r7 = append(r7, tuple.G) + r8 = append(r8, tuple.H) + } + + return r1, r2, r3, r4, r5, r6, r7, r8 +} + +// Unzip9 accepts an array of grouped elements and creates an array regrouping the elements +// to their pre-zip configuration. +func Unzip9[A any, B any, C any, D any, E any, F any, G any, H any, I any](tuples []Tuple9[A, B, C, D, E, F, G, H, I]) ([]A, []B, []C, []D, []E, []F, []G, []H, []I) { + size := len(tuples) + r1 := make([]A, 0, size) + r2 := make([]B, 0, size) + r3 := make([]C, 0, size) + r4 := make([]D, 0, size) + r5 := make([]E, 0, size) + r6 := make([]F, 0, size) + r7 := make([]G, 0, size) + r8 := make([]H, 0, size) + r9 := make([]I, 0, size) + + for _, tuple := range tuples { + r1 = append(r1, tuple.A) + r2 = append(r2, tuple.B) + r3 = append(r3, tuple.C) + r4 = append(r4, tuple.D) + r5 = append(r5, tuple.E) + r6 = append(r6, tuple.F) + r7 = append(r7, tuple.G) + r8 = append(r8, tuple.H) + r9 = append(r9, tuple.I) + } + + return r1, r2, r3, r4, r5, r6, r7, r8, r9 +} diff --git a/vendor/github.com/samber/lo/types.go b/vendor/github.com/samber/lo/types.go new file mode 100644 index 000000000..5361a02a1 --- /dev/null +++ b/vendor/github.com/samber/lo/types.go @@ -0,0 +1,83 @@ +package lo + +// Entry defines a key/value pairs. +type Entry[K comparable, V any] struct { + Key K + Value V +} + +// Tuple2 is a group of 2 elements (pair). +type Tuple2[A any, B any] struct { + A A + B B +} + +// Tuple3 is a group of 3 elements. +type Tuple3[A any, B any, C any] struct { + A A + B B + C C +} + +// Tuple4 is a group of 4 elements. +type Tuple4[A any, B any, C any, D any] struct { + A A + B B + C C + D D +} + +// Tuple5 is a group of 5 elements. +type Tuple5[A any, B any, C any, D any, E any] struct { + A A + B B + C C + D D + E E +} + +// Tuple6 is a group of 6 elements. +type Tuple6[A any, B any, C any, D any, E any, F any] struct { + A A + B B + C C + D D + E E + F F +} + +// Tuple7 is a group of 7 elements. +type Tuple7[A any, B any, C any, D any, E any, F any, G any] struct { + A A + B B + C C + D D + E E + F F + G G +} + +// Tuple8 is a group of 8 elements. +type Tuple8[A any, B any, C any, D any, E any, F any, G any, H any] struct { + A A + B B + C C + D D + E E + F F + G G + H H +} + +// Tuple9 is a group of 9 elements. +type Tuple9[A any, B any, C any, D any, E any, F any, G any, H any, I any] struct { + A A + B B + C C + D D + E E + F F + G G + H H + I I +} diff --git a/vendor/github.com/samber/lo/util.go b/vendor/github.com/samber/lo/util.go new file mode 100644 index 000000000..41ca9c80c --- /dev/null +++ b/vendor/github.com/samber/lo/util.go @@ -0,0 +1,50 @@ +package lo + +import "golang.org/x/exp/constraints" + +// Range creates an array of numbers (positive and/or negative) with given length. +func Range(elementNum int) []int { + length := If(elementNum < 0, -elementNum).Else(elementNum) + result := make([]int, length) + step := If(elementNum < 0, -1).Else(1) + for i, j := 0, 0; i < length; i, j = i+1, j+step { + result[i] = j + } + return result +} + +// RangeFrom creates an array of numbers from start with specified length. +func RangeFrom[T constraints.Integer | constraints.Float](start T, elementNum int) []T { + length := If(elementNum < 0, -elementNum).Else(elementNum) + result := make([]T, length) + step := If(elementNum < 0, -1).Else(1) + for i, j := 0, start; i < length; i, j = i+1, j+T(step) { + result[i] = j + } + return result +} + +// RangeWithSteps creates an array of numbers (positive and/or negative) progressing from start up to, but not including end. +// step set to zero will return empty array. +func RangeWithSteps[T constraints.Integer | constraints.Float](start, end, step T) []T { + result := []T{} + if start == end || step == 0 { + return result + } + if start < end { + if step < 0 { + return result + } + for i := start; i < end; i += step { + result = append(result, i) + } + return result + } + if step > 0 { + return result + } + for i := start; i > end; i += step { + result = append(result, i) + } + return result +} diff --git a/vendor/modules.txt b/vendor/modules.txt index f24c14661..6dc01e5ab 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -120,6 +120,11 @@ github.com/integrii/flaggy # github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 ## explicit github.com/jbenet/go-context/io +# github.com/jesseduffield/generics v0.0.0-20220318214805-3397e5e19e9f +## explicit; go 1.18 +github.com/jesseduffield/generics/hashmap +github.com/jesseduffield/generics/list +github.com/jesseduffield/generics/set # github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 ## explicit; go 1.13 github.com/jesseduffield/go-git/v5 @@ -221,6 +226,9 @@ github.com/rivo/uniseg # github.com/sahilm/fuzzy v0.1.0 ## explicit github.com/sahilm/fuzzy +# github.com/samber/lo v1.10.1 +## explicit; go 1.18 +github.com/samber/lo # github.com/sanity-io/litter v1.5.2 ## explicit; go 1.14 github.com/sanity-io/litter From eda8f4a5d4302691d99efd066f9851809c984bc0 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 19 Mar 2022 15:36:46 +1100 Subject: [PATCH 114/385] lots more generics --- go.mod | 4 +- go.sum | 4 +- pkg/cheatsheet/generate.go | 8 +- .../hosting_service/hosting_service.go | 2 +- pkg/commands/loaders/branches.go | 19 +-- pkg/commands/loaders/remotes.go | 25 ++- pkg/gui/controllers/global_controller.go | 4 +- .../controllers/helpers/cherry_pick_helper.go | 13 +- pkg/gui/filetree/inode.go | 16 +- pkg/gui/presentation/graph/graph.go | 10 +- .../generics/list/comparable_list.go | 49 ------ .../jesseduffield/generics/list/functions.go | 72 -------- .../jesseduffield/generics/list/list.go | 117 ------------- .../{hashmap/functions.go => maps/maps.go} | 2 +- .../jesseduffield/generics/set/set.go | 4 +- .../generics/slices/delegated_slices.go | 117 +++++++++++++ .../generics/slices/delegated_sort.go | 57 +++++++ .../jesseduffield/generics/slices/slices.go | 154 ++++++++++++++++++ vendor/modules.txt | 6 +- 19 files changed, 384 insertions(+), 299 deletions(-) delete mode 100644 vendor/github.com/jesseduffield/generics/list/comparable_list.go delete mode 100644 vendor/github.com/jesseduffield/generics/list/functions.go delete mode 100644 vendor/github.com/jesseduffield/generics/list/list.go rename vendor/github.com/jesseduffield/generics/{hashmap/functions.go => maps/maps.go} (98%) create mode 100644 vendor/github.com/jesseduffield/generics/slices/delegated_slices.go create mode 100644 vendor/github.com/jesseduffield/generics/slices/delegated_sort.go create mode 100644 vendor/github.com/jesseduffield/generics/slices/slices.go diff --git a/go.mod b/go.mod index afdf377ed..d966c20da 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gookit/color v1.4.2 github.com/imdario/mergo v0.3.11 github.com/integrii/flaggy v1.4.0 - github.com/jesseduffield/generics v0.0.0-20220318214805-3397e5e19e9f + github.com/jesseduffield/generics v0.0.0-20220319042131-63614a800d5f github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e @@ -32,7 +32,6 @@ require ( github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad github.com/stretchr/testify v1.7.0 github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 - golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0 ) @@ -61,6 +60,7 @@ require ( github.com/sergi/go-diff v1.1.0 // indirect github.com/xanzy/ssh-agent v0.2.1 // indirect golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // indirect + golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 // indirect golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c // indirect golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect diff --git a/go.sum b/go.sum index c06b0aef1..fe8e252ac 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jesseduffield/generics v0.0.0-20220318214805-3397e5e19e9f h1:9USuZttmg5ioHsjFyXboiGSbncpAqcKkq9qb4ga5PD0= -github.com/jesseduffield/generics v0.0.0-20220318214805-3397e5e19e9f/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= +github.com/jesseduffield/generics v0.0.0-20220319042131-63614a800d5f h1:VZkNxrfkR344djm4Ju7QuKLXxZlaaOaNCrAWVRc1gvU= +github.com/jesseduffield/generics v0.0.0-20220319042131-63614a800d5f/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 h1:9N08i5kjvOfkzMj6THmIM110wPTQLdVYEOHMHT2DFiI= diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index c7c2b0d37..d88f3d733 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -12,8 +12,8 @@ import ( "fmt" "log" "os" - "sort" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/app" "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui" @@ -180,9 +180,9 @@ outer: groupedBindings = append(groupedBindings, groupedBindingsType{contextAndView: contextAndView, bindings: contextBindings}) } - sort.Slice(groupedBindings, func(i, j int) bool { - first := groupedBindings[i].contextAndView - second := groupedBindings[j].contextAndView + slices.SortFunc(groupedBindings, func(a, b groupedBindingsType) bool { + first := a.contextAndView + second := b.contextAndView if first.title == "" { return true } diff --git a/pkg/commands/hosting_service/hosting_service.go b/pkg/commands/hosting_service/hosting_service.go index b448e3925..15fc244ba 100644 --- a/pkg/commands/hosting_service/hosting_service.go +++ b/pkg/commands/hosting_service/hosting_service.go @@ -10,7 +10,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/utils" "github.com/sirupsen/logrus" - "golang.org/x/exp/slices" + "github.com/jesseduffield/generics/slices" ) // This package is for handling logic specific to a git hosting service like github, gitlab, bitbucket, etc. diff --git a/pkg/commands/loaders/branches.go b/pkg/commands/loaders/branches.go index 9fa1e80f4..90480ca9a 100644 --- a/pkg/commands/loaders/branches.go +++ b/pkg/commands/loaders/branches.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/jesseduffield/generics/set" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/go-git/v5/config" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/common" @@ -78,8 +79,7 @@ outer: if branch.Head { foundHead = true branch.Recency = " *" - branches = append(branches[0:i], branches[i+1:]...) - branches = append([]*models.Branch{branch}, branches...) + branches = slices.Move(branches, i, 0) break } } @@ -88,7 +88,7 @@ outer: if err != nil { return nil, err } - branches = append([]*models.Branch{{Name: currentBranchName, DisplayName: currentBranchDisplayName, Head: true, Recency: " *"}}, branches...) + branches = slices.Prepend(branches, &models.Branch{Name: currentBranchName, DisplayName: currentBranchDisplayName, Head: true, Recency: " *"}) } configBranches, err := self.config.Branches() @@ -158,10 +158,10 @@ func (self *BranchLoader) obtainBranches() []*models.Branch { trimmedOutput := strings.TrimSpace(output) outputLines := strings.Split(trimmedOutput, "\n") - branches := make([]*models.Branch, 0, len(outputLines)) - for _, line := range outputLines { + + branches := slices.FilterMap(outputLines, func(line string) (*models.Branch, bool) { if line == "" { - continue + return nil, false } split := strings.Split(line, SEPARATION_CHAR) @@ -169,12 +169,11 @@ func (self *BranchLoader) obtainBranches() []*models.Branch { // Ignore line if it isn't separated into 4 parts // This is probably a warning message, for more info see: // https://github.com/jesseduffield/lazygit/issues/1385#issuecomment-885580439 - continue + return nil, false } - branch := obtainBranch(split) - branches = append(branches, branch) - } + return obtainBranch(split), true + }) return branches } diff --git a/pkg/commands/loaders/remotes.go b/pkg/commands/loaders/remotes.go index bd1fe0b6a..3cd57d9a2 100644 --- a/pkg/commands/loaders/remotes.go +++ b/pkg/commands/loaders/remotes.go @@ -3,13 +3,14 @@ package loaders import ( "fmt" "regexp" - "sort" "strings" + "github.com/jesseduffield/generics/slices" gogit "github.com/jesseduffield/go-git/v5" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/common" + "github.com/samber/lo" ) type RemoteLoader struct { @@ -42,37 +43,35 @@ func (self *RemoteLoader) GetRemotes() ([]*models.Remote, error) { } // first step is to get our remotes from go-git - remotes := make([]*models.Remote, len(goGitRemotes)) - for i, goGitRemote := range goGitRemotes { + remotes := lo.Map(goGitRemotes, func(goGitRemote *gogit.Remote, _ int) *models.Remote { remoteName := goGitRemote.Config().Name re := regexp.MustCompile(fmt.Sprintf(`(?m)^\s*%s\/([\S]+)`, remoteName)) matches := re.FindAllStringSubmatch(remoteBranchesStr, -1) - branches := make([]*models.RemoteBranch, len(matches)) - for j, match := range matches { - branches[j] = &models.RemoteBranch{ + branches := lo.Map(matches, func(match []string, _ int) *models.RemoteBranch { + return &models.RemoteBranch{ Name: match[1], RemoteName: remoteName, } - } + }) - remotes[i] = &models.Remote{ + return &models.Remote{ Name: goGitRemote.Config().Name, Urls: goGitRemote.Config().URLs, Branches: branches, } - } + }) // now lets sort our remotes by name alphabetically - sort.Slice(remotes, func(i, j int) bool { + slices.SortFunc(remotes, func(a, b *models.Remote) bool { // we want origin at the top because we'll be most likely to want it - if remotes[i].Name == "origin" { + if a.Name == "origin" { return true } - if remotes[j].Name == "origin" { + if b.Name == "origin" { return false } - return strings.ToLower(remotes[i].Name) < strings.ToLower(remotes[j].Name) + return strings.ToLower(a.Name) < strings.ToLower(b.Name) }) return remotes, nil diff --git a/pkg/gui/controllers/global_controller.go b/pkg/gui/controllers/global_controller.go index c45e98d85..e59231739 100644 --- a/pkg/gui/controllers/global_controller.go +++ b/pkg/gui/controllers/global_controller.go @@ -1,7 +1,7 @@ package controllers import ( - "github.com/jesseduffield/generics/list" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -57,7 +57,7 @@ func (self *GlobalController) customCommand() error { func (self *GlobalController) GetCustomCommandsHistorySuggestionsFunc() func(string) []*types.Suggestion { // reversing so that we display the latest command first - history := list.Reverse(self.c.GetAppState().CustomCommandsHistory) + history := slices.Reverse(self.c.GetAppState().CustomCommandsHistory) return helpers.FuzzySearchFunc(history) } diff --git a/pkg/gui/controllers/helpers/cherry_pick_helper.go b/pkg/gui/controllers/helpers/cherry_pick_helper.go index e4a9b3e81..c433655d0 100644 --- a/pkg/gui/controllers/helpers/cherry_pick_helper.go +++ b/pkg/gui/controllers/helpers/cherry_pick_helper.go @@ -2,6 +2,7 @@ package helpers import ( "github.com/jesseduffield/generics/set" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" @@ -118,12 +119,12 @@ func (self *CherryPickHelper) add(selectedCommit *models.Commit, commitsList []* commitSet := self.CherryPickedCommitShaSet() commitSet.Add(selectedCommit.Sha) - commitsInSet := lo.Filter(commitsList, func(commit *models.Commit, _ int) bool { - return commitSet.Includes(commit.Sha) - }) - newCommits := lo.Map(commitsInSet, func(commit *models.Commit, _ int) *models.Commit { - return &models.Commit{Name: commit.Name, Sha: commit.Sha} - }) + newCommits := slices.FilterThenMap(commitsList, + func(commit *models.Commit) bool { return commitSet.Includes(commit.Sha) }, + func(commit *models.Commit) *models.Commit { + return &models.Commit{Name: commit.Name, Sha: commit.Sha} + }, + ) self.getData().CherryPickedCommits = newCommits } diff --git a/pkg/gui/filetree/inode.go b/pkg/gui/filetree/inode.go index 7c8b9fb75..48cdc3be3 100644 --- a/pkg/gui/filetree/inode.go +++ b/pkg/gui/filetree/inode.go @@ -1,8 +1,6 @@ package filetree -import ( - "sort" -) +import "github.com/jesseduffield/generics/slices" type INode interface { IsNil() bool @@ -27,19 +25,17 @@ func sortChildren(node INode) { return } - children := node.GetChildren() - sortedChildren := make([]INode, len(children)) - copy(sortedChildren, children) + sortedChildren := slices.Clone(node.GetChildren()) - sort.Slice(sortedChildren, func(i, j int) bool { - if !sortedChildren[i].IsLeaf() && sortedChildren[j].IsLeaf() { + slices.SortFunc(sortedChildren, func(a, b INode) bool { + if !a.IsLeaf() && b.IsLeaf() { return true } - if sortedChildren[i].IsLeaf() && !sortedChildren[j].IsLeaf() { + if a.IsLeaf() && !b.IsLeaf() { return false } - return sortedChildren[i].GetPath() < sortedChildren[j].GetPath() + return a.GetPath() < b.GetPath() }) // TODO: think about making this in-place diff --git a/pkg/gui/presentation/graph/graph.go b/pkg/gui/presentation/graph/graph.go index 0e193cba8..70ab53079 100644 --- a/pkg/gui/presentation/graph/graph.go +++ b/pkg/gui/presentation/graph/graph.go @@ -2,10 +2,10 @@ package graph import ( "runtime" - "sort" "strings" "sync" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/utils" @@ -265,11 +265,11 @@ func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *mod } // not efficient but doing it for now: sorting my pipes by toPos, then by kind - sort.Slice(newPipes, func(i, j int) bool { - if newPipes[i].toPos == newPipes[j].toPos { - return newPipes[i].kind < newPipes[j].kind + slices.SortFunc(newPipes, func(a, b *Pipe) bool { + if a.toPos == b.toPos { + return a.kind < b.kind } - return newPipes[i].toPos < newPipes[j].toPos + return a.toPos < b.toPos }) return newPipes diff --git a/vendor/github.com/jesseduffield/generics/list/comparable_list.go b/vendor/github.com/jesseduffield/generics/list/comparable_list.go deleted file mode 100644 index 21d56a80b..000000000 --- a/vendor/github.com/jesseduffield/generics/list/comparable_list.go +++ /dev/null @@ -1,49 +0,0 @@ -package list - -import ( - "golang.org/x/exp/slices" -) - -type ComparableList[T comparable] struct { - *List[T] -} - -func NewComparable[T comparable]() *ComparableList[T] { - return &ComparableList[T]{List: New[T]()} -} - -func NewComparableFromSlice[T comparable](slice []T) *ComparableList[T] { - return &ComparableList[T]{List: NewFromSlice(slice)} -} - -func (l *ComparableList[T]) Equal(other *ComparableList[T]) bool { - return l.EqualSlice(other.ToSlice()) -} - -func (l *ComparableList[T]) EqualSlice(other []T) bool { - return slices.Equal(l.ToSlice(), other) -} - -func (l *ComparableList[T]) Compact() { - l.slice = slices.Compact(l.slice) -} - -func (l *ComparableList[T]) Index(needle T) int { - return slices.Index(l.slice, needle) -} - -func (l *ComparableList[T]) Contains(needle T) bool { - return slices.Contains(l.slice, needle) -} - -func (l *ComparableList[T]) SortFuncInPlace(test func(a T, b T) bool) { - slices.SortFunc(l.slice, test) -} - -func (l *ComparableList[T]) SortFunc(test func(a T, b T) bool) *ComparableList[T] { - newSlice := slices.Clone(l.slice) - - slices.SortFunc(newSlice, test) - - return NewComparableFromSlice(newSlice) -} diff --git a/vendor/github.com/jesseduffield/generics/list/functions.go b/vendor/github.com/jesseduffield/generics/list/functions.go deleted file mode 100644 index 21578b82f..000000000 --- a/vendor/github.com/jesseduffield/generics/list/functions.go +++ /dev/null @@ -1,72 +0,0 @@ -package list - -func Some[T any](slice []T, test func(T) bool) bool { - for _, value := range slice { - if test(value) { - return true - } - } - - return false -} - -func Every[T any](slice []T, test func(T) bool) bool { - for _, value := range slice { - if !test(value) { - return false - } - } - - return true -} - -func Map[T any, V any](slice []T, f func(T) V) []V { - result := make([]V, len(slice)) - for i, value := range slice { - result[i] = f(value) - } - - return result -} - -func MapInPlace[T any](slice []T, f func(T) T) { - for i, value := range slice { - slice[i] = f(value) - } -} - -func Filter[T any](slice []T, test func(T) bool) []T { - result := make([]T, 0) - for _, element := range slice { - if test(element) { - result = append(result, element) - } - } - return result -} - -func FilterInPlace[T any](slice []T, test func(T) bool) []T { - newLength := 0 - for _, element := range slice { - if test(element) { - slice[newLength] = element - newLength++ - } - } - - return slice[:newLength] -} - -func Reverse[T any](slice []T) []T { - result := make([]T, len(slice)) - for i := range slice { - result[i] = slice[len(slice)-1-i] - } - return result -} - -func ReverseInPlace[T any](slice []T) { - for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 { - slice[i], slice[j] = slice[j], slice[i] - } -} diff --git a/vendor/github.com/jesseduffield/generics/list/list.go b/vendor/github.com/jesseduffield/generics/list/list.go deleted file mode 100644 index 2b0f43010..000000000 --- a/vendor/github.com/jesseduffield/generics/list/list.go +++ /dev/null @@ -1,117 +0,0 @@ -package list - -import ( - "golang.org/x/exp/slices" -) - -type List[T any] struct { - slice []T -} - -func New[T any]() *List[T] { - return &List[T]{} -} - -func NewFromSlice[T any](slice []T) *List[T] { - return &List[T]{slice: slice} -} - -func (l *List[T]) ToSlice() []T { - return l.slice -} - -// Mutative methods - -func (l *List[T]) Push(v T) { - l.slice = append(l.slice, v) -} - -func (l *List[T]) Pop() { - l.slice = l.slice[0 : len(l.slice)-1] -} - -func (l *List[T]) Insert(index int, values ...T) { - l.slice = slices.Insert(l.slice, index, values...) -} - -func (l *List[T]) Append(values ...T) { - l.slice = append(l.slice, values...) -} - -func (l *List[T]) Prepend(values ...T) { - l.slice = append(values, l.slice...) -} - -func (l *List[T]) Remove(index int) { - l.Delete(index, index+1) -} - -func (l *List[T]) Delete(from int, to int) { - l.slice = slices.Delete(l.slice, from, to) -} - -func (l *List[T]) FilterInPlace(test func(value T) bool) { - l.slice = FilterInPlace(l.slice, test) -} - -func (l *List[T]) MapInPlace(f func(value T) T) { - MapInPlace(l.slice, f) -} - -func (l *List[T]) ReverseInPlace() { - ReverseInPlace(l.slice) -} - -// Non-mutative methods - -// Similar to Append but we leave the original slice untouched and return a new list -func (l *List[T]) Concat(values ...T) *List[T] { - newSlice := make([]T, 0, len(l.slice)+len(values)) - newSlice = append(newSlice, l.slice...) - newSlice = append(newSlice, values...) - return &List[T]{slice: newSlice} -} - -func (l *List[T]) Filter(test func(value T) bool) *List[T] { - return NewFromSlice(Filter(l.slice, test)) -} - -// Unfortunately this does not support mapping from one type to another -// because Go does not yet (and may never) support methods defining their own -// type parameters. For that functionality you'll need to use the standalone -// Map function instead -func (l *List[T]) Map(f func(value T) T) *List[T] { - return NewFromSlice(Map(l.slice, f)) -} - -func (l *List[T]) Clone() *List[T] { - return NewFromSlice(slices.Clone(l.slice)) -} - -func (l *List[T]) Some(test func(value T) bool) bool { - return Some(l.slice, test) -} - -func (l *List[T]) Every(test func(value T) bool) bool { - return Every(l.slice, test) -} - -func (l *List[T]) IndexFunc(f func(T) bool) int { - return slices.IndexFunc(l.slice, f) -} - -func (l *List[T]) ContainsFunc(f func(T) bool) bool { - return l.IndexFunc(f) != -1 -} - -func (l *List[T]) Reverse() *List[T] { - return NewFromSlice(Reverse(l.slice)) -} - -func (l *List[T]) IsEmpty() bool { - return len(l.slice) == 0 -} - -func (l *List[T]) Len() int { - return len(l.slice) -} diff --git a/vendor/github.com/jesseduffield/generics/hashmap/functions.go b/vendor/github.com/jesseduffield/generics/maps/maps.go similarity index 98% rename from vendor/github.com/jesseduffield/generics/hashmap/functions.go rename to vendor/github.com/jesseduffield/generics/maps/maps.go index 526222b1f..eaf890022 100644 --- a/vendor/github.com/jesseduffield/generics/hashmap/functions.go +++ b/vendor/github.com/jesseduffield/generics/maps/maps.go @@ -1,4 +1,4 @@ -package hashmap +package maps func Keys[Key comparable, Value any](m map[Key]Value) []Key { keys := make([]Key, 0, len(m)) diff --git a/vendor/github.com/jesseduffield/generics/set/set.go b/vendor/github.com/jesseduffield/generics/set/set.go index 3e9b9d9bf..317a4fa6b 100644 --- a/vendor/github.com/jesseduffield/generics/set/set.go +++ b/vendor/github.com/jesseduffield/generics/set/set.go @@ -1,6 +1,6 @@ package set -import "github.com/jesseduffield/generics/hashmap" +import "github.com/jesseduffield/generics/maps" type Set[T comparable] struct { hashMap map[T]bool @@ -45,5 +45,5 @@ func (s *Set[T]) Includes(value T) bool { // output slice is not necessarily in the same order that items were added func (s *Set[T]) ToSlice() []T { - return hashmap.Keys(s.hashMap) + return maps.Keys(s.hashMap) } diff --git a/vendor/github.com/jesseduffield/generics/slices/delegated_slices.go b/vendor/github.com/jesseduffield/generics/slices/delegated_slices.go new file mode 100644 index 000000000..015935331 --- /dev/null +++ b/vendor/github.com/jesseduffield/generics/slices/delegated_slices.go @@ -0,0 +1,117 @@ +package slices + +import ( + "golang.org/x/exp/constraints" + "golang.org/x/exp/slices" +) + +// This file delegates to the official slices package, so that we end up with a superset of the official API. + +// Equal reports whether two slices are equal: the same length and all +// elements equal. If the lengths are different, Equal returns false. +// Otherwise, the elements are compared in increasing index order, and the +// comparison stops at the first unequal pair. +// Floating point NaNs are not considered equal. +func Equal[E comparable](s1, s2 []E) bool { + return slices.Equal(s1, s2) +} + +// EqualFunc reports whether two slices are equal using a comparison +// function on each pair of elements. If the lengths are different, +// EqualFunc returns false. Otherwise, the elements are compared in +// increasing index order, and the comparison stops at the first index +// for which eq returns false. +func EqualFunc[E1, E2 any](s1 []E1, s2 []E2, eq func(E1, E2) bool) bool { + return slices.EqualFunc(s1, s2, eq) +} + +// Compare compares the elements of s1 and s2. +// The elements are compared sequentially, starting at index 0, +// until one element is not equal to the other. +// The result of comparing the first non-matching elements is returned. +// If both slices are equal until one of them ends, the shorter slice is +// considered less than the longer one. +// The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2. +// Comparisons involving floating point NaNs are ignored. +func Compare[E constraints.Ordered](s1, s2 []E) int { + return slices.Compare(s1, s2) +} + +// CompareFunc is like Compare but uses a comparison function +// on each pair of elements. The elements are compared in increasing +// index order, and the comparisons stop after the first time cmp +// returns non-zero. +// The result is the first non-zero result of cmp; if cmp always +// returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2), +// and +1 if len(s1) > len(s2). +func CompareFunc[E1, E2 any](s1 []E1, s2 []E2, cmp func(E1, E2) int) int { + return slices.CompareFunc(s1, s2, cmp) +} + +// Index returns the index of the first occurrence of v in s, +// or -1 if not present. +func Index[E comparable](s []E, v E) int { + return slices.Index(s, v) +} + +// IndexFunc returns the first index i satisfying f(s[i]), +// or -1 if none do. +func IndexFunc[E any](s []E, f func(E) bool) int { + return slices.IndexFunc(s, f) +} + +// Contains reports whether v is present in s. +func Contains[E comparable](s []E, v E) bool { + return slices.Contains(s, v) +} + +// Insert inserts the values v... into s at index i, +// returning the modified slice. +// In the returned slice r, r[i] == v[0]. +// Insert panics if i is out of range. +// This function is O(len(s) + len(v)). +func Insert[S ~[]E, E any](s S, i int, v ...E) S { + return slices.Insert(s, i, v...) +} + +// Delete removes the elements s[i:j] from s, returning the modified slice. +// Delete panics if s[i:j] is not a valid slice of s. +// Delete modifies the contents of the slice s; it does not create a new slice. +// Delete is O(len(s)-(j-i)), so if many items must be deleted, it is better to +// make a single call deleting them all together than to delete one at a time. +func Delete[S ~[]E, E any](s S, i, j int) S { + return slices.Delete(s, i, j) +} + +// Clone returns a copy of the slice. +// The elements are copied using assignment, so this is a shallow clone. +func Clone[S ~[]E, E any](s S) S { + return slices.Clone(s) +} + +// Compact replaces consecutive runs of equal elements with a single copy. +// This is like the uniq command found on Unix. +// Compact modifies the contents of the slice s; it does not create a new slice. +// Intended usage is to assign the result back to the input slice. +func Compact[S ~[]E, E comparable](s S) S { + return slices.Compact(s) +} + +// CompactFunc is like Compact but uses a comparison function. +func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S { + return slices.CompactFunc(s, eq) +} + +// Grow increases the slice's capacity, if necessary, to guarantee space for +// another n elements. After Grow(n), at least n elements can be appended +// to the slice without another allocation. Grow may modify elements of the +// slice between the length and the capacity. If n is negative or too large to +// allocate the memory, Grow panics. +func Grow[S ~[]E, E any](s S, n int) S { + return slices.Grow(s, n) +} + +// Clip removes unused capacity from the slice, returning s[:len(s):len(s)]. +func Clip[S ~[]E, E any](s S) S { + return slices.Clip(s) +} diff --git a/vendor/github.com/jesseduffield/generics/slices/delegated_sort.go b/vendor/github.com/jesseduffield/generics/slices/delegated_sort.go new file mode 100644 index 000000000..0741f0c55 --- /dev/null +++ b/vendor/github.com/jesseduffield/generics/slices/delegated_sort.go @@ -0,0 +1,57 @@ +package slices + +import ( + "golang.org/x/exp/constraints" + "golang.org/x/exp/slices" +) + +// This file delegates to the official slices package, so that we end up with a superset of the official API. + +// Sort sorts a slice of any ordered type in ascending order. +func Sort[E constraints.Ordered](x []E) { + slices.Sort(x) +} + +// Sort sorts the slice x in ascending order as determined by the less function. +// This sort is not guaranteed to be stable. +func SortFunc[E any](x []E, less func(a, b E) bool) { + slices.SortFunc(x, less) +} + +// SortStable sorts the slice x while keeping the original order of equal +// elements, using less to compare elements. +func SortStableFunc[E any](x []E, less func(a, b E) bool) { + slices.SortStableFunc(x, less) +} + +// IsSorted reports whether x is sorted in ascending order. +func IsSorted[E constraints.Ordered](x []E) bool { + return slices.IsSorted(x) +} + +// IsSortedFunc reports whether x is sorted in ascending order, with less as the +// comparison function. +func IsSortedFunc[E any](x []E, less func(a, b E) bool) bool { + return slices.IsSortedFunc(x, less) +} + +// BinarySearch searches for target in a sorted slice and returns the smallest +// index at which target is found. If the target is not found, the index at +// which it could be inserted into the slice is returned; therefore, if the +// intention is to find target itself a separate check for equality with the +// element at the returned index is required. +func BinarySearch[E constraints.Ordered](x []E, target E) int { + return slices.BinarySearch(x, target) +} + +// BinarySearchFunc uses binary search to find and return the smallest index i +// in [0, n) at which ok(i) is true, assuming that on the range [0, n), +// ok(i) == true implies ok(i+1) == true. That is, BinarySearchFunc requires +// that ok is false for some (possibly empty) prefix of the input range [0, n) +// and then true for the (possibly empty) remainder; BinarySearchFunc returns +// the first true index. If there is no such index, BinarySearchFunc returns n. +// (Note that the "not found" return value is not -1 as in, for instance, +// strings.Index.) Search calls ok(i) only for i in the range [0, n). +func BinarySearchFunc[E any](x []E, ok func(E) bool) int { + return slices.BinarySearchFunc(x, ok) +} diff --git a/vendor/github.com/jesseduffield/generics/slices/slices.go b/vendor/github.com/jesseduffield/generics/slices/slices.go new file mode 100644 index 000000000..b9c783caf --- /dev/null +++ b/vendor/github.com/jesseduffield/generics/slices/slices.go @@ -0,0 +1,154 @@ +package slices + +import ( + "golang.org/x/exp/slices" +) + +// This file contains the new functions that do not live in the official slices package. + +func Some[T any](slice []T, test func(T) bool) bool { + for _, value := range slice { + if test(value) { + return true + } + } + + return false +} + +func Every[T any](slice []T, test func(T) bool) bool { + for _, value := range slice { + if !test(value) { + return false + } + } + + return true +} + +// Produces a new slice, leaves the input slice untouched. +func Map[T any, V any](slice []T, f func(T) V) []V { + result := make([]V, len(slice)) + for i, value := range slice { + result[i] = f(value) + } + + return result +} + +func MapInPlace[T any](slice []T, f func(T) T) { + for i, value := range slice { + slice[i] = f(value) + } +} + +// Produces a new slice, leaves the input slice untouched. +func Filter[T any](slice []T, test func(T) bool) []T { + result := make([]T, 0) + for _, element := range slice { + if test(element) { + result = append(result, element) + } + } + return result +} + +// Mutates original slice. Intended usage is to reassign the slice result to the input slice. +func FilterInPlace[T any](slice []T, test func(T) bool) []T { + newLength := 0 + for _, element := range slice { + if test(element) { + slice[newLength] = element + newLength++ + } + } + + return slice[:newLength] +} + +// Produces a new slice, leaves the input slice untouched +func Reverse[T any](slice []T) []T { + result := make([]T, len(slice)) + for i := range slice { + result[i] = slice[len(slice)-1-i] + } + return result +} + +func ReverseInPlace[T any](slice []T) { + for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 { + slice[i], slice[j] = slice[j], slice[i] + } +} + +// Produces a new slice, leaves the input slice untouched. +func FilterMap[T any, E any](slice []T, test func(T) (bool, E)) []E { + result := make([]E, 0, len(slice)) + for _, element := range slice { + ok, mapped := test(element) + if ok { + result = append(result, mapped) + } + } + + return result +} + +// Produces a new slice, leaves the input slice untouched. +func FilterThenMap[T any, E any](slice []T, test func(T) bool, mapFn func(T) E) []E { + result := make([]E, 0, len(slice)) + for _, element := range slice { + if test(element) { + result = append(result, mapFn(element)) + } + } + return result +} + +// Prepends items to the beginning of a slice. +// E.g. Prepend([]int{1,2}, 3, 4) = []int{3,4,1,2} +// Mutates original slice. Intended usage is to reassign the slice result to the input slice. +func Prepend[T any](slice []T, values ...T) []T { + return append(values, slice...) +} + +// Removes the element at the given index. Intended usage is to reassign the result to the input slice. +func Remove[T any](slice []T, index int) []T { + return slices.Delete(slice, index, index+1) +} + +// Operates on the input slice. Expected use is to reassign the result to the input slice. +func Move[T any](slice []T, fromIndex int, toIndex int) []T { + item := slice[fromIndex] + slice = Remove(slice, fromIndex) + return slices.Insert(slice, toIndex, item) +} + +// Similar to Append but we leave the original slice untouched and return a new slice +func Concat[T any](slice []T, values ...T) []T { + newSlice := make([]T, 0, len(slice)+len(values)) + newSlice = append(newSlice, slice...) + newSlice = append(newSlice, values...) + return newSlice +} + +func ContainsFunc[T any](slice []T, f func(T) bool) bool { + return IndexFunc(slice, f) != -1 +} + +// Pops item from the end of the slice and returns it, along with the updated slice +// Mutates original slice. Intended usage is to reassign the slice result to the input slice. +func Pop[T any](slice []T) (T, []T) { + index := len(slice) - 1 + value := slice[index] + slice = slice[0:index] + return value, slice +} + +// Shifts item from the beginning of the slice and returns it, along with the updated slice. +// Mutates original slice. Intended usage is to reassign the slice result to the input slice. +func Shift[T any](slice []T) (T, []T) { + value := slice[0] + slice = slice[1:] + return value, slice +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 6dc01e5ab..d9f343780 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -120,11 +120,11 @@ github.com/integrii/flaggy # github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 ## explicit github.com/jbenet/go-context/io -# github.com/jesseduffield/generics v0.0.0-20220318214805-3397e5e19e9f +# github.com/jesseduffield/generics v0.0.0-20220319042131-63614a800d5f ## explicit; go 1.18 -github.com/jesseduffield/generics/hashmap -github.com/jesseduffield/generics/list +github.com/jesseduffield/generics/maps github.com/jesseduffield/generics/set +github.com/jesseduffield/generics/slices # github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 ## explicit; go 1.13 github.com/jesseduffield/go-git/v5 From bf4f06ab4e6ceefe388e0efefcc553526f3d96c2 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 19 Mar 2022 16:34:46 +1100 Subject: [PATCH 115/385] more generics --- go.mod | 2 +- go.sum | 4 +- pkg/cheatsheet/generate.go | 12 +-- pkg/commands/git_commands/working_tree.go | 8 +- pkg/commands/loaders/branches.go | 32 +++---- pkg/commands/loaders/commit_files.go | 31 ++++--- pkg/commands/loaders/commit_files_test.go | 71 +++++++++++++++ pkg/commands/loaders/commits.go | 8 +- pkg/commands/loaders/commits_test.go | 18 ---- pkg/commands/loaders/tags.go | 20 ++--- pkg/commands/loaders/tags_test.go | 68 +++++++++++++++ pkg/commands/oscommands/os.go | 15 ++-- pkg/commands/patch/patch_manager.go | 25 +++--- pkg/commands/patch/patch_parser.go | 30 ++++--- pkg/gui/context.go | 8 +- pkg/gui/presentation/commits_test.go | 87 ++++++++++--------- pkg/utils/lines.go | 9 -- pkg/utils/lines_test.go | 23 ----- .../jesseduffield/generics/maps/maps.go | 18 ++++ .../jesseduffield/generics/set/set.go | 10 +-- vendor/modules.txt | 2 +- 21 files changed, 303 insertions(+), 198 deletions(-) create mode 100644 pkg/commands/loaders/commit_files_test.go create mode 100644 pkg/commands/loaders/tags_test.go diff --git a/go.mod b/go.mod index d966c20da..e4ecbe338 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gookit/color v1.4.2 github.com/imdario/mergo v0.3.11 github.com/integrii/flaggy v1.4.0 - github.com/jesseduffield/generics v0.0.0-20220319042131-63614a800d5f + github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518 github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e diff --git a/go.sum b/go.sum index fe8e252ac..98c61cb73 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jesseduffield/generics v0.0.0-20220319042131-63614a800d5f h1:VZkNxrfkR344djm4Ju7QuKLXxZlaaOaNCrAWVRc1gvU= -github.com/jesseduffield/generics v0.0.0-20220319042131-63614a800d5f/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= +github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518 h1:scclO0fuRMsIdYr6Gg+9LS1S1ZO93tHKQSbErWQWQ4s= +github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 h1:9N08i5kjvOfkzMj6THmIM110wPTQLdVYEOHMHT2DFiI= diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index d88f3d733..ecb75f935 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -13,6 +13,7 @@ import ( "log" "os" + "github.com/jesseduffield/generics/maps" "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/app" "github.com/jesseduffield/lazygit/pkg/config" @@ -174,11 +175,12 @@ outer: bindings []*types.Binding } - groupedBindings := make([]groupedBindingsType, 0, len(contextAndViewBindingMap)) - - for contextAndView, contextBindings := range contextAndViewBindingMap { - groupedBindings = append(groupedBindings, groupedBindingsType{contextAndView: contextAndView, bindings: contextBindings}) - } + groupedBindings := maps.MapToSlice( + contextAndViewBindingMap, + func(contextAndView contextAndViewType, contextBindings []*types.Binding) groupedBindingsType { + return groupedBindingsType{contextAndView: contextAndView, bindings: contextBindings} + }, + ) slices.SortFunc(groupedBindings, func(a, b groupedBindingsType) bool { first := a.contextAndView diff --git a/pkg/commands/git_commands/working_tree.go b/pkg/commands/git_commands/working_tree.go index f594a639b..08e247459 100644 --- a/pkg/commands/git_commands/working_tree.go +++ b/pkg/commands/git_commands/working_tree.go @@ -8,6 +8,7 @@ import ( "time" "github.com/go-errors/errors" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/loaders" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" @@ -46,10 +47,9 @@ func (self *WorkingTreeCommands) StageFile(path string) error { } func (self *WorkingTreeCommands) StageFiles(paths []string) error { - quotedPaths := make([]string, len(paths)) - for i, path := range paths { - quotedPaths[i] = self.cmd.Quote(path) - } + quotedPaths := slices.Map(paths, func(path string) string { + return self.cmd.Quote(path) + }) return self.cmd.New(fmt.Sprintf("git add -- %s", strings.Join(quotedPaths, " "))).Run() } diff --git a/pkg/commands/loaders/branches.go b/pkg/commands/loaders/branches.go index 90480ca9a..682c23ad4 100644 --- a/pkg/commands/loaders/branches.go +++ b/pkg/commands/loaders/branches.go @@ -66,13 +66,13 @@ outer: if strings.EqualFold(reflogBranch.Name, branch.Name) { branch.Recency = reflogBranch.Recency branchesWithRecency = append(branchesWithRecency, branch) - branches = append(branches[0:j], branches[j+1:]...) + branches = slices.Remove(branches, j) continue outer } } } - branches = append(branchesWithRecency, branches...) + branches = slices.Prepend(branches, branchesWithRecency...) foundHead := false for i, branch := range branches { @@ -159,7 +159,7 @@ func (self *BranchLoader) obtainBranches() []*models.Branch { trimmedOutput := strings.TrimSpace(output) outputLines := strings.Split(trimmedOutput, "\n") - branches := slices.FilterMap(outputLines, func(line string) (*models.Branch, bool) { + return slices.FilterMap(outputLines, func(line string) (*models.Branch, bool) { if line == "" { return nil, false } @@ -174,8 +174,6 @@ func (self *BranchLoader) obtainBranches() []*models.Branch { return obtainBranch(split), true }) - - return branches } // TODO: only look at the new reflog commits, and otherwise store the recencies in @@ -184,17 +182,21 @@ func (self *BranchLoader) obtainReflogBranches(reflogCommits []*models.Commit) [ foundBranches := set.New[string]() re := regexp.MustCompile(`checkout: moving from ([\S]+) to ([\S]+)`) reflogBranches := make([]*models.Branch, 0, len(reflogCommits)) + for _, commit := range reflogCommits { - if match := re.FindStringSubmatch(commit.Name); len(match) == 3 { - recency := utils.UnixToTimeAgo(commit.UnixTimestamp) - for _, branchName := range match[1:] { - if !foundBranches.Includes(branchName) { - foundBranches.Add(branchName) - reflogBranches = append(reflogBranches, &models.Branch{ - Recency: recency, - Name: branchName, - }) - } + match := re.FindStringSubmatch(commit.Name) + if len(match) != 3 { + continue + } + + recency := utils.UnixToTimeAgo(commit.UnixTimestamp) + for _, branchName := range match[1:] { + if !foundBranches.Includes(branchName) { + foundBranches.Add(branchName) + reflogBranches = append(reflogBranches, &models.Branch{ + Recency: recency, + Name: branchName, + }) } } } diff --git a/pkg/commands/loaders/commit_files.go b/pkg/commands/loaders/commit_files.go index 755db768d..d68571edb 100644 --- a/pkg/commands/loaders/commit_files.go +++ b/pkg/commands/loaders/commit_files.go @@ -4,9 +4,11 @@ import ( "fmt" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/common" + "github.com/samber/lo" ) type CommitFileLoader struct { @@ -33,25 +35,22 @@ func (self *CommitFileLoader) GetFilesInDiff(from string, to string, reverse boo return nil, err } - return self.getCommitFilesFromFilenames(filenames), nil + return getCommitFilesFromFilenames(filenames), nil } -// filenames string is something like "file1\nfile2\nfile3" -func (self *CommitFileLoader) getCommitFilesFromFilenames(filenames string) []*models.CommitFile { - commitFiles := make([]*models.CommitFile, 0) - +// filenames string is something like "MM\x00file1\x00MU\x00file2\x00AA\x00file3\x00" +// so we need to split it by the null character and then map each status-name pair to a commit file +func getCommitFilesFromFilenames(filenames string) []*models.CommitFile { lines := strings.Split(strings.TrimRight(filenames, "\x00"), "\x00") - n := len(lines) - for i := 0; i < n-1; i += 2 { - // typical result looks like 'A my_file' meaning my_file was added - changeStatus := lines[i] - name := lines[i+1] - - commitFiles = append(commitFiles, &models.CommitFile{ - Name: name, - ChangeStatus: changeStatus, - }) + if len(lines) == 1 { + return []*models.CommitFile{} } - return commitFiles + // typical result looks like 'A my_file' meaning my_file was added + return slices.Map(lo.Chunk(lines, 2), func(chunk []string) *models.CommitFile { + return &models.CommitFile{ + ChangeStatus: chunk[0], + Name: chunk[1], + } + }) } diff --git a/pkg/commands/loaders/commit_files_test.go b/pkg/commands/loaders/commit_files_test.go new file mode 100644 index 000000000..a07390052 --- /dev/null +++ b/pkg/commands/loaders/commit_files_test.go @@ -0,0 +1,71 @@ +package loaders + +import ( + "testing" + + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/stretchr/testify/assert" +) + +func TestGetCommitFilesFromFilenames(t *testing.T) { + tests := []struct { + testName string + input string + output []*models.CommitFile + }{ + { + testName: "no files", + input: "", + output: []*models.CommitFile{}, + }, + { + testName: "one file", + input: "MM\x00Myfile\x00", + output: []*models.CommitFile{ + { + Name: "Myfile", + ChangeStatus: "MM", + }, + }, + }, + { + testName: "two files", + input: "MM\x00Myfile\x00M \x00MyOtherFile\x00", + output: []*models.CommitFile{ + { + Name: "Myfile", + ChangeStatus: "MM", + }, + { + Name: "MyOtherFile", + ChangeStatus: "M ", + }, + }, + }, + { + testName: "three files", + input: "MM\x00Myfile\x00M \x00MyOtherFile\x00 M\x00YetAnother\x00", + output: []*models.CommitFile{ + { + Name: "Myfile", + ChangeStatus: "MM", + }, + { + Name: "MyOtherFile", + ChangeStatus: "M ", + }, + { + Name: "YetAnother", + ChangeStatus: " M", + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.testName, func(t *testing.T) { + result := getCommitFilesFromFilenames(test.input) + assert.Equal(t, test.output, result) + }) + } +} diff --git a/pkg/commands/loaders/commits.go b/pkg/commands/loaders/commits.go index 187a13bb0..20721be42 100644 --- a/pkg/commands/loaders/commits.go +++ b/pkg/commands/loaders/commits.go @@ -9,6 +9,7 @@ import ( "strconv" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" @@ -200,10 +201,9 @@ func (self *CommitLoader) getHydratedRebasingCommits(rebaseMode enums.RebaseMode return nil, nil } - commitShas := make([]string, len(commits)) - for i, commit := range commits { - commitShas[i] = commit.Sha - } + commitShas := slices.Map(commits, func(commit *models.Commit) string { + return commit.Sha + }) // note that we're not filtering these as we do non-rebasing commits just because // I suspect that will cause some damage diff --git a/pkg/commands/loaders/commits_test.go b/pkg/commands/loaders/commits_test.go index ff406abaf..6bb81c57d 100644 --- a/pkg/commands/loaders/commits_test.go +++ b/pkg/commands/loaders/commits_test.go @@ -11,24 +11,6 @@ import ( "github.com/stretchr/testify/assert" ) -func NewDummyCommitLoader() *CommitLoader { - cmn := utils.NewDummyCommon() - - return &CommitLoader{ - Common: cmn, - cmd: nil, - getCurrentBranchName: func() (string, string, error) { return "master", "master", nil }, - getRebaseMode: func() (enums.RebaseMode, error) { return enums.REBASE_MODE_NONE, nil }, - dotGitDir: ".git", - readFile: func(filename string) ([]byte, error) { - return []byte(""), nil - }, - walkFiles: func(root string, fn filepath.WalkFunc) error { - return nil - }, - } -} - const commitsOutput = `0eea75e8c631fba6b58135697835d58ba4c18dbc|1640826609|Jesse Duffield| (HEAD -> better-tests)|b21997d6b4cbdf84b149|better typing for rebase mode b21997d6b4cbdf84b149d8e6a2c4d06a8e9ec164|1640824515|Jesse Duffield| (origin/better-tests)|e94e8fc5b6fab4cb755f|fix logging e94e8fc5b6fab4cb755f29f1bdb3ee5e001df35c|1640823749|Jesse Duffield||d8084cd558925eb7c9c3|refactor diff --git a/pkg/commands/loaders/tags.go b/pkg/commands/loaders/tags.go index 45b08a002..8e5063c34 100644 --- a/pkg/commands/loaders/tags.go +++ b/pkg/commands/loaders/tags.go @@ -1,8 +1,7 @@ package loaders import ( - "strings" - + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/common" @@ -27,25 +26,18 @@ func NewTagLoader( func (self *TagLoader) GetTags() ([]*models.Tag, error) { // get remote branches, sorted by creation date (descending) // see: https://git-scm.com/docs/git-tag#Documentation/git-tag.txt---sortltkeygt - remoteBranchesStr, err := self.cmd.New(`git tag --list --sort=-creatordate`).DontLog().RunWithOutput() + tagsOutput, err := self.cmd.New(`git tag --list --sort=-creatordate`).DontLog().RunWithOutput() if err != nil { return nil, err } - content := utils.TrimTrailingNewline(remoteBranchesStr) - if content == "" { - return nil, nil - } + split := utils.SplitLines(tagsOutput) - split := strings.Split(content, "\n") - - // first step is to get our remotes from go-git - tags := make([]*models.Tag, len(split)) - for i, tagName := range split { - tags[i] = &models.Tag{ + tags := slices.Map(split, func(tagName string) *models.Tag { + return &models.Tag{ Name: tagName, } - } + }) return tags, nil } diff --git a/pkg/commands/loaders/tags_test.go b/pkg/commands/loaders/tags_test.go new file mode 100644 index 000000000..5394fa3a8 --- /dev/null +++ b/pkg/commands/loaders/tags_test.go @@ -0,0 +1,68 @@ +package loaders + +import ( + "testing" + + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" + "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/stretchr/testify/assert" +) + +const tagsOutput = `v0.34 +v0.33 +v0.32.2 +v0.32.1 +v0.32 +testtag +` + +func TestGetTags(t *testing.T) { + type scenario struct { + testName string + runner *oscommands.FakeCmdObjRunner + expectedTags []*models.Tag + expectedError error + } + + scenarios := []scenario{ + { + testName: "should return no tags if there are none", + runner: oscommands.NewFakeRunner(t). + Expect(`git tag --list --sort=-creatordate`, "", nil), + expectedTags: []*models.Tag{}, + expectedError: nil, + }, + { + testName: "should return tags if present", + runner: oscommands.NewFakeRunner(t). + Expect(`git tag --list --sort=-creatordate`, tagsOutput, nil), + expectedTags: []*models.Tag{ + {Name: "v0.34"}, + {Name: "v0.33"}, + {Name: "v0.32.2"}, + {Name: "v0.32.1"}, + {Name: "v0.32"}, + {Name: "testtag"}, + }, + expectedError: nil, + }, + } + + for _, scenario := range scenarios { + scenario := scenario + t.Run(scenario.testName, func(t *testing.T) { + loader := &TagLoader{ + Common: utils.NewDummyCommon(), + cmd: oscommands.NewDummyCmdObjBuilder(scenario.runner), + } + + tags, err := loader.GetTags() + + assert.Equal(t, scenario.expectedTags, tags) + assert.Equal(t, scenario.expectedError, err) + + scenario.runner.CheckForMissingCalls() + }) + } +} diff --git a/pkg/commands/oscommands/os.go b/pkg/commands/oscommands/os.go index f3df3956f..b6f018af5 100644 --- a/pkg/commands/oscommands/os.go +++ b/pkg/commands/oscommands/os.go @@ -12,6 +12,7 @@ import ( "github.com/go-errors/errors" "github.com/atotto/clipboard" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -173,15 +174,11 @@ func (c *OSCommand) FileExists(path string) (bool, error) { // PipeCommands runs a heap of commands and pipes their inputs/outputs together like A | B | C func (c *OSCommand) PipeCommands(commandStrings ...string) error { - cmds := make([]*exec.Cmd, len(commandStrings)) - logCmdStr := "" - for i, str := range commandStrings { - if i > 0 { - logCmdStr += " | " - } - logCmdStr += str - cmds[i] = c.Cmd.New(str).GetCmd() - } + cmds := slices.Map(commandStrings, func(cmdString string) *exec.Cmd { + return c.Cmd.New(cmdString).GetCmd() + }) + + logCmdStr := strings.Join(commandStrings, " | ") c.LogCommand(logCmdStr, true) for i := 0; i < len(cmds)-1; i++ { diff --git a/pkg/commands/patch/patch_manager.go b/pkg/commands/patch/patch_manager.go index 1282356f8..4fb6507e6 100644 --- a/pkg/commands/patch/patch_manager.go +++ b/pkg/commands/patch/patch_manager.go @@ -4,6 +4,8 @@ import ( "sort" "strings" + "github.com/jesseduffield/generics/maps" + "github.com/jesseduffield/generics/slices" "github.com/samber/lo" "github.com/sirupsen/logrus" ) @@ -72,8 +74,9 @@ func (p *PatchManager) Start(from, to string, reverse bool, canRebase bool) { func (p *PatchManager) addFileWhole(info *fileInfo) { info.mode = WHOLE lineCount := len(strings.Split(info.diff, "\n")) - info.includedLineIndices = make([]int, lineCount) // add every line index + // TODO: add tests and then use lo.Range to simplify + info.includedLineIndices = make([]int, lineCount) for i := 0; i < lineCount; i++ { info.includedLineIndices[i] = i } @@ -192,21 +195,15 @@ func (p *PatchManager) RenderPatchForFile(filename string, plain bool, reverse b func (p *PatchManager) renderEachFilePatch(plain bool) []string { // sort files by name then iterate through and render each patch - filenames := make([]string, len(p.fileInfoMap)) - index := 0 - for filename := range p.fileInfoMap { - filenames[index] = filename - index++ - } + filenames := maps.Keys(p.fileInfoMap) sort.Strings(filenames) - output := []string{} - for _, filename := range filenames { - patch := p.RenderPatchForFile(filename, plain, false, true) - if patch != "" { - output = append(output, patch) - } - } + patches := slices.Map(filenames, func(filename string) string { + return p.RenderPatchForFile(filename, plain, false, true) + }) + output := slices.Filter(patches, func(patch string) bool { + return patch != "" + }) return output } diff --git a/pkg/commands/patch/patch_parser.go b/pkg/commands/patch/patch_parser.go index 3810d8a29..097f01329 100644 --- a/pkg/commands/patch/patch_parser.go +++ b/pkg/commands/patch/patch_parser.go @@ -4,9 +4,9 @@ import ( "regexp" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/theme" - "github.com/jesseduffield/lazygit/pkg/utils" "github.com/samber/lo" "github.com/sirupsen/logrus" ) @@ -184,16 +184,21 @@ func parsePatch(patch string) ([]int, []int, []*PatchLine) { // Render returns the coloured string of the diff with any selected lines highlighted func (p *PatchParser) Render(firstLineIndex int, lastLineIndex int, incLineIndices []int) string { - renderedLines := make([]string, len(p.PatchLines)) - for index, patchLine := range p.PatchLines { - selected := index >= firstLineIndex && index <= lastLineIndex - included := lo.Contains(incLineIndices, index) - renderedLines[index] = patchLine.render(selected, included) - } - result := strings.Join(renderedLines, "\n") - if strings.TrimSpace(utils.Decolorise(result)) == "" { + contentToDisplay := slices.Some(p.PatchLines, func(line *PatchLine) bool { + return line.Content != "" + }) + if !contentToDisplay { return "" } + + renderedLines := lo.Map(p.PatchLines, func(patchLine *PatchLine, index int) string { + selected := index >= firstLineIndex && index <= lastLineIndex + included := lo.Contains(incLineIndices, index) + return patchLine.render(selected, included) + }) + + result := strings.Join(renderedLines, "\n") + return result } @@ -202,10 +207,9 @@ func (p *PatchParser) Render(firstLineIndex int, lastLineIndex int, incLineIndic func (p *PatchParser) PlainRenderLines(firstLineIndex, lastLineIndex int) string { linesToCopy := p.PatchLines[firstLineIndex : lastLineIndex+1] - renderedLines := make([]string, len(linesToCopy)) - for index, line := range linesToCopy { - renderedLines[index] = line.Content - } + renderedLines := slices.Map(linesToCopy, func(line *PatchLine) string { + return line.Content + }) return strings.Join(renderedLines, "\n") } diff --git a/pkg/gui/context.go b/pkg/gui/context.go index b4b274092..53e29e246 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -6,6 +6,7 @@ import ( "sort" "strings" + "github.com/jesseduffield/generics/maps" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -231,10 +232,9 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro } func (gui *Gui) optionsMapToString(optionsMap map[string]string) string { - optionsArray := make([]string, 0) - for key, description := range optionsMap { - optionsArray = append(optionsArray, key+": "+description) - } + optionsArray := maps.MapToSlice(optionsMap, func(key string, description string) string { + return key + ": " + description + }) sort.Strings(optionsArray) return strings.Join(optionsArray, ", ") } diff --git a/pkg/gui/presentation/commits_test.go b/pkg/gui/presentation/commits_test.go index 846d50d19..d2acaeba2 100644 --- a/pkg/gui/presentation/commits_test.go +++ b/pkg/gui/presentation/commits_test.go @@ -38,13 +38,14 @@ func TestGetCommitListDisplayStrings(t *testing.T) { focus bool }{ { - testName: "no commits", - commits: []*models.Commit{}, - startIdx: 0, - length: 1, - showGraph: false, - bisectInfo: git_commands.NewNullBisectInfo(), - expected: "", + testName: "no commits", + commits: []*models.Commit{}, + startIdx: 0, + length: 1, + showGraph: false, + bisectInfo: git_commands.NewNullBisectInfo(), + cherryPickedCommitShaSet: set.New[string](), + expected: "", }, { testName: "some commits", @@ -52,10 +53,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) { {Name: "commit1", Sha: "sha1"}, {Name: "commit2", Sha: "sha2"}, }, - startIdx: 0, - length: 2, - showGraph: false, - bisectInfo: git_commands.NewNullBisectInfo(), + startIdx: 0, + length: 2, + showGraph: false, + bisectInfo: git_commands.NewNullBisectInfo(), + cherryPickedCommitShaSet: set.New[string](), expected: formatExpected(` sha1 commit1 sha2 commit2 @@ -70,10 +72,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) { {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, }, - startIdx: 0, - length: 5, - showGraph: true, - bisectInfo: git_commands.NewNullBisectInfo(), + startIdx: 0, + length: 5, + showGraph: true, + bisectInfo: git_commands.NewNullBisectInfo(), + cherryPickedCommitShaSet: set.New[string](), expected: formatExpected(` sha1 鈴b攢鈺 commit1 sha2 鈼 鈹 commit2 @@ -91,10 +94,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) { {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, }, - startIdx: 0, - length: 5, - showGraph: true, - bisectInfo: git_commands.NewNullBisectInfo(), + startIdx: 0, + length: 5, + showGraph: true, + bisectInfo: git_commands.NewNullBisectInfo(), + cherryPickedCommitShaSet: set.New[string](), expected: formatExpected(` sha1 pick commit1 sha2 pick commit2 @@ -112,10 +116,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) { {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, }, - startIdx: 1, - length: 10, - showGraph: true, - bisectInfo: git_commands.NewNullBisectInfo(), + startIdx: 1, + length: 10, + showGraph: true, + bisectInfo: git_commands.NewNullBisectInfo(), + cherryPickedCommitShaSet: set.New[string](), expected: formatExpected(` sha2 pick commit2 sha3 鈼 commit3 @@ -132,10 +137,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) { {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, }, - startIdx: 3, - length: 2, - showGraph: true, - bisectInfo: git_commands.NewNullBisectInfo(), + startIdx: 3, + length: 2, + showGraph: true, + bisectInfo: git_commands.NewNullBisectInfo(), + cherryPickedCommitShaSet: set.New[string](), expected: formatExpected(` sha4 鈼 commit4 sha5 鈼 commit5 @@ -150,10 +156,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) { {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, }, - startIdx: 0, - length: 2, - showGraph: true, - bisectInfo: git_commands.NewNullBisectInfo(), + startIdx: 0, + length: 2, + showGraph: true, + bisectInfo: git_commands.NewNullBisectInfo(), + cherryPickedCommitShaSet: set.New[string](), expected: formatExpected(` sha1 pick commit1 sha2 pick commit2 @@ -168,10 +175,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) { {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, }, - startIdx: 4, - length: 2, - showGraph: true, - bisectInfo: git_commands.NewNullBisectInfo(), + startIdx: 4, + length: 2, + showGraph: true, + bisectInfo: git_commands.NewNullBisectInfo(), + cherryPickedCommitShaSet: set.New[string](), expected: formatExpected(` sha5 鈼 commit5 `), @@ -185,10 +193,11 @@ func TestGetCommitListDisplayStrings(t *testing.T) { {Name: "commit4", Sha: "sha4", Parents: []string{"sha5"}, Action: "pick"}, {Name: "commit5", Sha: "sha5", Parents: []string{"sha7"}}, }, - startIdx: 0, - length: 2, - showGraph: true, - bisectInfo: git_commands.NewNullBisectInfo(), + startIdx: 0, + length: 2, + showGraph: true, + bisectInfo: git_commands.NewNullBisectInfo(), + cherryPickedCommitShaSet: set.New[string](), expected: formatExpected(` sha1 pick commit1 sha2 pick commit2 diff --git a/pkg/utils/lines.go b/pkg/utils/lines.go index 9aea84bff..47d33e939 100644 --- a/pkg/utils/lines.go +++ b/pkg/utils/lines.go @@ -17,15 +17,6 @@ func SplitLines(multilineString string) []string { return lines } -// TrimTrailingNewline - Trims the trailing newline -// TODO: replace with `chomp` after refactor -func TrimTrailingNewline(str string) string { - if strings.HasSuffix(str, "\n") { - return str[:len(str)-1] - } - return str -} - // NormalizeLinefeeds - Removes all Windows and Mac style line feeds func NormalizeLinefeeds(str string) string { str = strings.Replace(str, "\r\n", "\n", -1) diff --git a/pkg/utils/lines_test.go b/pkg/utils/lines_test.go index faafb863a..361f0a510 100644 --- a/pkg/utils/lines_test.go +++ b/pkg/utils/lines_test.go @@ -36,29 +36,6 @@ func TestSplitLines(t *testing.T) { } } -// TestTrimTrailingNewline is a function. -func TestTrimTrailingNewline(t *testing.T) { - type scenario struct { - str string - expected string - } - - scenarios := []scenario{ - { - "hello world !\n", - "hello world !", - }, - { - "hello world !", - "hello world !", - }, - } - - for _, s := range scenarios { - assert.EqualValues(t, s.expected, TrimTrailingNewline(s.str)) - } -} - // TestNormalizeLinefeeds is a function. func TestNormalizeLinefeeds(t *testing.T) { type scenario struct { diff --git a/vendor/github.com/jesseduffield/generics/maps/maps.go b/vendor/github.com/jesseduffield/generics/maps/maps.go index eaf890022..9d41a3303 100644 --- a/vendor/github.com/jesseduffield/generics/maps/maps.go +++ b/vendor/github.com/jesseduffield/generics/maps/maps.go @@ -33,3 +33,21 @@ func TransformKeys[Key comparable, Value any, NewKey comparable](m map[Key]Value } return output } + +func MapToSlice[Key comparable, Value any, Mapped any](m map[Key]Value, f func(Key, Value) Mapped) []Mapped { + output := make([]Mapped, 0, len(m)) + for key, value := range m { + output = append(output, f(key, value)) + } + return output +} + +func Filter[Key comparable, Value any](m map[Key]Value, f func(Key, Value) bool) map[Key]Value { + output := map[Key]Value{} + for key, value := range m { + if f(key, value) { + output[key] = value + } + } + return output +} diff --git a/vendor/github.com/jesseduffield/generics/set/set.go b/vendor/github.com/jesseduffield/generics/set/set.go index 317a4fa6b..3e1bb69a3 100644 --- a/vendor/github.com/jesseduffield/generics/set/set.go +++ b/vendor/github.com/jesseduffield/generics/set/set.go @@ -19,13 +19,9 @@ func NewFromSlice[T comparable](slice []T) *Set[T] { return &Set[T]{hashMap: hashMap} } -func (s *Set[T]) Add(value T) { - s.hashMap[value] = true -} - -func (s *Set[T]) AddSlice(slice []T) { - for _, value := range slice { - s.Add(value) +func (s *Set[T]) Add(values ...T) { + for _, value := range values { + s.hashMap[value] = true } } diff --git a/vendor/modules.txt b/vendor/modules.txt index d9f343780..b7234a630 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -120,7 +120,7 @@ github.com/integrii/flaggy # github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 ## explicit github.com/jbenet/go-context/io -# github.com/jesseduffield/generics v0.0.0-20220319042131-63614a800d5f +# github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518 ## explicit; go 1.18 github.com/jesseduffield/generics/maps github.com/jesseduffield/generics/set From 1b75ed37403ac2997cb6a5ede92d87f1a1eb96b1 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 19 Mar 2022 19:12:58 +1100 Subject: [PATCH 116/385] many more generics --- go.mod | 2 +- go.sum | 4 +- pkg/gui/context.go | 14 +--- pkg/gui/context/menu_context.go | 24 +++--- .../helpers/merge_and_rebase_helper.go | 10 +-- pkg/gui/controllers/helpers/refs_helper.go | 9 +-- .../controllers/helpers/suggestions_helper.go | 65 ++++++---------- pkg/gui/files_panel_test.go | 11 +-- pkg/gui/filetree/commit_file_node.go | 33 ++++---- pkg/gui/filetree/file_node.go | 34 ++++---- pkg/gui/filetree/file_tree.go | 9 +-- pkg/gui/list_context_config.go | 19 ++--- pkg/gui/options_menu_panel.go | 10 +-- pkg/gui/presentation/branches.go | 13 ++-- pkg/gui/presentation/graph/graph.go | 69 +++++++---------- pkg/gui/presentation/reflog_commits.go | 15 ++-- pkg/gui/presentation/remote_branches.go | 13 ++-- pkg/gui/presentation/remotes.go | 13 ++-- pkg/gui/presentation/stash_entries.go | 13 ++-- pkg/gui/presentation/submodules.go | 11 +-- pkg/gui/presentation/suggestions.go | 11 +-- pkg/gui/presentation/tags.go | 13 ++-- pkg/gui/recent_repos_panel.go | 11 +-- pkg/gui/refresh.go | 10 +-- .../custom_commands/handler_creator.go | 21 +++-- .../custom_commands/keybinding_creator.go | 9 +-- pkg/gui/status_panel.go | 14 ++-- pkg/utils/formatting.go | 29 +++---- pkg/utils/fuzzy_search.go | 10 +-- .../jesseduffield/generics/slices/slices.go | 77 ++++++++++++++++++- vendor/modules.txt | 2 +- 31 files changed, 278 insertions(+), 320 deletions(-) diff --git a/go.mod b/go.mod index e4ecbe338..bc85923d9 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gookit/color v1.4.2 github.com/imdario/mergo v0.3.11 github.com/integrii/flaggy v1.4.0 - github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518 + github.com/jesseduffield/generics v0.0.0-20220319080325-a60171f800d5 github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e diff --git a/go.sum b/go.sum index 98c61cb73..eff282697 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518 h1:scclO0fuRMsIdYr6Gg+9LS1S1ZO93tHKQSbErWQWQ4s= -github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= +github.com/jesseduffield/generics v0.0.0-20220319080325-a60171f800d5 h1:mZf9Ezkd4Thuw2tj5naFeoUbHkbNiD38LQFokUGSbtQ= +github.com/jesseduffield/generics v0.0.0-20220319080325-a60171f800d5/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 h1:9N08i5kjvOfkzMj6THmIM110wPTQLdVYEOHMHT2DFiI= diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 53e29e246..2c30218bc 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/jesseduffield/generics/maps" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -413,16 +414,9 @@ func (gui *Gui) changeMainViewsContext(c types.Context) { func (gui *Gui) viewTabNames(viewName string) []string { tabContexts := gui.State.ViewTabContextMap[viewName] - if len(tabContexts) == 0 { - return nil - } - - result := make([]string, len(tabContexts)) - for i, tabContext := range tabContexts { - result[i] = tabContext.Tab - } - - return result + return slices.Map(tabContexts, func(tabContext context.TabContext) string { + return tabContext.Tab + }) } func (gui *Gui) setViewTabForContext(c types.Context) { diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go index 67d6b126a..1f5654902 100644 --- a/pkg/gui/context/menu_context.go +++ b/pkg/gui/context/menu_context.go @@ -1,6 +1,7 @@ package context import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -77,19 +78,16 @@ func (self *MenuViewModel) SetMenuItems(items []*types.MenuItem) { } // TODO: move into presentation package -func (self *MenuViewModel) GetDisplayStrings(startIdx int, length int) [][]string { - stringArrays := make([][]string, len(self.menuItems)) - for i, item := range self.menuItems { - if item.DisplayStrings == nil { - styledStr := item.DisplayString - if item.OpensMenu { - styledStr = presentation.OpensMenuStyle(styledStr) - } - stringArrays[i] = []string{styledStr} - } else { - stringArrays[i] = item.DisplayStrings +func (self *MenuViewModel) GetDisplayStrings(_startIdx int, _length int) [][]string { + return slices.Map(self.menuItems, func(item *types.MenuItem) []string { + if item.DisplayStrings != nil { + return item.DisplayStrings } - } - return stringArrays + styledStr := item.DisplayString + if item.OpensMenu { + styledStr = presentation.OpensMenuStyle(styledStr) + } + return []string{styledStr} + }) } diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index 477c5c64f..636c1c5fe 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" @@ -51,17 +52,14 @@ func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error { options = append(options, REBASE_OPTION_SKIP) } - menuItems := make([]*types.MenuItem, len(options)) - for i, option := range options { - // note to self. Never, EVER, close over loop variables in a function - option := option - menuItems[i] = &types.MenuItem{ + menuItems := slices.Map(options, func(option string) *types.MenuItem { + return &types.MenuItem{ DisplayString: option, OnPress: func() error { return self.genericMergeCommand(option) }, } - } + }) var title string if self.git.Status.WorkingTreeState() == enums.REBASE_MODE_MERGING { diff --git a/pkg/gui/controllers/helpers/refs_helper.go b/pkg/gui/controllers/helpers/refs_helper.go index 65c01d4a7..0838dd6f0 100644 --- a/pkg/gui/controllers/helpers/refs_helper.go +++ b/pkg/gui/controllers/helpers/refs_helper.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" @@ -134,10 +135,8 @@ func (self *RefsHelper) ResetToRef(ref string, strength string, envVars []string func (self *RefsHelper) CreateGitResetMenu(ref string) error { strengths := []string{"soft", "mixed", "hard"} - menuItems := make([]*types.MenuItem, len(strengths)) - for i, strength := range strengths { - strength := strength - menuItems[i] = &types.MenuItem{ + menuItems := slices.Map(strengths, func(strength string) *types.MenuItem { + return &types.MenuItem{ DisplayStrings: []string{ fmt.Sprintf("%s reset", strength), style.FgRed.Sprintf("reset --%s %s", strength, ref), @@ -147,7 +146,7 @@ func (self *RefsHelper) CreateGitResetMenu(ref string) error { return self.ResetToRef(ref, strength, []string{}) }, } - } + }) return self.c.Menu(types.CreateMenuOptions{ Title: fmt.Sprintf("%s %s", self.c.Tr.LcResetTo, ref), diff --git a/pkg/gui/controllers/helpers/suggestions_helper.go b/pkg/gui/controllers/helpers/suggestions_helper.go index a48e325b1..52ccf9d96 100644 --- a/pkg/gui/controllers/helpers/suggestions_helper.go +++ b/pkg/gui/controllers/helpers/suggestions_helper.go @@ -4,6 +4,8 @@ import ( "fmt" "os" + "github.com/jesseduffield/generics/slices" + "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -51,22 +53,18 @@ func NewSuggestionsHelper( } func (self *SuggestionsHelper) getRemoteNames() []string { - result := make([]string, len(self.model.Remotes)) - for i, remote := range self.model.Remotes { - result[i] = remote.Name - } - return result + return slices.Map(self.model.Remotes, func(remote *models.Remote) string { + return remote.Name + }) } func matchesToSuggestions(matches []string) []*types.Suggestion { - suggestions := make([]*types.Suggestion, len(matches)) - for i, match := range matches { - suggestions[i] = &types.Suggestion{ + return slices.Map(matches, func(match string) *types.Suggestion { + return &types.Suggestion{ Value: match, Label: match, } - } - return suggestions + }) } func (self *SuggestionsHelper) GetRemoteSuggestionsFunc() func(string) []*types.Suggestion { @@ -76,11 +74,9 @@ func (self *SuggestionsHelper) GetRemoteSuggestionsFunc() func(string) []*types. } func (self *SuggestionsHelper) getBranchNames() []string { - result := make([]string, len(self.model.Branches)) - for i, branch := range self.model.Branches { - result[i] = branch.Name - } - return result + return slices.Map(self.model.Branches, func(branch *models.Branch) string { + return branch.Name + }) } func (self *SuggestionsHelper) GetBranchNameSuggestionsFunc() func(string) []*types.Suggestion { @@ -94,15 +90,12 @@ func (self *SuggestionsHelper) GetBranchNameSuggestionsFunc() func(string) []*ty matchingBranchNames = utils.FuzzySearch(input, branchNames) } - suggestions := make([]*types.Suggestion, len(matchingBranchNames)) - for i, branchName := range matchingBranchNames { - suggestions[i] = &types.Suggestion{ + return slices.Map(matchingBranchNames, func(branchName string) *types.Suggestion { + return &types.Suggestion{ Value: branchName, Label: presentation.GetBranchTextStyle(branchName).Sprint(branchName), } - } - - return suggestions + }) } } @@ -148,26 +141,16 @@ func (self *SuggestionsHelper) GetFilePathSuggestionsFunc() func(string) []*type // doing another fuzzy search for good measure matchingNames = utils.FuzzySearch(input, matchingNames) - suggestions := make([]*types.Suggestion, len(matchingNames)) - for i, name := range matchingNames { - suggestions[i] = &types.Suggestion{ - Value: name, - Label: name, - } - } - - return suggestions + return matchesToSuggestions(matchingNames) } } func (self *SuggestionsHelper) getRemoteBranchNames(separator string) []string { - result := []string{} - for _, remote := range self.model.Remotes { - for _, branch := range remote.Branches { - result = append(result, fmt.Sprintf("%s%s%s", remote.Name, separator, branch.Name)) - } - } - return result + return slices.FlatMap(self.model.Remotes, func(remote *models.Remote) []string { + return slices.Map(remote.Branches, func(branch *models.RemoteBranch) string { + return fmt.Sprintf("%s%s%s", remote.Name, separator, branch.Name) + }) + }) } func (self *SuggestionsHelper) GetRemoteBranchesSuggestionsFunc(separator string) func(string) []*types.Suggestion { @@ -175,11 +158,9 @@ func (self *SuggestionsHelper) GetRemoteBranchesSuggestionsFunc(separator string } func (self *SuggestionsHelper) getTagNames() []string { - result := make([]string, len(self.model.Tags)) - for i, tag := range self.model.Tags { - result[i] = tag.Name - } - return result + return slices.Map(self.model.Tags, func(tag *models.Tag) string { + return tag.Name + }) } func (self *SuggestionsHelper) GetRefsSuggestionsFunc() func(string) []*types.Suggestion { diff --git a/pkg/gui/files_panel_test.go b/pkg/gui/files_panel_test.go index 8946898e5..08d5d8838 100644 --- a/pkg/gui/files_panel_test.go +++ b/pkg/gui/files_panel_test.go @@ -3,6 +3,7 @@ package gui import ( "testing" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/stretchr/testify/assert" ) @@ -24,11 +25,7 @@ func TestGetSuggestedRemote(t *testing.T) { } func mkRemoteList(names ...string) []*models.Remote { - result := make([]*models.Remote, 0, len(names)) - - for _, name := range names { - result = append(result, &models.Remote{Name: name}) - } - - return result + return slices.Map(names, func(name string) *models.Remote { + return &models.Remote{Name: name} + }) } diff --git a/pkg/gui/filetree/commit_file_node.go b/pkg/gui/filetree/commit_file_node.go index ac2057da5..ad794c0c2 100644 --- a/pkg/gui/filetree/commit_file_node.go +++ b/pkg/gui/filetree/commit_file_node.go @@ -1,6 +1,7 @@ package filetree import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -40,19 +41,15 @@ func (s *CommitFileNode) GetPath() string { } func (s *CommitFileNode) GetChildren() []INode { - result := make([]INode, len(s.Children)) - for i, child := range s.Children { - result[i] = child - } - - return result + return slices.Map(s.Children, func(child *CommitFileNode) INode { + return child + }) } func (s *CommitFileNode) SetChildren(children []INode) { - castChildren := make([]*CommitFileNode, len(children)) - for i, child := range children { - castChildren[i] = child.(*CommitFileNode) - } + castChildren := slices.Map(children, func(child INode) *CommitFileNode { + return child.(*CommitFileNode) + }) s.Children = castChildren } @@ -102,12 +99,10 @@ func (s *CommitFileNode) EveryFile(test func(file *models.CommitFile) bool) bool func (n *CommitFileNode) Flatten(collapsedPaths *CollapsedPaths) []*CommitFileNode { results := flatten(n, collapsedPaths) - nodes := make([]*CommitFileNode, len(results)) - for i, result := range results { - nodes[i] = result.(*CommitFileNode) - } - return nodes + return slices.Map(results, func(result INode) *CommitFileNode { + return result.(*CommitFileNode) + }) } func (node *CommitFileNode) GetNodeAtIndex(index int, collapsedPaths *CollapsedPaths) *CommitFileNode { @@ -149,12 +144,10 @@ func (s *CommitFileNode) Compress() { func (s *CommitFileNode) GetLeaves() []*CommitFileNode { leaves := getLeaves(s) - castLeaves := make([]*CommitFileNode, len(leaves)) - for i := range leaves { - castLeaves[i] = leaves[i].(*CommitFileNode) - } - return castLeaves + return slices.Map(leaves, func(leaf INode) *CommitFileNode { + return leaf.(*CommitFileNode) + }) } // extra methods diff --git a/pkg/gui/filetree/file_node.go b/pkg/gui/filetree/file_node.go index e73504321..69663b000 100644 --- a/pkg/gui/filetree/file_node.go +++ b/pkg/gui/filetree/file_node.go @@ -1,6 +1,7 @@ package filetree import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -42,19 +43,15 @@ func (s *FileNode) GetPath() string { } func (s *FileNode) GetChildren() []INode { - result := make([]INode, len(s.Children)) - for i, child := range s.Children { - result[i] = child - } - - return result + return slices.Map(s.Children, func(child *FileNode) INode { + return child + }) } func (s *FileNode) SetChildren(children []INode) { - castChildren := make([]*FileNode, len(children)) - for i, child := range children { - castChildren[i] = child.(*FileNode) - } + castChildren := slices.Map(children, func(child INode) *FileNode { + return child.(*FileNode) + }) s.Children = castChildren } @@ -89,12 +86,9 @@ func (s *FileNode) Any(test func(node *FileNode) bool) bool { func (n *FileNode) Flatten(collapsedPaths *CollapsedPaths) []*FileNode { results := flatten(n, collapsedPaths) - nodes := make([]*FileNode, len(results)) - for i, result := range results { - nodes[i] = result.(*FileNode) - } - - return nodes + return slices.Map(results, func(result INode) *FileNode { + return result.(*FileNode) + }) } func (node *FileNode) GetNodeAtIndex(index int, collapsedPaths *CollapsedPaths) *FileNode { @@ -146,12 +140,10 @@ func (node *FileNode) GetFilePathsMatching(test func(*models.File) bool) []strin func (s *FileNode) GetLeaves() []*FileNode { leaves := getLeaves(s) - castLeaves := make([]*FileNode, len(leaves)) - for i := range leaves { - castLeaves[i] = leaves[i].(*FileNode) - } - return castLeaves + return slices.Map(leaves, func(leaf INode) *FileNode { + return leaf.(*FileNode) + }) } // extra methods diff --git a/pkg/gui/filetree/file_tree.go b/pkg/gui/filetree/file_tree.go index 47d7f32f2..d4bb8e596 100644 --- a/pkg/gui/filetree/file_tree.go +++ b/pkg/gui/filetree/file_tree.go @@ -3,6 +3,7 @@ package filetree import ( "fmt" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/sirupsen/logrus" ) @@ -85,13 +86,7 @@ func (self *FileTree) getFilesForDisplay() []*models.File { } func (self *FileTree) FilterFiles(test func(*models.File) bool) []*models.File { - result := make([]*models.File, 0) - for _, file := range self.getFiles() { - if test(file) { - result = append(result, file) - } - } - return result + return slices.Filter(self.getFiles(), test) } func (self *FileTree) SetFilter(filter FileTreeDisplayFilter) { diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index dcea5a936..5a3f172f0 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -3,6 +3,7 @@ package gui import ( "log" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/context" @@ -28,12 +29,9 @@ func (gui *Gui) filesListContext() *context.WorkingTreeContext { gui.Views.Files, func(startIdx int, length int) [][]string { lines := presentation.RenderFileTree(gui.State.Contexts.Files.FileTreeViewModel, gui.State.Modes.Diffing.Ref, gui.State.Model.Submodules) - mappedLines := make([][]string, len(lines)) - for i, line := range lines { - mappedLines[i] = []string{line} - } - - return mappedLines + return slices.Map(lines, func(line string) []string { + return []string{line} + }) }, OnFocusWrapper(gui.onFocusFile), OnFocusWrapper(gui.withDiffModeCheck(gui.filesRenderToMain)), @@ -235,12 +233,9 @@ func (gui *Gui) commitFilesListContext() *context.CommitFilesContext { } lines := presentation.RenderCommitFileTree(gui.State.Contexts.CommitFiles.CommitFileTreeViewModel, gui.State.Modes.Diffing.Ref, gui.git.Patch.PatchManager) - mappedLines := make([][]string, len(lines)) - for i, line := range lines { - mappedLines[i] = []string{line} - } - - return mappedLines + return slices.Map(lines, func(line string) []string { + return []string{line} + }) }, OnFocusWrapper(gui.onCommitFileFocus), OnFocusWrapper(gui.withDiffModeCheck(gui.commitFilesRenderToMain)), diff --git a/pkg/gui/options_menu_panel.go b/pkg/gui/options_menu_panel.go index 54f08ed50..c21a9dce3 100644 --- a/pkg/gui/options_menu_panel.go +++ b/pkg/gui/options_menu_panel.go @@ -4,6 +4,7 @@ import ( "log" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/gui/presentation" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" @@ -62,11 +63,8 @@ func (gui *Gui) handleCreateOptionsMenu() error { context := gui.currentContext() bindings := gui.getBindings(context) - menuItems := make([]*types.MenuItem, len(bindings)) - - for i, binding := range bindings { - binding := binding // note to self, never close over loop variables - menuItems[i] = &types.MenuItem{ + menuItems := slices.Map(bindings, func(binding *types.Binding) *types.MenuItem { + return &types.MenuItem{ DisplayStrings: []string{GetKeyDisplay(binding.Key), gui.displayDescription(binding)}, OnPress: func() error { if binding.Key == nil { @@ -78,7 +76,7 @@ func (gui *Gui) handleCreateOptionsMenu() error { return binding.Handler() }, } - } + }) return gui.c.Menu(types.CreateMenuOptions{ Title: strings.Title(gui.c.Tr.LcMenu), diff --git a/pkg/gui/presentation/branches.go b/pkg/gui/presentation/branches.go index 9062eface..b97ef6a5f 100644 --- a/pkg/gui/presentation/branches.go +++ b/pkg/gui/presentation/branches.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/i18n" @@ -14,14 +15,10 @@ import ( var branchPrefixColorCache = make(map[string]style.TextStyle) func GetBranchListDisplayStrings(branches []*models.Branch, fullDescription bool, diffName string, tr *i18n.TranslationSet) [][]string { - lines := make([][]string, len(branches)) - - for i := range branches { - diffed := branches[i].Name == diffName - lines[i] = getBranchDisplayStrings(branches[i], fullDescription, diffed, tr) - } - - return lines + return slices.Map(branches, func(branch *models.Branch) []string { + diffed := branch.Name == diffName + return getBranchDisplayStrings(branch, fullDescription, diffed, tr) + }) } // getBranchDisplayStrings returns the display string of branch diff --git a/pkg/gui/presentation/graph/graph.go b/pkg/gui/presentation/graph/graph.go index 70ab53079..de90d3e7a 100644 --- a/pkg/gui/presentation/graph/graph.go +++ b/pkg/gui/presentation/graph/graph.go @@ -5,10 +5,12 @@ import ( "strings" "sync" + "github.com/jesseduffield/generics/set" "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" ) type PipeKind uint8 @@ -77,7 +79,6 @@ func GetPipeSets(commits []*models.Commit, getStyle func(c *models.Commit) style func RenderAux(pipeSets [][]*Pipe, commits []*models.Commit, selectedCommitSha string) []string { maxProcs := runtime.GOMAXPROCS(0) - lines := make([]string, 0, len(pipeSets)) // splitting up the rendering of the graph into multiple goroutines allows us to render the graph in parallel chunks := make([][]string, maxProcs) perProc := len(pipeSets) / maxProcs @@ -110,24 +111,19 @@ func RenderAux(pipeSets [][]*Pipe, commits []*models.Commit, selectedCommitSha s wg.Wait() - for _, chunk := range chunks { - lines = append(lines, chunk...) - } - - return lines + return slices.Flatten(chunks) } func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *models.Commit) style.TextStyle) []*Pipe { - currentPipes := make([]*Pipe, 0, len(prevPipes)) - maxPos := 0 - for _, pipe := range prevPipes { - // a pipe that terminated in the previous line has no bearing on the current line - // so we'll filter those out - if pipe.kind != TERMINATES { - currentPipes = append(currentPipes, pipe) - } - maxPos = utils.Max(maxPos, pipe.toPos) - } + maxPos := lo.Max( + slices.Map(prevPipes, func(pipe *Pipe) int { return pipe.toPos }), + ) + + // a pipe that terminated in the previous line has no bearing on the current line + // so we'll filter those out + currentPipes := slices.Filter(prevPipes, func(pipe *Pipe) bool { + return pipe.kind != TERMINATES + }) newPipes := make([]*Pipe, 0, len(currentPipes)+len(commit.Parents)) // start by assuming that we've got a brand new commit not related to any preceding commit. @@ -142,9 +138,9 @@ func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *mod } // a taken spot is one where a current pipe is ending on - takenSpots := make(map[int]bool) + takenSpots := set.New[int]() // a traversed spot is one where a current pipe is starting on, ending on, or passing through - traversedSpots := make(map[int]bool) + traversedSpots := set.New[int]() if len(commit.Parents) > 0 { newPipes = append(newPipes, &Pipe{ @@ -157,17 +153,17 @@ func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *mod }) } - traversedSpotsForContinuingPipes := make(map[int]bool) + traversedSpotsForContinuingPipes := set.New[int]() for _, pipe := range currentPipes { if !equalHashes(pipe.toSha, commit.Sha) { - traversedSpotsForContinuingPipes[pipe.toPos] = true + traversedSpotsForContinuingPipes.Add(pipe.toPos) } } getNextAvailablePosForContinuingPipe := func() int { i := 0 for { - if !traversedSpots[i] { + if !traversedSpots.Includes(i) { return i } i++ @@ -179,7 +175,7 @@ func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *mod for { // a newly created pipe is not allowed to end on a spot that's already taken, // nor on a spot that's been traversed by a continuing pipe. - if !takenSpots[i] && !traversedSpotsForContinuingPipes[i] { + if !takenSpots.Includes(i) && !traversedSpotsForContinuingPipes.Includes(i) { return i } i++ @@ -192,9 +188,9 @@ func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *mod left, right = right, left } for i := left; i <= right; i++ { - traversedSpots[i] = true + traversedSpots.Add(i) } - takenSpots[to] = true + takenSpots.Add(to) } for _, pipe := range currentPipes { @@ -237,7 +233,7 @@ func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *mod style: getStyle(commit), }) - takenSpots[availablePos] = true + takenSpots.Add(availablePos) } } @@ -246,7 +242,7 @@ func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *mod // continuing on, potentially moving left to fill in a blank spot last := pipe.toPos for i := pipe.toPos; i > pos; i-- { - if takenSpots[i] || traversedSpots[i] { + if takenSpots.Includes(i) || traversedSpots.Includes(i) { break } else { last = i @@ -297,10 +293,9 @@ func renderPipeSet( } isMerge := startCount > 1 - cells := make([]*Cell, maxPos+1) - for i := range cells { - cells[i] = &Cell{cellType: CONNECTION, style: style.FgDefault} - } + cells := slices.Map(lo.Range(maxPos+1), func(i int) *Cell { + return &Cell{cellType: CONNECTION, style: style.FgDefault} + }) renderPipe := func(pipe *Pipe, style style.TextStyle, overrideRightStyle bool) { left := pipe.left() @@ -336,17 +331,9 @@ func renderPipeSet( // so we have our commit pos again, now it's time to build the cells. // we'll handle the one that's sourced from our selected commit last so that it can override the other cells. - selectedPipes := []*Pipe{} - // pre-allocating this one because most of the time we'll only have non-selected pipes - nonSelectedPipes := make([]*Pipe, 0, len(pipes)) - - for _, pipe := range pipes { - if highlight && equalHashes(pipe.fromSha, selectedCommitSha) { - selectedPipes = append(selectedPipes, pipe) - } else { - nonSelectedPipes = append(nonSelectedPipes, pipe) - } - } + selectedPipes, nonSelectedPipes := slices.Partition(pipes, func(pipe *Pipe) bool { + return highlight && equalHashes(pipe.fromSha, selectedCommitSha) + }) for _, pipe := range nonSelectedPipes { if pipe.kind == STARTS { diff --git a/pkg/gui/presentation/reflog_commits.go b/pkg/gui/presentation/reflog_commits.go index 72bb80ef6..95124c867 100644 --- a/pkg/gui/presentation/reflog_commits.go +++ b/pkg/gui/presentation/reflog_commits.go @@ -2,6 +2,7 @@ package presentation import ( "github.com/jesseduffield/generics/set" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/theme" @@ -10,8 +11,6 @@ import ( ) func GetReflogCommitListDisplayStrings(commits []*models.Commit, fullDescription bool, cherryPickedCommitShaSet *set.Set[string], diffName string, parseEmoji bool) [][]string { - lines := make([][]string, len(commits)) - var displayFunc func(*models.Commit, bool, bool, bool) []string if fullDescription { displayFunc = getFullDescriptionDisplayStringsForReflogCommit @@ -19,13 +18,11 @@ func GetReflogCommitListDisplayStrings(commits []*models.Commit, fullDescription displayFunc = getDisplayStringsForReflogCommit } - for i := range commits { - diffed := commits[i].Sha == diffName - cherryPicked := cherryPickedCommitShaSet.Includes(commits[i].Sha) - lines[i] = displayFunc(commits[i], cherryPicked, diffed, parseEmoji) - } - - return lines + return slices.Map(commits, func(commit *models.Commit) []string { + diffed := commit.Sha == diffName + cherryPicked := cherryPickedCommitShaSet.Includes(commit.Sha) + return displayFunc(commit, cherryPicked, diffed, parseEmoji) + }) } func reflogShaColor(cherryPicked, diffed bool) style.TextStyle { diff --git a/pkg/gui/presentation/remote_branches.go b/pkg/gui/presentation/remote_branches.go index d8439acfe..c5c54dfcb 100644 --- a/pkg/gui/presentation/remote_branches.go +++ b/pkg/gui/presentation/remote_branches.go @@ -1,19 +1,16 @@ package presentation import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/theme" ) func GetRemoteBranchListDisplayStrings(branches []*models.RemoteBranch, diffName string) [][]string { - lines := make([][]string, len(branches)) - - for i := range branches { - diffed := branches[i].FullName() == diffName - lines[i] = getRemoteBranchDisplayStrings(branches[i], diffed) - } - - return lines + return slices.Map(branches, func(branch *models.RemoteBranch) []string { + diffed := branch.FullName() == diffName + return getRemoteBranchDisplayStrings(branch, diffed) + }) } // getRemoteBranchDisplayStrings returns the display string of branch diff --git a/pkg/gui/presentation/remotes.go b/pkg/gui/presentation/remotes.go index a1e50fe2f..9b26cbfae 100644 --- a/pkg/gui/presentation/remotes.go +++ b/pkg/gui/presentation/remotes.go @@ -1,20 +1,17 @@ package presentation import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/theme" ) func GetRemoteListDisplayStrings(remotes []*models.Remote, diffName string) [][]string { - lines := make([][]string, len(remotes)) - - for i := range remotes { - diffed := remotes[i].Name == diffName - lines[i] = getRemoteDisplayStrings(remotes[i], diffed) - } - - return lines + return slices.Map(remotes, func(remote *models.Remote) []string { + diffed := remote.Name == diffName + return getRemoteDisplayStrings(remote, diffed) + }) } // getRemoteDisplayStrings returns the display string of branch diff --git a/pkg/gui/presentation/stash_entries.go b/pkg/gui/presentation/stash_entries.go index f15b35a9c..54b39c636 100644 --- a/pkg/gui/presentation/stash_entries.go +++ b/pkg/gui/presentation/stash_entries.go @@ -1,19 +1,16 @@ package presentation import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/theme" ) func GetStashEntryListDisplayStrings(stashEntries []*models.StashEntry, diffName string) [][]string { - lines := make([][]string, len(stashEntries)) - - for i := range stashEntries { - diffed := stashEntries[i].RefName() == diffName - lines[i] = getStashEntryDisplayStrings(stashEntries[i], diffed) - } - - return lines + return slices.Map(stashEntries, func(stashEntry *models.StashEntry) []string { + diffed := stashEntry.RefName() == diffName + return getStashEntryDisplayStrings(stashEntry, diffed) + }) } // getStashEntryDisplayStrings returns the display string of branch diff --git a/pkg/gui/presentation/submodules.go b/pkg/gui/presentation/submodules.go index 2d131ed8f..0fb057ef0 100644 --- a/pkg/gui/presentation/submodules.go +++ b/pkg/gui/presentation/submodules.go @@ -1,18 +1,15 @@ package presentation import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/theme" ) func GetSubmoduleListDisplayStrings(submodules []*models.SubmoduleConfig) [][]string { - lines := make([][]string, len(submodules)) - - for i := range submodules { - lines[i] = getSubmoduleDisplayStrings(submodules[i]) - } - - return lines + return slices.Map(submodules, func(submodule *models.SubmoduleConfig) []string { + return getSubmoduleDisplayStrings(submodule) + }) } func getSubmoduleDisplayStrings(s *models.SubmoduleConfig) []string { diff --git a/pkg/gui/presentation/suggestions.go b/pkg/gui/presentation/suggestions.go index 81c6a3a3d..5319b40f7 100644 --- a/pkg/gui/presentation/suggestions.go +++ b/pkg/gui/presentation/suggestions.go @@ -1,17 +1,14 @@ package presentation import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/gui/types" ) func GetSuggestionListDisplayStrings(suggestions []*types.Suggestion) [][]string { - lines := make([][]string, len(suggestions)) - - for i := range suggestions { - lines[i] = getSuggestionDisplayStrings(suggestions[i]) - } - - return lines + return slices.Map(suggestions, func(suggestion *types.Suggestion) []string { + return getSuggestionDisplayStrings(suggestion) + }) } func getSuggestionDisplayStrings(suggestion *types.Suggestion) []string { diff --git a/pkg/gui/presentation/tags.go b/pkg/gui/presentation/tags.go index 4754c4bef..2157e29c9 100644 --- a/pkg/gui/presentation/tags.go +++ b/pkg/gui/presentation/tags.go @@ -1,19 +1,16 @@ package presentation import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/theme" ) func GetTagListDisplayStrings(tags []*models.Tag, diffName string) [][]string { - lines := make([][]string, len(tags)) - - for i := range tags { - diffed := tags[i].Name == diffName - lines[i] = getTagDisplayStrings(tags[i], diffed) - } - - return lines + return slices.Map(tags, func(tag *models.Tag) []string { + diffed := tag.Name == diffName + return getTagDisplayStrings(tag, diffed) + }) } // getTagDisplayStrings returns the display string of branch diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index 73ee784c3..38684809b 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -4,22 +4,19 @@ import ( "os" "path/filepath" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/env" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/jesseduffield/lazygit/pkg/utils" ) func (gui *Gui) handleCreateRecentReposMenu() error { recentRepoPaths := gui.c.GetAppState().RecentRepos - reposCount := utils.Min(len(recentRepoPaths), 20) // we won't show the current repo hence the -1 - menuItems := make([]*types.MenuItem, reposCount-1) - for i, path := range recentRepoPaths[1:reposCount] { - path := path // cos we're closing over the loop variable - menuItems[i] = &types.MenuItem{ + menuItems := slices.Map(recentRepoPaths[1:], func(path string) *types.MenuItem { + return &types.MenuItem{ DisplayStrings: []string{ filepath.Base(path), style.FgMagenta.Sprint(path), @@ -31,7 +28,7 @@ func (gui *Gui) handleCreateRecentReposMenu() error { return gui.dispatchSwitchToRepo(path, false) }, } - } + }) return gui.c.Menu(types.CreateMenuOptions{Title: gui.c.Tr.RecentRepos, Items: menuItems}) } diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go index 5252d7ec9..602eb37e9 100644 --- a/pkg/gui/refresh.go +++ b/pkg/gui/refresh.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/jesseduffield/generics/set" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/loaders" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" @@ -32,12 +33,9 @@ func getScopeNames(scopes []types.RefreshableView) []string { types.BISECT_INFO: "bisect", } - scopeNames := make([]string, len(scopes)) - for i, scope := range scopes { - scopeNames[i] = scopeNameMap[scope] - } - - return scopeNames + return slices.Map(scopes, func(scope types.RefreshableView) string { + return scopeNameMap[scope] + }) } func getModeName(mode types.RefreshMode) string { diff --git a/pkg/gui/services/custom_commands/handler_creator.go b/pkg/gui/services/custom_commands/handler_creator.go index 04e6cb644..dbae84de7 100644 --- a/pkg/gui/services/custom_commands/handler_creator.go +++ b/pkg/gui/services/custom_commands/handler_creator.go @@ -1,6 +1,7 @@ package custom_commands import ( + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/config" @@ -99,16 +100,14 @@ func (self *HandlerCreator) inputPrompt(prompt *config.CustomCommandPrompt, wrap } func (self *HandlerCreator) menuPrompt(prompt *config.CustomCommandPrompt, wrappedF func(string) error) error { - menuItems := make([]*types.MenuItem, len(prompt.Options)) - for i, option := range prompt.Options { - option := option - menuItems[i] = &types.MenuItem{ + menuItems := slices.Map(prompt.Options, func(option config.CustomCommandMenuOption) *types.MenuItem { + return &types.MenuItem{ DisplayStrings: []string{option.Name, style.FgYellow.Sprint(option.Description)}, OnPress: func() error { return wrappedF(option.Value) }, } - } + }) return self.c.Menu(types.CreateMenuOptions{Title: prompt.Title, Items: menuItems}) } @@ -126,16 +125,14 @@ func (self *HandlerCreator) menuPromptFromCommand(prompt *config.CustomCommandPr return self.c.Error(err) } - menuItems := make([]*types.MenuItem, len(candidates)) - for i := range candidates { - i := i - menuItems[i] = &types.MenuItem{ - DisplayStrings: []string{candidates[i].label}, + menuItems := slices.Map(candidates, func(candidate *commandMenuEntry) *types.MenuItem { + return &types.MenuItem{ + DisplayStrings: []string{candidate.label}, OnPress: func() error { - return wrappedF(candidates[i].value) + return wrappedF(candidate.value) }, } - } + }) return self.c.Menu(types.CreateMenuOptions{Title: prompt.Title, Items: menuItems}) } diff --git a/pkg/gui/services/custom_commands/keybinding_creator.go b/pkg/gui/services/custom_commands/keybinding_creator.go index e3c233951..ed2921359 100644 --- a/pkg/gui/services/custom_commands/keybinding_creator.go +++ b/pkg/gui/services/custom_commands/keybinding_creator.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/context" @@ -77,11 +78,9 @@ func (self *KeybindingCreator) contextForContextKey(contextKey types.ContextKey) } func formatUnknownContextError(customCommand config.CustomCommand) error { - // stupid golang making me build an array of strings for this. - allContextKeyStrings := make([]string, len(context.AllContextKeys)) - for i := range context.AllContextKeys { - allContextKeyStrings[i] = string(context.AllContextKeys[i]) - } + allContextKeyStrings := slices.Map(context.AllContextKeys, func(key types.ContextKey) string { + return string(key) + }) return fmt.Errorf("Error when setting custom command keybindings: unknown context: %s. Key: %s, Command: %s.\nPermitted contexts: %s", customCommand.Context, customCommand.Key, customCommand.Command, strings.Join(allContextKeyStrings, ", ")) } diff --git a/pkg/gui/status_panel.go b/pkg/gui/status_panel.go index 6ca6e6996..cde535cd9 100644 --- a/pkg/gui/status_panel.go +++ b/pkg/gui/status_panel.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/types/enums" "github.com/jesseduffield/lazygit/pkg/constants" "github.com/jesseduffield/lazygit/pkg/gui/presentation" @@ -102,16 +103,15 @@ func (gui *Gui) askForConfigFile(action func(file string) error) error { case 1: return action(confPaths[0]) default: - menuItems := make([]*types.MenuItem, len(confPaths)) - for i, file := range confPaths { - i := i - menuItems[i] = &types.MenuItem{ - DisplayString: file, + menuItems := slices.Map(confPaths, func(path string) *types.MenuItem { + return &types.MenuItem{ + DisplayString: path, OnPress: func() error { - return action(confPaths[i]) + return action(path) }, } - } + }) + return gui.c.Menu(types.CreateMenuOptions{ Title: gui.c.Tr.SelectConfigFile, Items: menuItems, diff --git a/pkg/utils/formatting.go b/pkg/utils/formatting.go index d33028063..657d1d2eb 100644 --- a/pkg/utils/formatting.go +++ b/pkg/utils/formatting.go @@ -3,7 +3,9 @@ package utils import ( "strings" + "github.com/jesseduffield/generics/slices" "github.com/mattn/go-runewidth" + "github.com/samber/lo" ) // WithPadding pads a string as much as you want @@ -83,27 +85,20 @@ func getPaddedDisplayStrings(stringArrays [][]string, padWidths []int) string { } func getPadWidths(stringArrays [][]string) []int { - maxWidth := 0 - for _, stringArray := range stringArrays { - if len(stringArray) > maxWidth { - maxWidth = len(stringArray) - } - } + maxWidth := slices.MaxBy(stringArrays, func(stringArray []string) int { + return len(stringArray) + }) + if maxWidth-1 < 0 { return []int{} } - padWidths := make([]int, maxWidth-1) - for i := range padWidths { - for _, strings := range stringArrays { - uncoloredStr := Decolorise(strings[i]) + return slices.Map(lo.Range(maxWidth-1), func(i int) int { + return slices.MaxBy(stringArrays, func(stringArray []string) int { + uncoloredStr := Decolorise(stringArray[i]) - width := runewidth.StringWidth(uncoloredStr) - if width > padWidths[i] { - padWidths[i] = width - } - } - } - return padWidths + return runewidth.StringWidth(uncoloredStr) + }) + }) } // TruncateWithEllipsis returns a string, truncated to a certain length, with an ellipsis diff --git a/pkg/utils/fuzzy_search.go b/pkg/utils/fuzzy_search.go index 4199d6c8b..5fce3dde9 100644 --- a/pkg/utils/fuzzy_search.go +++ b/pkg/utils/fuzzy_search.go @@ -3,6 +3,7 @@ package utils import ( "sort" + "github.com/jesseduffield/generics/slices" "github.com/sahilm/fuzzy" ) @@ -14,10 +15,7 @@ func FuzzySearch(needle string, haystack []string) []string { matches := fuzzy.Find(needle, haystack) sort.Sort(matches) - result := make([]string, len(matches)) - for i, match := range matches { - result[i] = match.Str - } - - return result + return slices.Map(matches, func(match fuzzy.Match) string { + return match.Str + }) } diff --git a/vendor/github.com/jesseduffield/generics/slices/slices.go b/vendor/github.com/jesseduffield/generics/slices/slices.go index b9c783caf..ec5653ddc 100644 --- a/vendor/github.com/jesseduffield/generics/slices/slices.go +++ b/vendor/github.com/jesseduffield/generics/slices/slices.go @@ -1,6 +1,7 @@ package slices import ( + "golang.org/x/exp/constraints" "golang.org/x/exp/slices" ) @@ -28,14 +29,34 @@ func Every[T any](slice []T, test func(T) bool) bool { // Produces a new slice, leaves the input slice untouched. func Map[T any, V any](slice []T, f func(T) V) []V { - result := make([]V, len(slice)) - for i, value := range slice { - result[i] = f(value) + result := make([]V, 0, len(slice)) + for _, value := range slice { + result = append(result, f(value)) } return result } +// Produces a new slice, leaves the input slice untouched. +func FlatMap[T any, V any](slice []T, f func(T) []V) []V { + // impossible to know how long this slice will be in the end but the length + // of the original slice is the lower bound + result := make([]V, 0, len(slice)) + for _, value := range slice { + result = append(result, f(value)...) + } + + return result +} + +func Flatten[T any](slice [][]T) []T { + result := make([]T, 0, len(slice)) + for _, subSlice := range slice { + result = append(result, subSlice...) + } + return result +} + func MapInPlace[T any](slice []T, f func(T) T) { for i, value := range slice { slice[i] = f(value) @@ -152,3 +173,53 @@ func Shift[T any](slice []T) (T, []T) { slice = slice[1:] return value, slice } + +func Partition[T any](slice []T, test func(T) bool) ([]T, []T) { + left := make([]T, 0, len(slice)) + right := make([]T, 0, len(slice)) + + for _, value := range slice { + if test(value) { + left = append(left, value) + } else { + right = append(right, value) + } + } + + return left, right +} + +func MaxBy[T any, V constraints.Ordered](slice []T, f func(T) V) V { + if len(slice) == 0 { + return zero[V]() + } + + max := f(slice[0]) + for _, element := range slice[1:] { + value := f(element) + if value > max { + max = value + } + } + return max +} + +func MinBy[T any, V constraints.Ordered](slice []T, f func(T) V) V { + if len(slice) == 0 { + return zero[V]() + } + + min := f(slice[0]) + for _, element := range slice[1:] { + value := f(element) + if value < min { + min = value + } + } + return min +} + +func zero[T any]() T { + var value T + return value +} diff --git a/vendor/modules.txt b/vendor/modules.txt index b7234a630..332871ffe 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -120,7 +120,7 @@ github.com/integrii/flaggy # github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 ## explicit github.com/jbenet/go-context/io -# github.com/jesseduffield/generics v0.0.0-20220319062156-fa5cb8bde518 +# github.com/jesseduffield/generics v0.0.0-20220319080325-a60171f800d5 ## explicit; go 1.18 github.com/jesseduffield/generics/maps github.com/jesseduffield/generics/set From 94a53484a183bb32b066dc51fb90948dead634a1 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 19 Mar 2022 19:51:48 +1100 Subject: [PATCH 117/385] would you believe that I'm adding even more generics --- go.mod | 2 +- go.sum | 4 ++-- .../hosting_service/hosting_service.go | 8 +++---- pkg/commands/loaders/commits.go | 5 +++-- pkg/commands/loaders/remotes.go | 5 ++--- pkg/commands/loaders/stash.go | 9 ++++---- pkg/commands/patch/patch_parser.go | 2 +- pkg/gui/app_status_manager.go | 11 ++++------ pkg/gui/context.go | 16 +++++++------- .../controllers/helpers/cherry_pick_helper.go | 3 +-- pkg/gui/filetree/inode.go | 9 +++----- pkg/gui/presentation/graph/graph.go | 15 +++++-------- .../jesseduffield/generics/slices/slices.go | 22 +++++++++++++++++++ vendor/modules.txt | 2 +- 14 files changed, 62 insertions(+), 51 deletions(-) diff --git a/go.mod b/go.mod index bc85923d9..958440ca6 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gookit/color v1.4.2 github.com/imdario/mergo v0.3.11 github.com/integrii/flaggy v1.4.0 - github.com/jesseduffield/generics v0.0.0-20220319080325-a60171f800d5 + github.com/jesseduffield/generics v0.0.0-20220319083513-5f145a9c0677 github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e diff --git a/go.sum b/go.sum index eff282697..e99d02da5 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jesseduffield/generics v0.0.0-20220319080325-a60171f800d5 h1:mZf9Ezkd4Thuw2tj5naFeoUbHkbNiD38LQFokUGSbtQ= -github.com/jesseduffield/generics v0.0.0-20220319080325-a60171f800d5/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= +github.com/jesseduffield/generics v0.0.0-20220319083513-5f145a9c0677 h1:GoP06WWOE4AvTkAavXkF40nhYsg2hI09uVLDIuxzZYI= +github.com/jesseduffield/generics v0.0.0-20220319083513-5f145a9c0677/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 h1:9N08i5kjvOfkzMj6THmIM110wPTQLdVYEOHMHT2DFiI= diff --git a/pkg/commands/hosting_service/hosting_service.go b/pkg/commands/hosting_service/hosting_service.go index 15fc244ba..091da3ebb 100644 --- a/pkg/commands/hosting_service/hosting_service.go +++ b/pkg/commands/hosting_service/hosting_service.go @@ -111,10 +111,10 @@ func (self *HostingServiceMgr) getCandidateServiceDomains() []ServiceDomain { serviceDefinition, ok := serviceDefinitionByProvider[provider] if !ok { - providerNames := []string{} - for _, serviceDefinition := range serviceDefinitions { - providerNames = append(providerNames, serviceDefinition.provider) - } + providerNames := slices.Map(serviceDefinitions, func(serviceDefinition ServiceDefinition) string { + return serviceDefinition.provider + }) + self.log.Errorf("Unknown git service type: '%s'. Expected one of %s", provider, strings.Join(providerNames, ", ")) continue } diff --git a/pkg/commands/loaders/commits.go b/pkg/commands/loaders/commits.go index 20721be42..c370cc059 100644 --- a/pkg/commands/loaders/commits.go +++ b/pkg/commands/loaders/commits.go @@ -307,6 +307,7 @@ func (self *CommitLoader) getInteractiveRebasingCommits() ([]*models.Commit, err commits := []*models.Commit{} lines := strings.Split(string(bytesContent), "\n") + for _, line := range lines { if line == "" || line == "noop" { return commits, nil @@ -315,12 +316,12 @@ func (self *CommitLoader) getInteractiveRebasingCommits() ([]*models.Commit, err continue } splitLine := strings.Split(line, " ") - commits = append([]*models.Commit{{ + commits = slices.Prepend(commits, &models.Commit{ Sha: splitLine[1], Name: strings.Join(splitLine[2:], " "), Status: "rebasing", Action: splitLine[0], - }}, commits...) + }) } return commits, nil diff --git a/pkg/commands/loaders/remotes.go b/pkg/commands/loaders/remotes.go index 3cd57d9a2..1323560f5 100644 --- a/pkg/commands/loaders/remotes.go +++ b/pkg/commands/loaders/remotes.go @@ -10,7 +10,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/common" - "github.com/samber/lo" ) type RemoteLoader struct { @@ -43,12 +42,12 @@ func (self *RemoteLoader) GetRemotes() ([]*models.Remote, error) { } // first step is to get our remotes from go-git - remotes := lo.Map(goGitRemotes, func(goGitRemote *gogit.Remote, _ int) *models.Remote { + remotes := slices.Map(goGitRemotes, func(goGitRemote *gogit.Remote) *models.Remote { remoteName := goGitRemote.Config().Name re := regexp.MustCompile(fmt.Sprintf(`(?m)^\s*%s\/([\S]+)`, remoteName)) matches := re.FindAllStringSubmatch(remoteBranchesStr, -1) - branches := lo.Map(matches, func(match []string, _ int) *models.RemoteBranch { + branches := slices.Map(matches, func(match []string) *models.RemoteBranch { return &models.RemoteBranch{ Name: match[1], RemoteName: remoteName, diff --git a/pkg/commands/loaders/stash.go b/pkg/commands/loaders/stash.go index 689bf30ce..66cfeaa3e 100644 --- a/pkg/commands/loaders/stash.go +++ b/pkg/commands/loaders/stash.go @@ -5,6 +5,7 @@ import ( "strconv" "strings" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/common" @@ -65,11 +66,9 @@ outer: func (self *StashLoader) getUnfilteredStashEntries() []*models.StashEntry { rawString, _ := self.cmd.New("git stash list --pretty='%gs'").DontLog().RunWithOutput() - stashEntries := []*models.StashEntry{} - for i, line := range utils.SplitLines(rawString) { - stashEntries = append(stashEntries, self.stashEntryFromLine(line, i)) - } - return stashEntries + return slices.MapWithIndex(utils.SplitLines(rawString), func(line string, index int) *models.StashEntry { + return self.stashEntryFromLine(line, index) + }) } func (c *StashLoader) stashEntryFromLine(line string, index int) *models.StashEntry { diff --git a/pkg/commands/patch/patch_parser.go b/pkg/commands/patch/patch_parser.go index 097f01329..fa730afe7 100644 --- a/pkg/commands/patch/patch_parser.go +++ b/pkg/commands/patch/patch_parser.go @@ -191,7 +191,7 @@ func (p *PatchParser) Render(firstLineIndex int, lastLineIndex int, incLineIndic return "" } - renderedLines := lo.Map(p.PatchLines, func(patchLine *PatchLine, index int) string { + renderedLines := slices.MapWithIndex(p.PatchLines, func(patchLine *PatchLine, index int) string { selected := index >= firstLineIndex && index <= lastLineIndex included := lo.Contains(incLineIndices, index) return patchLine.render(selected, included) diff --git a/pkg/gui/app_status_manager.go b/pkg/gui/app_status_manager.go index 4c32f79b5..34c97a5f4 100644 --- a/pkg/gui/app_status_manager.go +++ b/pkg/gui/app_status_manager.go @@ -4,6 +4,7 @@ import ( "sync" "time" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/utils" ) @@ -23,13 +24,9 @@ func (m *statusManager) removeStatus(id int) { m.mutex.Lock() defer m.mutex.Unlock() - newStatuses := []appStatus{} - for _, status := range m.statuses { - if status.id != id { - newStatuses = append(newStatuses, status) - } - } - m.statuses = newStatuses + m.statuses = slices.Filter(m.statuses, func(status appStatus) bool { + return status.id != id + }) } func (m *statusManager) addWaitingStatus(message string) int { diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 2c30218bc..13b55e342 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -14,14 +14,14 @@ import ( ) func (gui *Gui) popupViewNames() []string { - result := []string{} - for _, context := range gui.State.Contexts.Flatten() { - if context.GetKind() == types.PERSISTENT_POPUP || context.GetKind() == types.TEMPORARY_POPUP { - result = append(result, context.GetViewName()) - } - } - - return result + return slices.FilterThenMap(gui.State.Contexts.Flatten(), + func(c types.Context) bool { + return c.GetKind() == types.PERSISTENT_POPUP || c.GetKind() == types.TEMPORARY_POPUP + }, + func(c types.Context) string { + return c.GetViewName() + }, + ) } func (gui *Gui) currentContextKeyIgnoringPopups() types.ContextKey { diff --git a/pkg/gui/controllers/helpers/cherry_pick_helper.go b/pkg/gui/controllers/helpers/cherry_pick_helper.go index c433655d0..9117f24f6 100644 --- a/pkg/gui/controllers/helpers/cherry_pick_helper.go +++ b/pkg/gui/controllers/helpers/cherry_pick_helper.go @@ -8,7 +8,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/modes/cherrypicking" "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/samber/lo" ) type CherryPickHelper struct { @@ -109,7 +108,7 @@ func (self *CherryPickHelper) Reset() error { } func (self *CherryPickHelper) CherryPickedCommitShaSet() *set.Set[string] { - shas := lo.Map(self.getData().CherryPickedCommits, func(commit *models.Commit, _ int) string { + shas := slices.Map(self.getData().CherryPickedCommits, func(commit *models.Commit) string { return commit.Sha }) return set.NewFromSlice(shas) diff --git a/pkg/gui/filetree/inode.go b/pkg/gui/filetree/inode.go index 48cdc3be3..d59315b28 100644 --- a/pkg/gui/filetree/inode.go +++ b/pkg/gui/filetree/inode.go @@ -200,10 +200,7 @@ func getLeaves(node INode) []INode { return []INode{node} } - output := []INode{} - for _, child := range node.GetChildren() { - output = append(output, getLeaves(child)...) - } - - return output + return slices.FlatMap(node.GetChildren(), func(child INode) []INode { + return getLeaves(child) + }) } diff --git a/pkg/gui/presentation/graph/graph.go b/pkg/gui/presentation/graph/graph.go index de90d3e7a..392af8984 100644 --- a/pkg/gui/presentation/graph/graph.go +++ b/pkg/gui/presentation/graph/graph.go @@ -67,13 +67,10 @@ func GetPipeSets(commits []*models.Commit, getStyle func(c *models.Commit) style pipes := []*Pipe{{fromPos: 0, toPos: 0, fromSha: "START", toSha: commits[0].Sha, kind: STARTS, style: style.FgDefault}} - pipeSets := [][]*Pipe{} - for _, commit := range commits { + return slices.Map(commits, func(commit *models.Commit) []*Pipe { pipes = getNextPipes(pipes, commit, getStyle) - pipeSets = append(pipeSets, pipes) - } - - return pipeSets + return pipes + }) } func RenderAux(pipeSets [][]*Pipe, commits []*models.Commit, selectedCommitSha string) []string { @@ -115,9 +112,9 @@ func RenderAux(pipeSets [][]*Pipe, commits []*models.Commit, selectedCommitSha s } func getNextPipes(prevPipes []*Pipe, commit *models.Commit, getStyle func(c *models.Commit) style.TextStyle) []*Pipe { - maxPos := lo.Max( - slices.Map(prevPipes, func(pipe *Pipe) int { return pipe.toPos }), - ) + maxPos := slices.MaxBy(prevPipes, func(pipe *Pipe) int { + return pipe.toPos + }) // a pipe that terminated in the previous line has no bearing on the current line // so we'll filter those out diff --git a/vendor/github.com/jesseduffield/generics/slices/slices.go b/vendor/github.com/jesseduffield/generics/slices/slices.go index ec5653ddc..1d224255a 100644 --- a/vendor/github.com/jesseduffield/generics/slices/slices.go +++ b/vendor/github.com/jesseduffield/generics/slices/slices.go @@ -37,6 +37,16 @@ func Map[T any, V any](slice []T, f func(T) V) []V { return result } +// Produces a new slice, leaves the input slice untouched. +func MapWithIndex[T any, V any](slice []T, f func(T, int) V) []V { + result := make([]V, 0, len(slice)) + for i, value := range slice { + result = append(result, f(value, i)) + } + + return result +} + // Produces a new slice, leaves the input slice untouched. func FlatMap[T any, V any](slice []T, f func(T) []V) []V { // impossible to know how long this slice will be in the end but the length @@ -74,6 +84,18 @@ func Filter[T any](slice []T, test func(T) bool) []T { return result } +// Produces a new slice, leaves the input slice untouched. +func FilterWithIndex[T any](slice []T, f func(T, int) bool) []T { + result := make([]T, 0, len(slice)) + for i, value := range slice { + if f(value, i) { + result = append(result, value) + } + } + + return result +} + // Mutates original slice. Intended usage is to reassign the slice result to the input slice. func FilterInPlace[T any](slice []T, test func(T) bool) []T { newLength := 0 diff --git a/vendor/modules.txt b/vendor/modules.txt index 332871ffe..a7b196cea 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -120,7 +120,7 @@ github.com/integrii/flaggy # github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 ## explicit github.com/jbenet/go-context/io -# github.com/jesseduffield/generics v0.0.0-20220319080325-a60171f800d5 +# github.com/jesseduffield/generics v0.0.0-20220319083513-5f145a9c0677 ## explicit; go 1.18 github.com/jesseduffield/generics/maps github.com/jesseduffield/generics/set From 67a76523fb8029a31fd540fdd5dc9aaf1c2e8473 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 19 Mar 2022 21:01:10 +1100 Subject: [PATCH 118/385] rename --- pkg/gui/context.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 13b55e342..75e2a7357 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -233,11 +233,11 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro } func (gui *Gui) optionsMapToString(optionsMap map[string]string) string { - optionsArray := maps.MapToSlice(optionsMap, func(key string, description string) string { + options := maps.MapToSlice(optionsMap, func(key string, description string) string { return key + ": " + description }) - sort.Strings(optionsArray) - return strings.Join(optionsArray, ", ") + sort.Strings(options) + return strings.Join(options, ", ") } func (gui *Gui) renderOptionsMap(optionsMap map[string]string) { From e392b9f86ab7683b231de4c1addd1986cffc9d91 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 20 Mar 2022 09:24:39 +1100 Subject: [PATCH 119/385] no more filterThenMap --- pkg/gui/context.go | 15 +++++++-------- pkg/gui/controllers/helpers/cherry_pick_helper.go | 13 ++++++------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 75e2a7357..e75eb0a05 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -14,14 +14,13 @@ import ( ) func (gui *Gui) popupViewNames() []string { - return slices.FilterThenMap(gui.State.Contexts.Flatten(), - func(c types.Context) bool { - return c.GetKind() == types.PERSISTENT_POPUP || c.GetKind() == types.TEMPORARY_POPUP - }, - func(c types.Context) string { - return c.GetViewName() - }, - ) + popups := slices.Filter(gui.State.Contexts.Flatten(), func(c types.Context) bool { + return c.GetKind() == types.PERSISTENT_POPUP || c.GetKind() == types.TEMPORARY_POPUP + }) + + return slices.Map(popups, func(c types.Context) string { + return c.GetViewName() + }) } func (gui *Gui) currentContextKeyIgnoringPopups() types.ContextKey { diff --git a/pkg/gui/controllers/helpers/cherry_pick_helper.go b/pkg/gui/controllers/helpers/cherry_pick_helper.go index 9117f24f6..2c9ca301a 100644 --- a/pkg/gui/controllers/helpers/cherry_pick_helper.go +++ b/pkg/gui/controllers/helpers/cherry_pick_helper.go @@ -118,14 +118,13 @@ func (self *CherryPickHelper) add(selectedCommit *models.Commit, commitsList []* commitSet := self.CherryPickedCommitShaSet() commitSet.Add(selectedCommit.Sha) - newCommits := slices.FilterThenMap(commitsList, - func(commit *models.Commit) bool { return commitSet.Includes(commit.Sha) }, - func(commit *models.Commit) *models.Commit { - return &models.Commit{Name: commit.Name, Sha: commit.Sha} - }, - ) + cherryPickedCommits := slices.Filter(commitsList, func(commit *models.Commit) bool { + return commitSet.Includes(commit.Sha) + }) - self.getData().CherryPickedCommits = newCommits + self.getData().CherryPickedCommits = slices.Map(cherryPickedCommits, func(commit *models.Commit) *models.Commit { + return &models.Commit{Name: commit.Name, Sha: commit.Sha} + }) } // you can only copy from one context at a time, because the order and position of commits matter From cb26c7a1f20d754665e68db7abc8df3382cef66a Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 20 Mar 2022 10:19:14 +1100 Subject: [PATCH 120/385] more things --- go.mod | 2 +- go.sum | 4 +- pkg/app/app.go | 28 ++-- pkg/cheatsheet/generate.go | 9 +- pkg/gui/information_panel.go | 23 +-- .../jesseduffield/generics/slices/slices.go | 149 +++++++++++++++++- vendor/modules.txt | 2 +- 7 files changed, 176 insertions(+), 41 deletions(-) diff --git a/go.mod b/go.mod index 958440ca6..fd00f19d8 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gookit/color v1.4.2 github.com/imdario/mergo v0.3.11 github.com/integrii/flaggy v1.4.0 - github.com/jesseduffield/generics v0.0.0-20220319083513-5f145a9c0677 + github.com/jesseduffield/generics v0.0.0-20220319230408-6eaa96457df2 github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e diff --git a/go.sum b/go.sum index e99d02da5..2f8f8e890 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jesseduffield/generics v0.0.0-20220319083513-5f145a9c0677 h1:GoP06WWOE4AvTkAavXkF40nhYsg2hI09uVLDIuxzZYI= -github.com/jesseduffield/generics v0.0.0-20220319083513-5f145a9c0677/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= +github.com/jesseduffield/generics v0.0.0-20220319230408-6eaa96457df2 h1:nGS5ysWioxYaPzwuEK3b4NKzBnNhQjiD1fK3bkn43cQ= +github.com/jesseduffield/generics v0.0.0-20220319230408-6eaa96457df2/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 h1:GOQrmaE8i+KEdB8NzAegKYd4tPn/inM0I1uo0NXFerg= github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o= github.com/jesseduffield/gocui v0.3.1-0.20220227022729-69f0c798eec8 h1:9N08i5kjvOfkzMj6THmIM110wPTQLdVYEOHMHT2DFiI= diff --git a/pkg/app/app.go b/pkg/app/app.go index 2d279936f..eeb1b849f 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -14,6 +14,7 @@ import ( "strings" "github.com/aybabtme/humanlog" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/commands/git_config" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" @@ -284,13 +285,9 @@ func (app *App) Rebase() error { // Close closes any resources func (app *App) Close() error { - for _, closer := range app.closers { - err := closer.Close() - if err != nil { - return err - } - } - return nil + return slices.TryForEach(app.closers, func(closer io.Closer) error { + return closer.Close() + }) } // KnownError takes an error and tells us whether it's an error that we know about where we can print a nicely formatted version of it rather than panicking with a stack trace @@ -299,10 +296,10 @@ func (app *App) KnownError(err error) (string, bool) { knownErrorMessages := []string{app.Tr.MinGitVersionError} - for _, message := range knownErrorMessages { - if errorMessage == message { - return message, true - } + if message, ok := slices.Find(knownErrorMessages, func(knownErrorMessage string) bool { + return knownErrorMessage == errorMessage + }); ok { + return message, true } mappings := []errorMapping{ @@ -312,11 +309,12 @@ func (app *App) KnownError(err error) (string, bool) { }, } - for _, mapping := range mappings { - if strings.Contains(errorMessage, mapping.originalError) { - return mapping.newError, true - } + if mapping, ok := slices.Find(mappings, func(mapping errorMapping) bool { + return strings.Contains(errorMessage, mapping.originalError) + }); ok { + return mapping.newError, true } + return "", false } diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index ecb75f935..04d8d3fd5 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -141,12 +141,11 @@ outer: if existing == nil { contextAndViewBindingMap[key] = []*types.Binding{binding} } else { - for _, navBinding := range contextAndViewBindingMap[key] { - if navBinding.Description == binding.Description { - continue outer - } + if !slices.Some(contextAndViewBindingMap[key], func(navBinding *types.Binding) bool { + return navBinding.Description == binding.Description + }) { + contextAndViewBindingMap[key] = append(contextAndViewBindingMap[key], binding) } - contextAndViewBindingMap[key] = append(contextAndViewBindingMap[key], binding) } continue outer diff --git a/pkg/gui/information_panel.go b/pkg/gui/information_panel.go index 3e317a349..4527da43b 100644 --- a/pkg/gui/information_panel.go +++ b/pkg/gui/information_panel.go @@ -3,15 +3,14 @@ package gui import ( "fmt" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/constants" "github.com/jesseduffield/lazygit/pkg/gui/style" ) func (gui *Gui) informationStr() string { - for _, mode := range gui.modeStatuses() { - if mode.isActive() { - return mode.description() - } + if activeMode, ok := gui.getActiveMode(); ok { + return activeMode.description() } if gui.g.Mouse { @@ -23,6 +22,12 @@ func (gui *Gui) informationStr() string { } } +func (gui *Gui) getActiveMode() (modeStatus, bool) { + return slices.Find(gui.modeStatuses(), func(mode modeStatus) bool { + return mode.isActive() + }) +} + func (gui *Gui) handleInfoClick() error { if !gui.g.Mouse { return nil @@ -33,13 +38,11 @@ func (gui *Gui) handleInfoClick() error { cx, _ := view.Cursor() width, _ := view.Size() - for _, mode := range gui.modeStatuses() { - if mode.isActive() { - if width-cx > len(gui.c.Tr.ResetInParentheses) { - return nil - } - return mode.reset() + if activeMode, ok := gui.getActiveMode(); ok { + if width-cx > len(gui.c.Tr.ResetInParentheses) { + return nil } + return activeMode.reset() } // if we're not in an active mode we show the donate button diff --git a/vendor/github.com/jesseduffield/generics/slices/slices.go b/vendor/github.com/jesseduffield/generics/slices/slices.go index 1d224255a..18ad4694f 100644 --- a/vendor/github.com/jesseduffield/generics/slices/slices.go +++ b/vendor/github.com/jesseduffield/generics/slices/slices.go @@ -47,6 +47,32 @@ func MapWithIndex[T any, V any](slice []T, f func(T, int) V) []V { return result } +func TryMap[T any, V any](slice []T, f func(T) (V, error)) ([]V, error) { + result := make([]V, 0, len(slice)) + for _, value := range slice { + output, err := f(value) + if err != nil { + return nil, err + } + result = append(result, output) + } + + return result, nil +} + +func TryMapWithIndex[T any, V any](slice []T, f func(T, int) (V, error)) ([]V, error) { + result := make([]V, 0, len(slice)) + for i, value := range slice { + output, err := f(value, i) + if err != nil { + return nil, err + } + result = append(result, output) + } + + return result, nil +} + // Produces a new slice, leaves the input slice untouched. func FlatMap[T any, V any](slice []T, f func(T) []V) []V { // impossible to know how long this slice will be in the end but the length @@ -59,6 +85,17 @@ func FlatMap[T any, V any](slice []T, f func(T) []V) []V { return result } +func FlatMapWithIndex[T any, V any](slice []T, f func(T, int) []V) []V { + // impossible to know how long this slice will be in the end but the length + // of the original slice is the lower bound + result := make([]V, 0, len(slice)) + for i, value := range slice { + result = append(result, f(value, i)...) + } + + return result +} + func Flatten[T any](slice [][]T) []T { result := make([]T, 0, len(slice)) for _, subSlice := range slice { @@ -96,6 +133,34 @@ func FilterWithIndex[T any](slice []T, f func(T, int) bool) []T { return result } +func TryFilter[T any](slice []T, test func(T) (bool, error)) ([]T, error) { + result := make([]T, 0) + for _, element := range slice { + ok, err := test(element) + if err != nil { + return nil, err + } + if ok { + result = append(result, element) + } + } + return result, nil +} + +func TryFilterWithIndex[T any](slice []T, test func(T, int) (bool, error)) ([]T, error) { + result := make([]T, 0) + for i, element := range slice { + ok, err := test(element, i) + if err != nil { + return nil, err + } + if ok { + result = append(result, element) + } + } + return result, nil +} + // Mutates original slice. Intended usage is to reassign the slice result to the input slice. func FilterInPlace[T any](slice []T, test func(T) bool) []T { newLength := 0 @@ -125,10 +190,10 @@ func ReverseInPlace[T any](slice []T) { } // Produces a new slice, leaves the input slice untouched. -func FilterMap[T any, E any](slice []T, test func(T) (bool, E)) []E { +func FilterMap[T any, E any](slice []T, test func(T) (E, bool)) []E { result := make([]E, 0, len(slice)) for _, element := range slice { - ok, mapped := test(element) + mapped, ok := test(element) if ok { result = append(result, mapped) } @@ -137,17 +202,48 @@ func FilterMap[T any, E any](slice []T, test func(T) (bool, E)) []E { return result } -// Produces a new slice, leaves the input slice untouched. -func FilterThenMap[T any, E any](slice []T, test func(T) bool, mapFn func(T) E) []E { +func FilterMapWithIndex[T any, E any](slice []T, test func(T, int) (E, bool)) []E { result := make([]E, 0, len(slice)) - for _, element := range slice { - if test(element) { - result = append(result, mapFn(element)) + for i, element := range slice { + mapped, ok := test(element, i) + if ok { + result = append(result, mapped) } } + return result } +func TryFilterMap[T any, E any](slice []T, test func(T) (E, bool, error)) ([]E, error) { + result := make([]E, 0, len(slice)) + for _, element := range slice { + mapped, ok, err := test(element) + if err != nil { + return nil, err + } + if ok { + result = append(result, mapped) + } + } + + return result, nil +} + +func TryFilterMapWithIndex[T any, E any](slice []T, test func(T, int) (E, bool, error)) ([]E, error) { + result := make([]E, 0, len(slice)) + for i, element := range slice { + mapped, ok, err := test(element, i) + if err != nil { + return nil, err + } + if ok { + result = append(result, mapped) + } + } + + return result, nil +} + // Prepends items to the beginning of a slice. // E.g. Prepend([]int{1,2}, 3, 4) = []int{3,4,1,2} // Mutates original slice. Intended usage is to reassign the slice result to the input slice. @@ -241,6 +337,45 @@ func MinBy[T any, V constraints.Ordered](slice []T, f func(T) V) V { return min } +func Find[T any](slice []T, f func(T) bool) (T, bool) { + for _, element := range slice { + if f(element) { + return element, true + } + } + return zero[T](), false +} + +func ForEach[T any](slice []T, f func(T)) { + for _, element := range slice { + f(element) + } +} + +func ForEachWithIndex[T any](slice []T, f func(T, int)) { + for i, element := range slice { + f(element, i) + } +} + +func TryForEach[T any](slice []T, f func(T) error) error { + for _, element := range slice { + if err := f(element); err != nil { + return err + } + } + return nil +} + +func TryForEachWithIndex[T any](slice []T, f func(T, int) error) error { + for i, element := range slice { + if err := f(element, i); err != nil { + return err + } + } + return nil +} + func zero[T any]() T { var value T return value diff --git a/vendor/modules.txt b/vendor/modules.txt index a7b196cea..e6dc129fc 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -120,7 +120,7 @@ github.com/integrii/flaggy # github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 ## explicit github.com/jbenet/go-context/io -# github.com/jesseduffield/generics v0.0.0-20220319083513-5f145a9c0677 +# github.com/jesseduffield/generics v0.0.0-20220319230408-6eaa96457df2 ## explicit; go 1.18 github.com/jesseduffield/generics/maps github.com/jesseduffield/generics/set From 340a145bc8af32123550f6b4db5104f61417c019 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 20 Mar 2022 13:59:33 +1100 Subject: [PATCH 121/385] refactor cheatsheet generator --- docs/keybindings/Keybindings_en.md | 1 - docs/keybindings/Keybindings_nl.md | 81 ++++----- docs/keybindings/Keybindings_pl.md | 213 +++++++++++----------- docs/keybindings/Keybindings_zh.md | 245 +++++++++++++------------ pkg/cheatsheet/generate.go | 203 ++++++++------------- pkg/cheatsheet/generate_test.go | 281 +++++++++++++++++++++++++++++ pkg/utils/slice.go | 16 ++ 7 files changed, 640 insertions(+), 400 deletions(-) create mode 100644 pkg/cheatsheet/generate_test.go diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index 662631386..6f8c12966 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -269,7 +269,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct 鈻: select next hunk ctrl+o: copy the selected text to the clipboard e: edit file - o: open file v: toggle drag select V: toggle drag select a: toggle select hunk diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index dd9c45ad2..c0accbd44 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -41,6 +41,46 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct [: vorige tabblad
+ ctrl+o: kopieer de bestandsnaam naar het klembord + ctrl+w: Toggle whether or not whitespace changes are shown in the diff view + d: bekijk 'veranderingen ongedaan maken' opties + space: toggle staged + ctrl+b: Filter files (staged/unstaged) + c: commit veranderingen + w: commit veranderingen zonder pre-commit hook + A: wijzig laatste commit + C: commit veranderingen met de git editor + e: verander bestand + o: open bestand + i: voeg toe aan .gitignore + r: refresh bestanden + s: stash-bestanden + S: bekijk stash opties + a: toggle staged alle + enter: stage individuele hunks/lijnen + g: bekijk upstream reset opties + D: bekijk reset opties + `: toggle bestandsboom weergave + M: open external merge tool (git mergetool) + f: fetch ++ +## Bestanden Paneel (Submodules) + +
+ ctrl+o: kopieer submodule naam naar klembord + enter: enter submodule + d: remove submodule + u: update submodule + n: voeg nieuwe submodule toe + e: update submodule URL + i: initialiseer submodule + b: bekijk bulk submodule opties ++ ## Branches Paneel (Branches Tabblad)
@@ -178,46 +218,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct @: open command log menu-## Bestanden Paneel (Bestanden) - -
- ctrl+o: kopieer de bestandsnaam naar het klembord - ctrl+w: Toggle whether or not whitespace changes are shown in the diff view - d: bekijk 'veranderingen ongedaan maken' opties - space: toggle staged - ctrl+b: Filter files (staged/unstaged) - c: commit veranderingen - w: commit veranderingen zonder pre-commit hook - A: wijzig laatste commit - C: commit veranderingen met de git editor - e: verander bestand - o: open bestand - i: voeg toe aan .gitignore - r: refresh bestanden - s: stash-bestanden - S: bekijk stash opties - a: toggle staged alle - enter: stage individuele hunks/lijnen - g: bekijk upstream reset opties - D: bekijk reset opties - `: toggle bestandsboom weergave - M: open external merge tool (git mergetool) - f: fetch -- -## Bestanden Paneel (Submodules) - -
- ctrl+o: kopieer submodule naam naar klembord - enter: enter submodule - d: remove submodule - u: update submodule - n: voeg nieuwe submodule toe - e: update submodule URL - i: initialiseer submodule - b: bekijk bulk submodule opties -- ## Hoofd Paneel (Mergen)
@@ -269,7 +269,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct 鈻: selecteer de volgende hunk ctrl+o: copy the selected text to the clipboard e: verander bestand - o: open bestand v: toggle drag selecteer V: toggle drag selecteer a: toggle selecteer hunk diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index 2d032e5e3..9c619f6b6 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -41,6 +41,56 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct [: previous tab+## Commity Panel (Commity) + +
+ ctrl+o: copy commit SHA to clipboard + ctrl+r: reset cherry-picked (copied) commits selection + b: view bisect options + s: 艣ci艣nij + f: napraw commit + r: zmie艅 nazw臋 commita + R: zmie艅 nazw臋 commita w edytorze + d: usu艅 commit + e: edytuj commit + p: wybierz commit (podczas zmiany bazy) + F: utw贸rz commit naprawczy dla tego commita + S: sp艂aszcz wszystkie commity naprawcze powy偶ej zaznaczonych commit贸w (autosquash) + ctrl+j: przenie艣 commit 1 w d贸艂 + ctrl+k: przenie艣 commit 1 w g贸r臋 + A: popraw commit zmianami z poczekalni + t: odwr贸膰 commit + n: create new branch off of commit + c: kopiuj commit (przebieranie) + C: kopiuj zakres commit贸w (przebieranie) + v: wklej commity (przebieranie) + ctrl+l: open log menu + g: zresetuj do tego commita + space: checkout commit + T: tag commit + ctrl+y: copy commit message to clipboard + o: open commit in browser + enter: przegl膮daj pliki commita ++ +## Commity Panel (Reflog Tab) + +
+ ctrl+o: copy commit SHA to clipboard + space: checkout commit + g: wy艣wietl opcje resetu + c: kopiuj commit (przebieranie) + C: kopiuj zakres commit贸w (przebieranie) + ctrl+r: reset cherry-picked (copied) commits selection + enter: przegl膮daj pliki commita ++ +## Extras Panel + +
+ @: open command log menu ++ ## Ga艂臋zie Panel (Branches Tab)
@@ -109,73 +159,69 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: view commits-## Pliki commita Panel +## G艂贸wne Panel (Patch Building)
- ctrl+o: copy the committed file name to the clipboard -- -## Pliki commita Panel (Pliki commita) - -
- c: plik wybierania - d: porzu膰 zmiany commita dla tego pliku + esc: wy艣cie z trybu "linia po linii" o: otw贸rz plik + 鈻: poprzednia linia + 鈻: nast臋pna linia + 鈼: poprzedni kawa艂ek + 鈻: nast臋pny kawa艂ek + ctrl+o: copy the selected text to the clipboard + space: add/remove line(s) to patch + v: toggle drag select + V: toggle drag select + a: toggle select hunk ++ +## G艂贸wne Panel (Poczekalnia) + +
+ esc: wr贸膰 do panelu plik贸w + space: toggle line staged / unstaged + d: delete change (git reset) + tab: switch to other panel + o: otw贸rz plik + 鈻: poprzednia linia + 鈻: nast臋pna linia + 鈼: poprzedni kawa艂ek + 鈻: nast臋pny kawa艂ek + ctrl+o: copy the selected text to the clipboard e: edytuj plik - space: toggle file included in patch - a: toggle all files included in patch - enter: enter file to add selected聽lines to the patch (or toggle directory collapsed) - `: toggle file tree view + v: toggle drag select + V: toggle drag select + a: toggle select hunk + c: Zatwierd藕 zmiany + w: zatwierd藕 zmiany bez skryptu pre-commit + C: Zatwierd藕 zmiany u偶ywaj膮c edytora-## Commity Panel (Commity) +## G艂贸wne Panel (Scalanie)
- ctrl+o: copy commit SHA to clipboard - ctrl+r: reset cherry-picked (copied) commits selection - b: view bisect options - s: 艣ci艣nij - f: napraw commit - r: zmie艅 nazw臋 commita - R: zmie艅 nazw臋 commita w edytorze - d: usu艅 commit - e: edytuj commit - p: wybierz commit (podczas zmiany bazy) - F: utw贸rz commit naprawczy dla tego commita - S: sp艂aszcz wszystkie commity naprawcze powy偶ej zaznaczonych commit贸w (autosquash) - ctrl+j: przenie艣 commit 1 w d贸艂 - ctrl+k: przenie艣 commit 1 w g贸r臋 - A: popraw commit zmianami z poczekalni - t: odwr贸膰 commit - n: create new branch off of commit - c: kopiuj commit (przebieranie) - C: kopiuj zakres commit贸w (przebieranie) - v: wklej commity (przebieranie) - ctrl+l: open log menu - g: zresetuj do tego commita - space: checkout commit - T: tag commit - ctrl+y: copy commit message to clipboard - o: open commit in browser - enter: przegl膮daj pliki commita + esc: wr贸膰 do panelu plik贸w + M: open external merge tool (git mergetool) + space: wybierz kawa艂ek + b: wybierz wszystkie kawa艂ki + 鈼: poprzedni konflikt + 鈻: nast臋pny konflikt + 鈻: wybierz poprzedni kawa艂ek + 鈻: wybierz nast臋pny kawa艂ek + z: cofnij-## Commity Panel (Reflog Tab) +## G艂贸wne Panel (Zwyk艂e)
- ctrl+o: copy commit SHA to clipboard - space: checkout commit - g: wy艣wietl opcje resetu - c: kopiuj commit (przebieranie) - C: kopiuj zakres commit贸w (przebieranie) - ctrl+r: reset cherry-picked (copied) commits selection - enter: przegl膮daj pliki commita + mouse wheel down: przewi艅 w d贸艂 (fn+up) + mouse wheel up: przewi艅 w g贸r臋 (fn+down)-## Extras Panel +## Menu Panel
- @: open command log menu + esc: close menu## Pliki Panel (Pliki) @@ -218,70 +264,23 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct b: view bulk submodule options -## G艂贸wne Panel (Scalanie) +## Pliki commita Panel
- esc: wr贸膰 do panelu plik贸w - M: open external merge tool (git mergetool) - space: wybierz kawa艂ek - b: wybierz wszystkie kawa艂ki - 鈼: poprzedni konflikt - 鈻: nast臋pny konflikt - 鈻: wybierz poprzedni kawa艂ek - 鈻: wybierz nast臋pny kawa艂ek - z: cofnij + ctrl+o: copy the committed file name to the clipboard-## G艂贸wne Panel (Zwyk艂e) +## Pliki commita Panel (Pliki commita)
- mouse wheel down: przewi艅 w d贸艂 (fn+up) - mouse wheel up: przewi艅 w g贸r臋 (fn+down) -- -## G艂贸wne Panel (Patch Building) - -
- esc: wy艣cie z trybu "linia po linii" + c: plik wybierania + d: porzu膰 zmiany commita dla tego pliku o: otw贸rz plik - 鈻: poprzednia linia - 鈻: nast臋pna linia - 鈼: poprzedni kawa艂ek - 鈻: nast臋pny kawa艂ek - ctrl+o: copy the selected text to the clipboard - space: add/remove line(s) to patch - v: toggle drag select - V: toggle drag select - a: toggle select hunk -- -## G艂贸wne Panel (Poczekalnia) - -
- esc: wr贸膰 do panelu plik贸w - space: toggle line staged / unstaged - d: delete change (git reset) - tab: switch to other panel - o: otw贸rz plik - 鈻: poprzednia linia - 鈻: nast臋pna linia - 鈼: poprzedni kawa艂ek - 鈻: nast臋pny kawa艂ek - ctrl+o: copy the selected text to the clipboard e: edytuj plik - o: otw贸rz plik - v: toggle drag select - V: toggle drag select - a: toggle select hunk - c: Zatwierd藕 zmiany - w: zatwierd藕 zmiany bez skryptu pre-commit - C: Zatwierd藕 zmiany u偶ywaj膮c edytora -- -## Menu Panel - -
- esc: close menu + space: toggle file included in patch + a: toggle all files included in patch + enter: enter file to add selected聽lines to the patch (or toggle directory collapsed) + `: toggle file tree view## Schowek Panel (Schowek) diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index 12b9a90f7..d477edb40 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -41,6 +41,71 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct [: 涓婁竴涓爣绛 +## Extras 闈㈡澘 + +
+ @: 鎵撳紑鍛戒护鏃ュ織鑿滃崟 ++ +## 涓昏 闈㈡澘 (鍚堝苟涓) + +
+ esc: 杩斿洖鏂囦欢闈㈡澘 + M: 鎵撳紑鍚堝苟宸ュ叿 + space: 閫変腑鍖哄潡 + b: 閫変腑鎵鏈夊尯鍧 + 鈼: 閫夋嫨涓婁竴涓啿绐 + 鈻: 閫夋嫨涓嬩竴涓啿绐 + 鈻: 閫夋嫨椤堕儴鍧 + 鈻: 閫夋嫨搴曢儴鍧 + z: 鎾ら攢 ++ +## 涓昏 闈㈡澘 (鏋勫缓琛ヤ竵涓) + +
+ esc: 閫鍑洪愯妯″紡 + o: 鎵撳紑鏂囦欢 + 鈻: 閫夋嫨涓婁竴琛 + 鈻: 閫夋嫨涓嬩竴琛 + 鈼: 閫夋嫨涓婁竴涓尯鍧 + 鈻: 閫夋嫨涓嬩竴涓尯鍧 + ctrl+o: copy the selected text to the clipboard + space: 娣诲姞/绉婚櫎 琛屽埌琛ヤ竵 + v: 鍒囨崲鎷栧姩閫夋嫨 + V: 鍒囨崲鎷栧姩閫夋嫨 + a: 鍒囨崲閫夋嫨鍖哄潡 ++ +## 涓昏 闈㈡澘 (姝e湪鏆傚瓨) + +
+ esc: 杩斿洖鏂囦欢闈㈡澘 + space: 鍒囨崲琛屾殏瀛樼姸鎬 + d: 鍙栨秷鍙樻洿 (git reset) + tab: 鍒囨崲鍒板叾浠栭潰鏉 + o: 鎵撳紑鏂囦欢 + 鈻: 閫夋嫨涓婁竴琛 + 鈻: 閫夋嫨涓嬩竴琛 + 鈼: 閫夋嫨涓婁竴涓尯鍧 + 鈻: 閫夋嫨涓嬩竴涓尯鍧 + ctrl+o: copy the selected text to the clipboard + e: 缂栬緫鏂囦欢 + v: 鍒囨崲鎷栧姩閫夋嫨 + V: 鍒囨崲鎷栧姩閫夋嫨 + a: 鍒囨崲閫夋嫨鍖哄潡 + c: 鎻愪氦鏇存敼 + w: 鎻愪氦鏇存敼鑰屾棤闇棰勫厛鎻愪氦閽╁瓙 + C: 鎻愪氦鏇存敼锛堜娇鐢ㄧ紪杈戝櫒缂栬緫鎻愪氦淇℃伅锛 ++ +## 涓昏 闈㈡澘 (姝e父) + +
+ mouse wheel down: 鍚戜笅婊氬姩 (fn+up) + mouse wheel up: 鍚戜笂婊氬姩 (fn+down) ++ ## 鍒嗘敮 闈㈡澘 (鍒嗘敮鏍囩)
@@ -62,29 +127,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: 鏌ョ湅鎻愪氦-## 鍒嗘敮 闈㈡澘 (杩滅▼鍒嗘敮锛堝湪杩滅▼椤甸潰涓級) - -
- space: 妫鍑 - n: 鏂板垎鏀 - M: 鍚堝苟鍒板綋鍓嶆鍑虹殑鍒嗘敮 - r: 灏嗗凡妫鍑虹殑鍒嗘敮鍙樺熀鍒拌鍒嗘敮 - d: 鍒犻櫎鍒嗘敮 - u: 璁剧疆涓烘鍑哄垎鏀殑涓婃父 - esc: 杩斿洖杩滅▼浠撳簱鍒楄〃 - g: 鏌ョ湅閲嶇疆閫夐」 - enter: 鏌ョ湅鎻愪氦 -- -## 鍒嗘敮 闈㈡澘 (杩滅▼椤甸潰) - -
- f: 鎶撳彇杩滅▼浠撳簱 - n: 娣诲姞鏂扮殑杩滅▼浠撳簱 - d: 鍒犻櫎杩滅▼ - e: 缂栬緫杩滅▼浠撳簱 -- ## 鍒嗘敮 闈㈡澘 (瀛愭彁浜)
@@ -109,23 +151,39 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: 鏌ョ湅鎻愪氦-## 鎻愪氦鏂囦欢 闈㈡澘 +## 鍒嗘敮 闈㈡澘 (杩滅▼鍒嗘敮锛堝湪杩滅▼椤甸潰涓級)
- ctrl+o: 灏嗘彁浜ょ殑鏂囦欢鍚嶅鍒跺埌鍓创鏉 + space: 妫鍑 + n: 鏂板垎鏀 + M: 鍚堝苟鍒板綋鍓嶆鍑虹殑鍒嗘敮 + r: 灏嗗凡妫鍑虹殑鍒嗘敮鍙樺熀鍒拌鍒嗘敮 + d: 鍒犻櫎鍒嗘敮 + u: 璁剧疆涓烘鍑哄垎鏀殑涓婃父 + esc: 杩斿洖杩滅▼浠撳簱鍒楄〃 + g: 鏌ョ湅閲嶇疆閫夐」 + enter: 鏌ョ湅鎻愪氦-## 鎻愪氦鏂囦欢 闈㈡澘 (鎻愪氦鏂囦欢) +## 鍒嗘敮 闈㈡澘 (杩滅▼椤甸潰)
- c: 妫鍑烘枃浠 - d: 鏀惧純瀵规鏂囦欢鐨勬彁浜ゆ洿鏀 - o: 鎵撳紑鏂囦欢 - e: 缂栬緫鏂囦欢 - space: 琛ヤ竵涓寘鍚殑鍒囨崲鏂囦欢 - a: toggle all files included in patch - enter: 杈撳叆鏂囦欢浠ュ皢鎵閫夎娣诲姞鍒拌ˉ涓佷腑锛堟垨鍒囨崲鐩綍鎶樺彔锛 - `: 鍒囨崲鏂囦欢鏍戣鍥 + f: 鎶撳彇杩滅▼浠撳簱 + n: 娣诲姞鏂扮殑杩滅▼浠撳簱 + d: 鍒犻櫎杩滅▼ + e: 缂栬緫杩滅▼浠撳簱 ++ +## 鎻愪氦 闈㈡澘 (Reflog) + +
+ ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 + space: 妫鍑烘彁浜 + g: 鏌ョ湅閲嶇疆閫夐」 + c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 + C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 + ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 + enter: 鏌ョ湅鎻愪氦鐨勬枃浠## 鎻愪氦 闈㈡澘 (鎻愪氦) @@ -160,22 +218,36 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: 鏌ョ湅鎻愪氦鐨勬枃浠 -## 鎻愪氦 闈㈡澘 (Reflog) +## 鎻愪氦鏂囦欢 闈㈡澘
- ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 - space: 妫鍑烘彁浜 - g: 鏌ョ湅閲嶇疆閫夐」 - c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 - C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 - ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 - enter: 鏌ョ湅鎻愪氦鐨勬枃浠 + ctrl+o: 灏嗘彁浜ょ殑鏂囦欢鍚嶅鍒跺埌鍓创鏉-## Extras 闈㈡澘 +## 鎻愪氦鏂囦欢 闈㈡澘 (鎻愪氦鏂囦欢)
- @: 鎵撳紑鍛戒护鏃ュ織鑿滃崟 + c: 妫鍑烘枃浠 + d: 鏀惧純瀵规鏂囦欢鐨勬彁浜ゆ洿鏀 + o: 鎵撳紑鏂囦欢 + e: 缂栬緫鏂囦欢 + space: 琛ヤ竵涓寘鍚殑鍒囨崲鏂囦欢 + a: toggle all files included in patch + enter: 杈撳叆鏂囦欢浠ュ皢鎵閫夎娣诲姞鍒拌ˉ涓佷腑锛堟垨鍒囨崲鐩綍鎶樺彔锛 + `: 鍒囨崲鏂囦欢鏍戣鍥 ++ +## 鏂囦欢 闈㈡澘 (瀛愭ā鍧) + +
+ ctrl+o: 灏嗗瓙妯″潡鍚嶇О澶嶅埗鍒板壀璐存澘 + enter: 杈撳叆瀛愭ā鍧 + d: 鍒犻櫎瀛愭ā鍧 + u: 鏇存柊瀛愭ā鍧 + n: 娣诲姞鏂扮殑瀛愭ā鍧 + e: 鏇存柊瀛愭ā鍧 URL + i: 鍒濆鍖栧瓙妯″潡 + b: 鏌ョ湅鎵归噺瀛愭ā鍧楅夐」## 鏂囦欢 闈㈡澘 (鏂囦欢) @@ -205,77 +277,14 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct f: 鎶撳彇 -## 鏂囦欢 闈㈡澘 (瀛愭ā鍧) +## 鐘舵 闈㈡澘 (鐘舵)
- ctrl+o: 灏嗗瓙妯″潡鍚嶇О澶嶅埗鍒板壀璐存澘 - enter: 杈撳叆瀛愭ā鍧 - d: 鍒犻櫎瀛愭ā鍧 - u: 鏇存柊瀛愭ā鍧 - n: 娣诲姞鏂扮殑瀛愭ā鍧 - e: 鏇存柊瀛愭ā鍧 URL - i: 鍒濆鍖栧瓙妯″潡 - b: 鏌ョ湅鎵归噺瀛愭ā鍧楅夐」 -- -## 涓昏 闈㈡澘 (鍚堝苟涓) - -
- esc: 杩斿洖鏂囦欢闈㈡澘 - M: 鎵撳紑鍚堝苟宸ュ叿 - space: 閫変腑鍖哄潡 - b: 閫変腑鎵鏈夊尯鍧 - 鈼: 閫夋嫨涓婁竴涓啿绐 - 鈻: 閫夋嫨涓嬩竴涓啿绐 - 鈻: 閫夋嫨椤堕儴鍧 - 鈻: 閫夋嫨搴曢儴鍧 - z: 鎾ら攢 -- -## 涓昏 闈㈡澘 (姝e父) - -
- mouse wheel down: 鍚戜笅婊氬姩 (fn+up) - mouse wheel up: 鍚戜笂婊氬姩 (fn+down) -- -## 涓昏 闈㈡澘 (鏋勫缓琛ヤ竵涓) - -
- esc: 閫鍑洪愯妯″紡 - o: 鎵撳紑鏂囦欢 - 鈻: 閫夋嫨涓婁竴琛 - 鈻: 閫夋嫨涓嬩竴琛 - 鈼: 閫夋嫨涓婁竴涓尯鍧 - 鈻: 閫夋嫨涓嬩竴涓尯鍧 - ctrl+o: copy the selected text to the clipboard - space: 娣诲姞/绉婚櫎 琛屽埌琛ヤ竵 - v: 鍒囨崲鎷栧姩閫夋嫨 - V: 鍒囨崲鎷栧姩閫夋嫨 - a: 鍒囨崲閫夋嫨鍖哄潡 -- -## 涓昏 闈㈡澘 (姝e湪鏆傚瓨) - -
- esc: 杩斿洖鏂囦欢闈㈡澘 - space: 鍒囨崲琛屾殏瀛樼姸鎬 - d: 鍙栨秷鍙樻洿 (git reset) - tab: 鍒囨崲鍒板叾浠栭潰鏉 - o: 鎵撳紑鏂囦欢 - 鈻: 閫夋嫨涓婁竴琛 - 鈻: 閫夋嫨涓嬩竴琛 - 鈼: 閫夋嫨涓婁竴涓尯鍧 - 鈻: 閫夋嫨涓嬩竴涓尯鍧 - ctrl+o: copy the selected text to the clipboard - e: 缂栬緫鏂囦欢 - o: 鎵撳紑鏂囦欢 - v: 鍒囨崲鎷栧姩閫夋嫨 - V: 鍒囨崲鎷栧姩閫夋嫨 - a: 鍒囨崲閫夋嫨鍖哄潡 - c: 鎻愪氦鏇存敼 - w: 鎻愪氦鏇存敼鑰屾棤闇棰勫厛鎻愪氦閽╁瓙 - C: 鎻愪氦鏇存敼锛堜娇鐢ㄧ紪杈戝櫒缂栬緫鎻愪氦淇℃伅锛 + e: 缂栬緫閰嶇疆鏂囦欢 + o: 鎵撳紑閰嶇疆鏂囦欢 + u: 妫鏌ユ洿鏂 + enter: 鍒囨崲鍒版渶杩戠殑浠撳簱 + a: 鏄剧ず鎵鏈夊垎鏀殑鏃ュ織## 鑿滃崟 闈㈡澘 @@ -293,13 +302,3 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct n: 鏂板垎鏀 enter: 鏌ョ湅鎻愪氦鐨勬枃浠 - -## 鐘舵 闈㈡澘 (鐘舵) - -
- e: 缂栬緫閰嶇疆鏂囦欢 - o: 鎵撳紑閰嶇疆鏂囦欢 - u: 妫鏌ユ洿鏂 - enter: 鍒囨崲鍒版渶杩戠殑浠撳簱 - a: 鏄剧ず鎵鏈夊垎鏀殑鏃ュ織 -diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index 04d8d3fd5..d20a0c71a 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -21,6 +21,8 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/i18n" "github.com/jesseduffield/lazygit/pkg/integration" + "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" ) type bindingSection struct { @@ -28,6 +30,17 @@ type bindingSection struct { bindings []*types.Binding } +type header struct { + // priority decides the order of the headers in the cheatsheet (lower means higher) + priority int + title string +} + +type headerWithBindings struct { + header header + bindings []*types.Binding +} + func CommandToRun() string { return "go run scripts/cheatsheet/main.go generate" } @@ -49,7 +62,8 @@ func generateAtDir(cheatsheetDir string) { panic(err) } - bindingSections := getBindingSections(mApp) + bindings := mApp.Gui.GetCheatsheetKeybindings() + bindingSections := getBindingSections(bindings, mApp.Tr) content := formatSections(mApp.Tr, bindingSections) content = fmt.Sprintf("_This file is auto-generated. To update, make the changes in the "+ "pkg/i18n directory and then run `%s` from the project root._\n\n%s", CommandToRun(), content) @@ -68,9 +82,7 @@ func writeString(file *os.File, str string) { } } -func localisedTitle(mApp *app.App, str string) string { - tr := mApp.Tr - +func localisedTitle(tr *i18n.TranslationSet, str string) string { contextTitleMap := map[string]string{ "global": tr.GlobalTitle, "navigation": tr.NavigationTitle, @@ -110,142 +122,66 @@ func localisedTitle(mApp *app.App, str string) string { return title } -func formatTitle(title string) string { - return fmt.Sprintf("\n## %s\n\n", title) -} - -func formatBinding(binding *types.Binding) string { - if binding.Alternative != "" { - return fmt.Sprintf(" %s: %s (%s)\n", gui.GetKeyDisplay(binding.Key), binding.Description, binding.Alternative) - } - return fmt.Sprintf(" %s: %s\n", gui.GetKeyDisplay(binding.Key), binding.Description) -} - -func getBindingSections(mApp *app.App) []*bindingSection { - bindingSections := []*bindingSection{} - - bindings := mApp.Gui.GetCheatsheetKeybindings() - - type contextAndViewType struct { - subtitle string - title string - } - - contextAndViewBindingMap := map[contextAndViewType][]*types.Binding{} - -outer: - for _, binding := range bindings { - if binding.Tag == "navigation" { - key := contextAndViewType{subtitle: "", title: "navigation"} - existing := contextAndViewBindingMap[key] - if existing == nil { - contextAndViewBindingMap[key] = []*types.Binding{binding} - } else { - if !slices.Some(contextAndViewBindingMap[key], func(navBinding *types.Binding) bool { - return navBinding.Description == binding.Description - }) { - contextAndViewBindingMap[key] = append(contextAndViewBindingMap[key], binding) - } - } - - continue outer - } - - contexts := []string{} - if len(binding.Contexts) == 0 { - contexts = append(contexts, "") - } else { - contexts = append(contexts, binding.Contexts...) - } - - for _, context := range contexts { - key := contextAndViewType{subtitle: context, title: binding.ViewName} - existing := contextAndViewBindingMap[key] - if existing == nil { - contextAndViewBindingMap[key] = []*types.Binding{binding} - } else { - contextAndViewBindingMap[key] = append(contextAndViewBindingMap[key], binding) - } - } - } - - type groupedBindingsType struct { - contextAndView contextAndViewType - bindings []*types.Binding - } - - groupedBindings := maps.MapToSlice( - contextAndViewBindingMap, - func(contextAndView contextAndViewType, contextBindings []*types.Binding) groupedBindingsType { - return groupedBindingsType{contextAndView: contextAndView, bindings: contextBindings} - }, - ) - - slices.SortFunc(groupedBindings, func(a, b groupedBindingsType) bool { - first := a.contextAndView - second := b.contextAndView - if first.title == "" { - return true - } - if second.title == "" { - return false - } - if first.title == "navigation" { - return true - } - if second.title == "navigation" { - return false - } - return first.title < second.title || (first.title == second.title && first.subtitle < second.subtitle) +func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*bindingSection { + bindingsToDisplay := slices.Filter(bindings, func(binding *types.Binding) bool { + return binding.Description != "" || binding.Alternative != "" }) - for _, group := range groupedBindings { - contextAndView := group.contextAndView - contextBindings := group.bindings - mApp.Log.Info("viewname: " + contextAndView.title + ", context: " + contextAndView.subtitle) - viewName := contextAndView.title - if viewName == "" { - viewName = "global" - } - translatedView := localisedTitle(mApp, viewName) - var title string - if contextAndView.subtitle == "" { - addendum := " " + mApp.Tr.Panel - if viewName == "global" || viewName == "navigation" { - addendum = "" - } - title = fmt.Sprintf("%s%s", translatedView, addendum) - } else { - translatedContextName := localisedTitle(mApp, contextAndView.subtitle) - title = fmt.Sprintf("%s %s (%s)", translatedView, mApp.Tr.Panel, translatedContextName) - } + bindingsByHeader := utils.MuiltiGroupBy(bindingsToDisplay, func(binding *types.Binding) []header { + return getHeaders(binding, tr) + }) - for _, binding := range contextBindings { - bindingSections = addBinding(title, bindingSections, binding) - } - } + bindingGroups := maps.MapToSlice(bindingsByHeader, func(header header, hBindings []*types.Binding) headerWithBindings { + uniqBindings := lo.UniqBy(hBindings, func(binding *types.Binding) string { + return binding.Description + gui.GetKeyDisplay(binding.Key) + }) - return bindingSections + return headerWithBindings{ + header: header, + bindings: uniqBindings, + } + }) + + slices.SortFunc(bindingGroups, func(a, b headerWithBindings) bool { + if a.header.priority != b.header.priority { + return a.header.priority > b.header.priority + } + return a.header.title < b.header.title + }) + + return slices.Map(bindingGroups, func(hb headerWithBindings) *bindingSection { + return &bindingSection{ + title: hb.header.title, + bindings: hb.bindings, + } + }) } -func addBinding(title string, bindingSections []*bindingSection, binding *types.Binding) []*bindingSection { - if binding.Description == "" && binding.Alternative == "" { - return bindingSections +// a binding may belong to multiple headers if it is applicable to multiple contexts, +// for example the copy-to-clipboard binding. +func getHeaders(binding *types.Binding, tr *i18n.TranslationSet) []header { + if binding.Tag == "navigation" { + return []header{{priority: 2, title: localisedTitle(tr, "navigation")}} } - for _, section := range bindingSections { - if title == section.title { - section.bindings = append(section.bindings, binding) - return bindingSections - } + if binding.ViewName == "" { + return []header{{priority: 3, title: localisedTitle(tr, "global")}} } - section := &bindingSection{ - title: title, - bindings: []*types.Binding{binding}, + if len(binding.Contexts) == 0 { + translatedView := localisedTitle(tr, binding.ViewName) + title := fmt.Sprintf("%s %s", translatedView, tr.Panel) + + return []header{{priority: 1, title: title}} } - return append(bindingSections, section) + return slices.Map(binding.Contexts, func(context string) header { + translatedView := localisedTitle(tr, binding.ViewName) + translatedContextName := localisedTitle(tr, context) + title := fmt.Sprintf("%s %s (%s)", translatedView, tr.Panel, translatedContextName) + + return header{priority: 1, title: title} + }) } func formatSections(tr *i18n.TranslationSet, bindingSections []*bindingSection) string { @@ -262,3 +198,14 @@ func formatSections(tr *i18n.TranslationSet, bindingSections []*bindingSection) return content } + +func formatTitle(title string) string { + return fmt.Sprintf("\n## %s\n\n", title) +} + +func formatBinding(binding *types.Binding) string { + if binding.Alternative != "" { + return fmt.Sprintf(" %s: %s (%s)\n", gui.GetKeyDisplay(binding.Key), binding.Description, binding.Alternative) + } + return fmt.Sprintf(" %s: %s\n", gui.GetKeyDisplay(binding.Key), binding.Description) +} diff --git a/pkg/cheatsheet/generate_test.go b/pkg/cheatsheet/generate_test.go new file mode 100644 index 000000000..94b571454 --- /dev/null +++ b/pkg/cheatsheet/generate_test.go @@ -0,0 +1,281 @@ +package cheatsheet + +import ( + "testing" + + "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/i18n" + "github.com/stretchr/testify/assert" +) + +func TestGetBindingSections(t *testing.T) { + tr := i18n.EnglishTranslationSet() + + tests := []struct { + testName string + bindings []*types.Binding + expected []*bindingSection + }{ + { + testName: "no bindings", + bindings: []*types.Binding{}, + expected: []*bindingSection{}, + }, + { + testName: "one binding", + bindings: []*types.Binding{ + { + ViewName: "files", + Description: "stage file", + }, + }, + expected: []*bindingSection{ + { + title: "Files Panel", + bindings: []*types.Binding{ + { + ViewName: "files", + Description: "stage file", + }, + }, + }, + }, + }, + { + testName: "one binding with context", + bindings: []*types.Binding{ + { + ViewName: "files", + Description: "stage file", + Contexts: []string{"submodules"}, + }, + }, + expected: []*bindingSection{ + { + title: "Files Panel (Submodules)", + bindings: []*types.Binding{ + { + ViewName: "files", + Description: "stage file", + Contexts: []string{"submodules"}, + }, + }, + }, + }, + }, + { + testName: "global binding", + bindings: []*types.Binding{ + { + ViewName: "", + Description: "quit", + }, + }, + expected: []*bindingSection{ + { + title: "Global Keybindings", + bindings: []*types.Binding{ + { + ViewName: "", + Description: "quit", + }, + }, + }, + }, + }, + { + testName: "grouped bindings", + bindings: []*types.Binding{ + { + ViewName: "files", + Description: "stage file", + Contexts: []string{"files"}, + }, + { + ViewName: "files", + Description: "unstage file", + Contexts: []string{"files"}, + }, + { + ViewName: "files", + Description: "drop submodule", + Contexts: []string{"submodules"}, + }, + { + ViewName: "commits", + Description: "revert commit", + }, + }, + expected: []*bindingSection{ + { + title: "Commits Panel", + bindings: []*types.Binding{ + { + ViewName: "commits", + Description: "revert commit", + }, + }, + }, + { + title: "Files Panel (Files)", + bindings: []*types.Binding{ + { + ViewName: "files", + Description: "stage file", + Contexts: []string{"files"}, + }, + { + ViewName: "files", + Description: "unstage file", + Contexts: []string{"files"}, + }, + }, + }, + { + title: "Files Panel (Submodules)", + bindings: []*types.Binding{ + { + ViewName: "files", + Description: "drop submodule", + Contexts: []string{"submodules"}, + }, + }, + }, + }, + }, + { + testName: "with navigation bindings", + bindings: []*types.Binding{ + { + ViewName: "files", + Description: "stage file", + }, + { + ViewName: "files", + Description: "unstage file", + }, + { + ViewName: "files", + Description: "scroll", + Tag: "navigation", + }, + { + ViewName: "commits", + Description: "revert commit", + }, + }, + expected: []*bindingSection{ + { + title: "List Panel Navigation", + bindings: []*types.Binding{ + { + ViewName: "files", + Description: "scroll", + Tag: "navigation", + }, + }, + }, + { + title: "Commits Panel", + bindings: []*types.Binding{ + { + ViewName: "commits", + Description: "revert commit", + }, + }, + }, + { + title: "Files Panel", + bindings: []*types.Binding{ + { + ViewName: "files", + Description: "stage file", + }, + { + ViewName: "files", + Description: "unstage file", + }, + }, + }, + }, + }, + { + testName: "with duplicate navigation bindings", + bindings: []*types.Binding{ + { + ViewName: "files", + Description: "stage file", + }, + { + ViewName: "files", + Description: "unstage file", + }, + { + ViewName: "files", + Description: "scroll", + Tag: "navigation", + }, + { + ViewName: "commits", + Description: "revert commit", + }, + { + ViewName: "commits", + Description: "scroll", + Tag: "navigation", + }, + { + ViewName: "commits", + Description: "page up", + Tag: "navigation", + }, + }, + expected: []*bindingSection{ + { + title: "List Panel Navigation", + bindings: []*types.Binding{ + { + ViewName: "files", + Description: "scroll", + Tag: "navigation", + }, + { + ViewName: "commits", + Description: "page up", + Tag: "navigation", + }, + }, + }, + { + title: "Commits Panel", + bindings: []*types.Binding{ + { + ViewName: "commits", + Description: "revert commit", + }, + }, + }, + { + title: "Files Panel", + bindings: []*types.Binding{ + { + ViewName: "files", + Description: "stage file", + }, + { + ViewName: "files", + Description: "unstage file", + }, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.testName, func(t *testing.T) { + actual := getBindingSections(test.bindings, &tr) + assert.EqualValues(t, test.expected, actual) + }) + } +} diff --git a/pkg/utils/slice.go b/pkg/utils/slice.go index 6971c9367..2281d8a73 100644 --- a/pkg/utils/slice.go +++ b/pkg/utils/slice.go @@ -76,3 +76,19 @@ func LimitStr(value string, limit int) string { } return value } + +// Similar to a regular GroupBy, except that each item can be grouped under multiple keys, +// so the callback returns a slice of keys instead of just one key. +func MuiltiGroupBy[T any, K comparable](slice []T, f func(T) []K) map[K][]T { + result := map[K][]T{} + for _, item := range slice { + for _, key := range f(item) { + if _, ok := result[key]; !ok { + result[key] = []T{item} + } else { + result[key] = append(result[key], item) + } + } + } + return result +} From 99e55725fb0783bc3280498ec6047350368c25d7 Mon Sep 17 00:00:00 2001 From: Jesse Duffield
- @: 鎵撳紑鍛戒护鏃ュ織鑿滃崟 -- -## 涓昏 闈㈡澘 (鍚堝苟涓) - -
- esc: 杩斿洖鏂囦欢闈㈡澘 - M: 鎵撳紑鍚堝苟宸ュ叿 - space: 閫変腑鍖哄潡 - b: 閫変腑鎵鏈夊尯鍧 - 鈼: 閫夋嫨涓婁竴涓啿绐 - 鈻: 閫夋嫨涓嬩竴涓啿绐 - 鈻: 閫夋嫨椤堕儴鍧 - 鈻: 閫夋嫨搴曢儴鍧 - z: 鎾ら攢 -- ## 涓昏 闈㈡澘 (鏋勫缓琛ヤ竵涓)
@@ -70,13 +50,27 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct 鈻: 閫夋嫨涓嬩竴琛 鈼: 閫夋嫨涓婁竴涓尯鍧 鈻: 閫夋嫨涓嬩竴涓尯鍧 - ctrl+o: copy the selected text to the clipboard + ctrl+o: 灏嗛変腑鏂囨湰澶嶅埗鍒板壀璐存澘 space: 娣诲姞/绉婚櫎 琛屽埌琛ヤ竵 v: 鍒囨崲鎷栧姩閫夋嫨 V: 鍒囨崲鎷栧姩閫夋嫨 a: 鍒囨崲閫夋嫨鍖哄潡+## 涓昏 闈㈡澘 (姝e湪鍚堝苟) + +
+ esc: 杩斿洖鏂囦欢闈㈡澘 + M: 鎵撳紑澶栭儴鍚堝苟宸ュ叿 (git mergetool) + space: 閫変腑鍖哄潡 + b: 閫変腑鎵鏈夊尯鍧 + 鈼: 閫夋嫨涓婁竴涓啿绐 + 鈻: 閫夋嫨涓嬩竴涓啿绐 + 鈻: 閫夋嫨椤堕儴鍧 + 鈻: 閫夋嫨搴曢儴鍧 + z: 鎾ら攢 ++ ## 涓昏 闈㈡澘 (姝e湪鏆傚瓨)
@@ -89,7 +83,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct 鈻: 閫夋嫨涓嬩竴琛 鈼: 閫夋嫨涓婁竴涓尯鍧 鈻: 閫夋嫨涓嬩竴涓尯鍧 - ctrl+o: copy the selected text to the clipboard + ctrl+o: 灏嗛変腑鏂囨湰澶嶅埗鍒板壀璐存澘 e: 缂栬緫鏂囦欢 v: 鍒囨崲鎷栧姩閫夋嫨 V: 鍒囨崲鎷栧姩閫夋嫨 @@ -106,7 +100,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct mouse wheel up: 鍚戜笂婊氬姩 (fn+down)-## 鍒嗘敮 闈㈡澘 (鍒嗘敮鏍囩) +## 鍒嗘敮 闈㈡澘 (鍒嗘敮椤甸潰)
ctrl+o: 灏嗗垎鏀悕绉板鍒跺埌鍓创鏉 @@ -174,7 +168,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct e: 缂栬緫杩滅▼浠撳簱-## 鎻愪氦 闈㈡澘 (Reflog) +## 鎻愪氦 闈㈡澘 (Reflog 椤甸潰)
ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 @@ -191,7 +185,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct+ +## 闄勫姞 闈㈡澘 + +ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 - b: view bisect options + b: 鏌ョ湅浜屽垎鏌ユ壘閫夐」 s: 鍚戜笅鍘嬬缉 f: 淇鎻愪氦锛坒ixup锛 r: 鏀瑰啓鎻愪氦 @@ -209,12 +203,12 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 v: 绮樿创鎻愪氦锛堟嫞閫夛級 - ctrl+l: open log menu + ctrl+l: 鎵撳紑鏃ュ織鑿滃崟 g: 閲嶇疆涓烘鎻愪氦 space: 妫鍑烘彁浜 T: 鏍囩鎻愪氦 ctrl+y: 灏嗘彁浜ゆ秷鎭鍒跺埌鍓创鏉 - o: open commit in browser + o: 鍦ㄦ祻瑙堝櫒涓墦寮鎻愪氦 enter: 鏌ョ湅鎻愪氦鐨勬枃浠@@ -254,8 +248,8 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directctrl+o: 灏嗘枃浠跺悕澶嶅埗鍒板壀璐存澘 - ctrl+w: 鍒囨崲鏄惁鍦ㄥ樊寮傝鍥句腑鏄剧ず绌虹櫧鏇存敼 - d: 鏌ョ湅'鏀惧純鏇存敼鈥橀夐」 + ctrl+w: 鍒囨崲鏄惁鍦ㄥ樊寮傝鍥句腑鏄剧ず绌虹櫧瀛楃宸紓 + d: 鏌ョ湅'鏀惧純鏇存敼'閫夐」 space: 鍒囨崲鏆傚瓨鐘舵 ctrl+b: Filter files (staged/unstaged) c: 鎻愪氦鏇存敼 @@ -267,13 +261,13 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct i: 娣诲姞鍒 .gitignore r: 鍒锋柊鏂囦欢 s: 灏嗘墍鏈夋洿鏀瑰姞鍏ヨ串钘 - S: 鏌ョ湅闅愯棌閫夐」 + S: 鏌ョ湅璐棌閫夐」 a: 鍒囨崲鎵鏈夋枃浠剁殑鏆傚瓨鐘舵 enter: 鏆傚瓨鍗曚釜 鍧/琛 鐢ㄤ簬鏂囦欢, 鎴 鎶樺彔/灞曞紑 鐩綍 g: 鏌ョ湅涓婃父閲嶇疆閫夐」 D: 鏌ョ湅閲嶇疆閫夐」 `: 鍒囨崲鏂囦欢鏍戣鍥 - M: 鎵撳紑鍚堝苟宸ュ叿 + M: 鎵撳紑澶栭儴鍚堝苟宸ュ叿 (git mergetool) f: 鎶撳彇@@ -302,3 +296,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct n: 鏂板垎鏀 enter: 鏌ョ湅鎻愪氦鐨勬枃浠
+ @: 鎵撳紑鍛戒护鏃ュ織鑿滃崟 +diff --git a/pkg/i18n/chinese.go b/pkg/i18n/chinese.go index 9fa455d73..3f83f6756 100644 --- a/pkg/i18n/chinese.go +++ b/pkg/i18n/chinese.go @@ -1,33 +1,38 @@ +/* + +鏈炕璇戞枃浠朵腑鐨勮瘝璇殑缈昏瘧鍙傝冧簡 https://github.com/progit/progit2-zh/blob/master/TRANSLATION_NOTES.asc銆 +涓嬫柟鐨勬湳璇鐓ц〃鏄鍏剁殑琛ュ厖銆 + +Translation in this file refer to https://github.com/progit/progit2-zh/blob/master/TRANSLATION_NOTES.asc. +Glossary below is a supplement of that documentation. + +Glossary 鏈瀵圭収琛 + +change 鏇存敼 +fixup 淇 +reset 閲嶇疆 + +*/ + package i18n -// 鏈炕璇戞枃浠朵腑鐨勮瘝璇殑缈昏瘧鍙傝冧簡 https://github.com/progit/progit2-zh/blob/master/TRANSLATION_NOTES.asc銆 -// 涓嬫柟鐨勬湳璇鐓ц〃鏄鍏剁殑琛ュ厖 - -// Translation in this file refer to https://github.com/progit/progit2-zh/blob/master/TRANSLATION_NOTES.asc. -// Glossary below is a supplement of that documentation. - -// Glossary 鏈瀵圭収琛 - -// change 鏇存敼 -// fixup 淇 -// reset 閲嶇疆 - const chineseIntroPopupMessage = ` -鎰熻阿浣跨敤 lazygit锛佷笅闈㈠嚑鐐逛綘鍙兘浼氭劅鍏磋叮锛 +鎰熻阿浣跨敤 lazygit锛佷綘鐪熺殑澶浜嗐備笅闈㈠嚑鐐逛綘鍙兘浼氭劅鍏磋叮锛 1) 瑙傜湅姝よ棰戯紝蹇熶簡瑙 lazygit 鐨勫姛鑳斤細 https://youtu.be/CPLdltN7wgE - 2) 璁板緱闃呰鏈鏂扮殑鍙戣璇存槑锛 + 2) 璁板緱鐪嬬湅鏈鏂板彂琛岃鏄庯細 https://github.com/jesseduffield/lazygit/releases - 3) 浣跨敤 git 璇存槑浣犳槸涓浣嶇▼搴忓憳锛佷綘鍙互鍜屾垜浠竴璧疯 - lazygit 鍙樺緱鏇村ソ銆傝冭檻璐$尞涓浜涗唬鐮侊細 + 3) 浣跨敤 git 璇存槑浣犳槸涓浣嶇▼搴忓憳锛佷綘鍙互鍜屾垜浠竴璧疯 lazygit 鍙樺緱鏇村ソ銆 + 鑰冭檻涓烘湰椤圭洰鍋氫簺璐$尞鍚э細 https://github.com/jesseduffield/lazygit - 涔熷彲浠ヨ禐鍔╁苟鍛婅瘔鎴戝摢閲岄渶瑕佹敼杩涳紝鐐瑰彸涓嬭鐨勬崘璧犳寜閽氨濂戒簡銆 - 灏辩畻缁欎粨搴撶偣涓槦鏄熶篃寰堟锛 + 浣犱篃鍙互鐩存帴璧炲姪锛屽苟鍛婅瘔鎴戝摢閲岄渶瑕佹敼杩涳紝鐐瑰彸涓嬭鐨勬崘璧犳寜閽氨濂戒簡銆 + 鍝曞彧鏄粰浠撳簱鐐逛釜鏄熸槦涔熷緢妫掞紒 ` +// exporting this so we can use it in tests func chineseTranslationSet() TranslationSet { return TranslationSet{ NotEnoughSpace: "娌℃湁瓒冲鐨勭┖闂存潵娓叉煋闈㈡澘", @@ -40,7 +45,7 @@ func chineseTranslationSet() TranslationSet { StagedChanges: `宸叉殏瀛樻洿鏀筦, MainTitle: "涓昏", StagingTitle: "姝e湪鏆傚瓨", - MergingTitle: "鍚堝苟涓", + MergingTitle: "姝e湪鍚堝苟", NormalTitle: "姝e父", CommitMessage: "鎻愪氦淇℃伅", CredentialsUsername: "鐢ㄦ埛鍚", @@ -59,7 +64,7 @@ func chineseTranslationSet() TranslationSet { LcToggleStaged: "鍒囨崲鏆傚瓨鐘舵", LcToggleStagedAll: "鍒囨崲鎵鏈夋枃浠剁殑鏆傚瓨鐘舵", LcToggleTreeView: "鍒囨崲鏂囦欢鏍戣鍥", - LcOpenMergeTool: "鎵撳紑鍚堝苟宸ュ叿", + LcOpenMergeTool: "鎵撳紑澶栭儴鍚堝苟宸ュ叿 (git mergetool)", LcRefresh: "鍒锋柊", LcPush: "鎺ㄩ", LcPull: "鎷夊彇", @@ -69,11 +74,11 @@ func chineseTranslationSet() TranslationSet { NoChangedFiles: "娌℃湁鏇存敼杩囨枃浠", NoFilesDisplay: "娌℃湁鏂囦欢鍙樉绀", NotAFile: "涓嶆槸鏂囦欢", - PullWait: "鎷夊彇涓︹", - PushWait: "鎺ㄩ佷腑鈥︹", - FetchWait: "姝e湪鎶撳彇鈥︹", + PullWait: "姝e湪鎷夊彇鈥", + PushWait: "姝e湪鎺ㄩ佲", + FetchWait: "姝e湪鎶撳彇鈥", LcSoftReset: "杞噸缃", - AlreadyCheckedOutBranch: "鎮ㄥ凡缁忔鍑轰簡杩欎釜鍒嗘敮", + AlreadyCheckedOutBranch: "鎮ㄥ凡缁忔鍑鸿嚦姝ゅ垎鏀", SureForceCheckout: "鎮ㄧ‘瀹氳寮哄埗妫鍑哄悧锛熸偍灏嗕涪澶辨墍鏈夋湰鍦版洿鏀", ForceCheckoutBranch: "寮哄埗妫鍑哄垎鏀", BranchName: "鍒嗘敮鍚嶇О", @@ -142,9 +147,9 @@ func chineseTranslationSet() TranslationSet { ForcePushDisabled: "鎮ㄧ殑鍒嗘敮宸蹭笌杩滅▼鍒嗘敮涓嶅悓, 骞朵笖鎮ㄥ凡缁忕鐢ㄤ簡寮鸿鎺ㄩ", UpdatesRejectedAndForcePushDisabled: "鏇存柊琚嫆缁濓紝鎮ㄥ凡绂佺敤寮哄埗鎺ㄩ", LcCheckForUpdate: "妫鏌ユ洿鏂", - CheckingForUpdates: "妫鏌ユ洿鏂颁腑鈥︹", - OnLatestVersionErr: "鎮ㄧ殑杞欢宸茬粡鏄渶鏂扮増鏈", - MajorVersionErr: "鏂扮増鏈 ({{.newVersion}}) 涓庡綋鍓嶇増鏈浉姣旓紝鍏锋湁鍚戝悗鍏煎鐨勬洿鏀 ({{.currentVersion}})", + CheckingForUpdates: "姝e湪妫鏌ユ洿鏂扳", + OnLatestVersionErr: "宸叉槸鏈鏂扮増鏈", + MajorVersionErr: "鏂扮増鏈 ({{.newVersion}}) 涓庡綋鍓嶇増鏈 ({{.currentVersion}}) 鐩告瘮锛屽叿鏈夐潪鍚戝悗鍏煎鐨勬洿鏀", CouldNotFindBinaryErr: "鍦 {{.url}} 澶勬壘涓嶅埌浠讳綍浜岃繘鍒舵枃浠", MergeToolTitle: "鍚堝苟宸ュ叿", MergeToolPrompt: "纭畾瑕佹墦寮 `git mergetool` 鍚?", @@ -186,7 +191,7 @@ func chineseTranslationSet() TranslationSet { MergeOptionsTitle: "鍚堝苟閫夐」", RebaseOptionsTitle: "鍙樺熀閫夐」", CommitMessageTitle: "鎻愪氦璁伅", - LocalBranchesTitle: "鍒嗘敮鏍囩", + LocalBranchesTitle: "鍒嗘敮椤甸潰", SearchTitle: "鎼滅储", TagsTitle: "鏍囩椤甸潰", MenuTitle: "鑿滃崟", @@ -195,27 +200,28 @@ func chineseTranslationSet() TranslationSet { PatchBuildingTitle: "鏋勫缓琛ヤ竵涓", InformationTitle: "淇℃伅", SecondaryTitle: "娆¤", - ReflogCommitsTitle: "Reflog", + ReflogCommitsTitle: "Reflog 椤甸潰", GlobalTitle: "鍏ㄥ眬閿粦瀹", ConflictsResolved: "宸茶В鍐虫墍鏈夊啿绐併傛槸鍚︾户缁紵", RebasingTitle: "鍙樺熀", ConfirmRebase: "鎮ㄧ‘瀹氳灏嗗垎鏀 {{.checkedOutBranch}} 鍙樺熀鍒 {{.selectedBranch}} 鍚楋紵", ConfirmMerge: "鎮ㄧ‘瀹氳灏嗗垎鏀 {{.selectedBranch}} 鍚堝苟鍒 {{.checkedOutBranch}} 鍚楋紵", - FwdNoUpstream: "鏃犳硶蹇繘娌℃湁涓婃父鐨勫垎鏀", - FwdCommitsToPush: "鏃犳硶蹇繘骞舵彁浜ゆ帹閫佺殑鍒嗘敮", + FwdNoUpstream: "姝ゅ垎鏀病鏈変笂娓革紝鏃犳硶蹇繘", + FwdNoLocalUpstream: "姝ゅ垎鏀殑杩滅▼鏈湪鏈湴娉ㄥ唽锛屾棤娉曞揩杩", + FwdCommitsToPush: "姝ゅ垎鏀甫鏈夊皻鏈帹閫佺殑鎻愪氦锛屾棤娉曞揩杩", ErrorOccurred: "鍙戠敓閿欒锛佽鍦ㄤ互涓嬩綅缃垱寤 issue", - NoRoom: "娌℃湁瓒冲鐨勭┖闂", + NoRoom: "绌洪棿涓嶈冻", YouAreHere: "鎮ㄥ湪杩欓噷", LcRewordNotSupported: "褰撳墠涓嶆敮鎸佷氦浜掑紡閲嶆柊鍩哄噯鍖栨椂鐨勯噸鏂版帾璇嶆彁浜", LcCherryPickCopy: "澶嶅埗鎻愪氦锛堟嫞閫夛級", LcCherryPickCopyRange: "澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級", LcPasteCommits: "绮樿创鎻愪氦锛堟嫞閫夛級", SureCherryPick: "鎮ㄧ‘瀹氳灏嗛変腑鐨勬彁浜よ繘琛屾嫞閫夊埌杩欎釜鍒嗘敮鍚楋紵", - CherryPick: "鎷i", - CannotRebaseOntoFirstCommit: "鎮ㄤ笉鑳戒互浜や簰鏂瑰紡鍩轰簬绗竴娆℃彁浜", - CannotSquashOntoSecondCommit: "鎮ㄤ笉鑳 鍘嬬缉/淇(fixup)绗簩涓彁浜", + CherryPick: "鎷i (Cherry-Pick)", + CannotRebaseOntoFirstCommit: "鎮ㄤ笉鑳戒互浜や簰鏂瑰紡鍙樺熀 (rebase) 鑷崇涓娆℃彁浜", + CannotSquashOntoSecondCommit: "鎮ㄤ笉鑳藉帇缂 (squash) 鎴栦慨姝 (fixup) 绗簩涓彁浜", Donate: "鎹愬姪", - AskQuestion: "闂鍜ㄨ", + AskQuestion: "鎻愰棶鍜ㄨ", PrevLine: "閫夋嫨涓婁竴琛", NextLine: "閫夋嫨涓嬩竴琛", PrevHunk: "閫夋嫨涓婁竴涓尯鍧", @@ -236,12 +242,12 @@ func chineseTranslationSet() TranslationSet { FixingStatus: "姝e湪淇", DeletingStatus: "姝e湪鍒犻櫎", MovingStatus: "姝e湪绉诲姩", - RebasingStatus: "鍙樺熀", - AmendingStatus: "淇敼", - CherryPickingStatus: "鎷i変腑", + RebasingStatus: "姝e湪鍙樺熀", + AmendingStatus: "姝e湪淇敼", + CherryPickingStatus: "姝e湪鎷i", UndoingStatus: "姝e湪鎾ら攢", RedoingStatus: "姝e湪閲嶅仛", - CheckingOutStatus: "妫鍑", + CheckingOutStatus: "闀垮瓙妫鍑", CommittingStatus: "姝e湪鎻愪氦", CommitFiles: "鎻愪氦鏂囦欢", LcViewItemFiles: "鏌ョ湅鎻愪氦鐨勬枃浠", @@ -251,11 +257,11 @@ func chineseTranslationSet() TranslationSet { DiscardFileChangesTitle: "鏀惧純鏂囦欢鏇存敼", DiscardFileChangesPrompt: "鎮ㄧ‘瀹氳鑸嶅純姝ゆ彁浜ゅ璇ユ枃浠剁殑鏇存敼鍚楋紵濡傛灉姝ゆ枃浠舵槸鍦ㄦ鎻愪氦涓垱寤虹殑锛屽畠灏嗚鍒犻櫎", DisabledForGPG: "璇ュ姛鑳戒笉閫傜敤浜庝娇鐢 GPG 鐨勭敤鎴", - CreateRepo: "涓嶅湪 git 浠撳簱涓傚垱寤轰竴涓柊鐨 git 浠撳簱鍚楋紵(y/n): ", + CreateRepo: "褰撳墠鐩綍涓嶅湪 git 浠撳簱涓傛槸鍚﹀湪姝ょ洰褰曞垱寤轰竴涓柊鐨 git 浠撳簱锛(y/n): ", AutoStashTitle: "鑷姩瀛樺偍锛", AutoStashPrompt: "鎮ㄥ繀椤婚殣钘忓苟寮瑰嚭鏇存敼浠ヤ娇鏇存敼鐢熸晥銆傝嚜鍔ㄦ墽琛岋紵(enter/esc)", StashPrefix: "鑷姩闅愯棌鏇存敼 ", - LcViewDiscardOptions: "鏌ョ湅'鏀惧純鏇存敼鈥橀夐」", + LcViewDiscardOptions: "鏌ョ湅'鏀惧純鏇存敼'閫夐」", LcCancel: "鍙栨秷", LcDiscardAllChanges: "鏀惧純鎵鏈夋洿鏀", LcDiscardUnstagedChanges: "鏀惧純鏈殏瀛樼殑鍙樻洿", @@ -276,12 +282,15 @@ func chineseTranslationSet() TranslationSet { SkipHookPrefixNotConfigured: "鎮ㄥ皻鏈厤缃敤浜庤烦杩囬挬瀛愮殑鎻愪氦娑堟伅鍓嶇紑銆傝鍦ㄦ偍鐨勯厤缃腑璁剧疆 `git.skipHookPrefix ='WIP'`", LcResetTo: `閲嶇疆涓篳, PressEnterToReturn: "鎸変笅 Enter 閿繑鍥 lazygit", - LcViewStashOptions: "鏌ョ湅闅愯棌閫夐」", + LcViewStashOptions: "鏌ョ湅璐棌閫夐」", LcStashAllChanges: "灏嗘墍鏈夋洿鏀瑰姞鍏ヨ串钘", LcStashStagedChanges: "灏嗗凡鏆傚瓨鐨勬洿鏀瑰姞鍏ヨ串钘", LcStashOptions: "璐棌閫夐」", NotARepository: "閿欒锛氬繀椤诲湪 git 浠撳簱涓繍琛", LcJump: "璺冲埌闈㈡澘", + LcScrollLeftRight: "宸﹀彸婊氬姩", + LcScrollLeft: "鍚戝乏婊氬姩", + LcScrollRight: "鍚戝彸婊氬姩", DiscardPatch: "涓㈠純琛ヤ竵", DiscardPatchConfirm: "鎮ㄤ竴娆″彧鑳介氳繃涓涓彁浜ゆ垨璐棌鏉$洰鏋勫缓琛ヤ竵銆傞渶瑕佹斁寮冨綋鍓嶈ˉ涓佸悧锛", CantPatchWhileRebasingError: "澶勪簬鍚堝苟鎴栧彉鍩虹姸鎬佹椂锛屾偍鏃犳硶鏋勫缓淇ˉ绋嬪簭鎴栬繍琛屼慨琛ョ▼搴忓懡浠", @@ -291,11 +300,12 @@ func chineseTranslationSet() TranslationSet { NoPatchError: "灏氭湭鍒涘缓琛ヤ竵銆備綘鍙互鍦ㄦ彁浜や腑鐨勬枃浠朵笂鎸変笅鈥滅┖鏍尖濇垨浣跨敤鈥滃洖杞︹濇坊鍔犲叾涓殑鐗瑰畾琛屼互寮濮嬫瀯寤鸿ˉ涓", LcEnterFile: "杈撳叆鏂囦欢浠ュ皢鎵閫夎娣诲姞鍒拌ˉ涓佷腑锛堟垨鍒囨崲鐩綍鎶樺彔锛", ExitLineByLineMode: `閫鍑洪愯妯″紡`, - EnterUpstream: `浠ヨ繖绉嶅舰寮忚緭鍏ヤ笂娓革細鈥<杩滅▼浠撳簱> <鍒嗘敮鍚嶇О>鈥漙, + EnterUpstream: `浠ヨ繖绉嶆牸寮忚緭鍏ヤ笂娓革細'<杩滅▼浠撳簱> <鍒嗘敮鍚嶇О>'`, + InvalidUpstream: "涓婃父鏍煎紡鏃犳晥锛屾牸寮忓簲褰撲负锛'
ctrl+o: copy commit SHA to clipboard space: checkout commit - g: view reset options - n: new branch + y: copy commit attribute + o: open commit in browser + n: create new branch off of commit + g: reset to this commit c: copy commit (cherry-pick) C: copy commit range (cherry-pick) ctrl+r: reset cherry-picked (copied) commits selection @@ -147,16 +149,16 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+k: move commit up one A: amend commit with staged changes t: revert commit - n: create new branch off of commit - c: copy commit (cherry-pick) - C: copy commit range (cherry-pick) v: paste commits (cherry-pick) ctrl+l: open log menu - g: reset to this commit - space: checkout commit T: tag commit + space: checkout commit y: copy commit attribute o: open commit in browser + n: create new branch off of commit + g: reset to this commit + c: copy commit (cherry-pick) + C: copy commit range (cherry-pick) enter: view selected item's files@@ -165,7 +167,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
ctrl+o: copy commit SHA to clipboard space: checkout commit - g: view reset options + y: copy commit attribute + o: open commit in browser + n: create new branch off of commit + g: reset to this commit c: copy commit (cherry-pick) C: copy commit range (cherry-pick) ctrl+r: reset cherry-picked (copied) commits selection diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index bec3e35ad..8fbf16ccd 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -130,8 +130,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct+ +## Sub-commits Paneel (Sub-commits) + +ctrl+o: kopieer commit SHA naar klembord space: checkout commit - g: bekijk reset opties - n: nieuwe branch + y: copy commit attribute + o: open commit in browser + n: cre毛er nieuwe branch van commit + g: reset naar deze commit c: kopieer commit (cherry-pick) C: kopieer commit reeks (cherry-pick) ctrl+r: reset cherry-picked (gekopieerde) commits selectie @@ -187,16 +189,16 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+k: verplaats commit 1 naar boven A: wijzig commit met staged veranderingen t: commit ongedaan maken - n: cre毛er nieuwe branch van commit - c: kopieer commit (cherry-pick) - C: kopieer commit reeks (cherry-pick) v: plak commits (cherry-pick) ctrl+l: open log menu - g: reset naar deze commit - space: checkout commit T: tag commit + space: checkout commit y: copy commit attribute o: open commit in browser + n: cre毛er nieuwe branch van commit + g: reset naar deze commit + c: kopieer commit (cherry-pick) + C: kopieer commit reeks (cherry-pick) enter: bekijk gecommite bestanden@@ -205,7 +207,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directctrl+o: kopieer commit SHA naar klembord space: checkout commit - g: bekijk reset opties + y: copy commit attribute + o: open commit in browser + n: cre毛er nieuwe branch van commit + g: reset naar deze commit c: kopieer commit (cherry-pick) C: kopieer commit reeks (cherry-pick) ctrl+r: reset cherry-picked (gekopieerde) commits selectie diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index 3e9443b4e..93f91050a 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -60,16 +60,16 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+k: przenie艣 commit 1 w g贸r臋 A: popraw commit zmianami z poczekalni t: odwr贸膰 commit - n: create new branch off of commit - c: kopiuj commit (przebieranie) - C: kopiuj zakres commit贸w (przebieranie) v: wklej commity (przebieranie) ctrl+l: open log menu - g: zresetuj do tego commita - space: checkout commit T: tag commit + space: checkout commit y: copy commit attribute o: open commit in browser + n: create new branch off of commit + g: zresetuj do tego commita + c: kopiuj commit (przebieranie) + C: kopiuj zakres commit贸w (przebieranie) enter: przegl膮daj pliki commita@@ -78,7 +78,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directctrl+o: copy commit SHA to clipboard space: checkout commit - g: wy艣wietl opcje resetu + y: copy commit attribute + o: open commit in browser + n: create new branch off of commit + g: zresetuj do tego commita c: kopiuj commit (przebieranie) C: kopiuj zakres commit贸w (przebieranie) ctrl+r: reset cherry-picked (copied) commits selection @@ -140,8 +143,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct-## Commit bestanden Paneel - -ctrl+o: copy commit SHA to clipboard space: checkout commit - g: wy艣wietl opcje resetu - n: nowa ga艂膮藕 + y: copy commit attribute + o: open commit in browser + n: create new branch off of commit + g: zresetuj do tego commita c: kopiuj commit (przebieranie) C: kopiuj zakres commit贸w (przebieranie) ctrl+r: reset cherry-picked (copied) commits selection diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index ba672a858..7e1b1c407 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -126,8 +126,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct+ +## Sub-commits Panel (Sub-commits) + +ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 space: 妫鍑烘彁浜 - g: 鏌ョ湅閲嶇疆閫夐」 - n: 鏂板垎鏀 + y: copy commit attribute + o: 鍦ㄦ祻瑙堝櫒涓墦寮鎻愪氦 + n: 浠庢彁浜ゅ垱寤烘柊鍒嗘敮 + g: 閲嶇疆涓烘鎻愪氦 c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 @@ -173,7 +175,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct-## Commit Files Panel - -ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 space: 妫鍑烘彁浜 - g: 鏌ョ湅閲嶇疆閫夐」 + y: copy commit attribute + o: 鍦ㄦ祻瑙堝櫒涓墦寮鎻愪氦 + n: 浠庢彁浜ゅ垱寤烘柊鍒嗘敮 + g: 閲嶇疆涓烘鎻愪氦 c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 @@ -199,16 +204,16 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+k: 涓婄Щ鎻愪氦 A: 鐢ㄥ凡鏆傚瓨鐨勬洿鏀规潵淇ˉ鎻愪氦 t: 杩樺師鎻愪氦 - n: 浠庢彁浜ゅ垱寤烘柊鍒嗘敮 - c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 - C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 v: 绮樿创鎻愪氦锛堟嫞閫夛級 ctrl+l: 鎵撳紑鏃ュ織鑿滃崟 - g: 閲嶇疆涓烘鎻愪氦 - space: 妫鍑烘彁浜 T: 鏍囩鎻愪氦 + space: 妫鍑烘彁浜 y: copy commit attribute - o: open commit in browser + o: 鍦ㄦ祻瑙堝櫒涓墦寮鎻愪氦 + n: 浠庢彁浜ゅ垱寤烘柊鍒嗘敮 + g: 閲嶇疆涓烘鎻愪氦 + c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 + C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 enter: 鏌ョ湅鎻愪氦鐨勬枃浠diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index 46e3be2cd..cc7a2a0d2 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -108,3 +108,7 @@ func (self *LocalCommitsViewModel) SetShowWholeGitGraph(value bool) { func (self *LocalCommitsViewModel) GetShowWholeGitGraph() bool { return self.showWholeGitGraph } + +func (self *LocalCommitsViewModel) GetCommits() []*models.Commit { + return self.getModel() +} diff --git a/pkg/gui/context/reflog_commits_context.go b/pkg/gui/context/reflog_commits_context.go index 815805515..a1ad6cfda 100644 --- a/pkg/gui/context/reflog_commits_context.go +++ b/pkg/gui/context/reflog_commits_context.go @@ -70,3 +70,7 @@ func (self *ReflogCommitsContext) GetSelectedRefName() string { return item.RefName() } + +func (self *ReflogCommitsContext) GetCommits() []*models.Commit { + return self.getModel() +} diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go index 93a0c3593..315093f8f 100644 --- a/pkg/gui/context/sub_commits_context.go +++ b/pkg/gui/context/sub_commits_context.go @@ -72,3 +72,7 @@ func (self *SubCommitsContext) GetSelectedRefName() string { return item.RefName() } + +func (self *SubCommitsContext) GetCommits() []*models.Commit { + return self.getModel() +} diff --git a/pkg/gui/controllers.go b/pkg/gui/controllers.go index 3e33783e1..13a0eedb5 100644 --- a/pkg/gui/controllers.go +++ b/pkg/gui/controllers.go @@ -74,9 +74,6 @@ func (gui *Gui) resetControllers() { bisectController := controllers.NewBisectController(common) - reflogController := controllers.NewReflogController(common) - subCommitsController := controllers.NewSubCommitsController(common) - getSavedCommitMessage := func() string { return gui.State.savedCommitMessage } @@ -159,13 +156,21 @@ func (gui *Gui) resetControllers() { controllers.AttachControllers(context, commitishControllerFactory.Create(context)) } + basicCommitsControllerFactory := controllers.NewBasicCommitsControllerFactory(common) + + for _, context := range []controllers.ContainsCommits{ + gui.State.Contexts.LocalCommits, + gui.State.Contexts.ReflogCommits, + gui.State.Contexts.SubCommits, + } { + controllers.AttachControllers(context, basicCommitsControllerFactory.Create(context)) + } + controllers.AttachControllers(gui.State.Contexts.Branches, branchesController, gitFlowController) controllers.AttachControllers(gui.State.Contexts.Files, gui.Controllers.Files, filesRemoveController) controllers.AttachControllers(gui.State.Contexts.Tags, gui.Controllers.Tags) controllers.AttachControllers(gui.State.Contexts.Submodules, gui.Controllers.Submodules) controllers.AttachControllers(gui.State.Contexts.LocalCommits, gui.Controllers.LocalCommits, bisectController) - controllers.AttachControllers(gui.State.Contexts.ReflogCommits, reflogController) - controllers.AttachControllers(gui.State.Contexts.SubCommits, subCommitsController) controllers.AttachControllers(gui.State.Contexts.CommitFiles, commitFilesController) controllers.AttachControllers(gui.State.Contexts.Remotes, gui.Controllers.Remotes) controllers.AttachControllers(gui.State.Contexts.Stash, stashController) diff --git a/pkg/gui/controllers/basic_commits_controller.go b/pkg/gui/controllers/basic_commits_controller.go new file mode 100644 index 000000000..c59686126 --- /dev/null +++ b/pkg/gui/controllers/basic_commits_controller.go @@ -0,0 +1,236 @@ +package controllers + +import ( + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +// This controller is for all contexts that contain a list of commits. + +type BasicCommitsControllerFactory struct { + controllerCommon *controllerCommon +} + +var _ types.IController = &BasicCommitsController{} + +type ContainsCommits interface { + types.Context + GetSelected() *models.Commit + GetCommits() []*models.Commit + GetSelectedLineIdx() int +} + +type BasicCommitsController struct { + baseController + *controllerCommon + context ContainsCommits +} + +func NewBasicCommitsControllerFactory( + common *controllerCommon, +) *BasicCommitsControllerFactory { + return &BasicCommitsControllerFactory{ + controllerCommon: common, + } +} + +func (self *BasicCommitsControllerFactory) Create(context ContainsCommits) *BasicCommitsController { + return &BasicCommitsController{ + baseController: baseController{}, + controllerCommon: self.controllerCommon, + context: context, + } +} + +func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + bindings := []*types.Binding{ + { + Key: opts.GetKey(opts.Config.Commits.CheckoutCommit), + Handler: self.checkSelected(self.checkout), + Description: self.c.Tr.LcCheckoutCommit, + }, + { + Key: opts.GetKey(opts.Config.Commits.CopyCommitAttributeToClipboard), + Handler: self.checkSelected(self.copyCommitAttribute), + Description: self.c.Tr.LcCopyCommitAttributeToClipboard, + OpensMenu: true, + }, + { + Key: opts.GetKey(opts.Config.Commits.OpenInBrowser), + Handler: self.checkSelected(self.openInBrowser), + Description: self.c.Tr.LcOpenCommitInBrowser, + }, + { + Key: opts.GetKey(opts.Config.Universal.New), + Modifier: gocui.ModNone, + Handler: self.checkSelected(self.newBranch), + Description: self.c.Tr.LcCreateNewBranchFromCommit, + }, + { + Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), + Handler: self.checkSelected(self.createResetMenu), + Description: self.c.Tr.LcResetToThisCommit, + }, + { + Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), + Handler: self.checkSelected(self.copy), + Description: self.c.Tr.LcCherryPickCopy, + }, + { + Key: opts.GetKey(opts.Config.Commits.CherryPickCopyRange), + Handler: self.checkSelected(self.copyRange), + Description: self.c.Tr.LcCherryPickCopyRange, + }, + { + Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), + Handler: self.helpers.CherryPick.Reset, + Description: self.c.Tr.LcResetCherryPick, + }, + } + + return bindings +} + +func (self *BasicCommitsController) checkSelected(callback func(*models.Commit) error) func() error { + return func() error { + commit := self.context.GetSelected() + if commit == nil { + return nil + } + + return callback(commit) + } +} + +func (self *BasicCommitsController) Context() types.Context { + return self.context +} + +func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) error { + return self.c.Menu(types.CreateMenuOptions{ + Title: self.c.Tr.Actions.CopyCommitAttributeToClipboard, + Items: []*types.MenuItem{ + { + DisplayString: self.c.Tr.LcCommitSha, + OnPress: func() error { + return self.copyCommitSHAToClipboard(commit) + }, + }, + { + DisplayString: self.c.Tr.LcCommitURL, + OnPress: func() error { + return self.copyCommitURLToClipboard(commit) + }, + }, + { + DisplayString: self.c.Tr.LcCommitDiff, + OnPress: func() error { + return self.copyCommitDiffToClipboard(commit) + }, + }, + { + DisplayString: self.c.Tr.LcCommitMessage, + OnPress: func() error { + return self.copyCommitMessageToClipboard(commit) + }, + }, + }, + }) +} + +func (self *BasicCommitsController) copyCommitSHAToClipboard(commit *models.Commit) error { + self.c.LogAction(self.c.Tr.Actions.CopyCommitSHAToClipboard) + if err := self.os.CopyToClipboard(commit.Sha); err != nil { + return self.c.Error(err) + } + + self.c.Toast(self.c.Tr.CommitSHACopiedToClipboard) + return nil +} + +func (self *BasicCommitsController) copyCommitURLToClipboard(commit *models.Commit) error { + url, err := self.helpers.Host.GetCommitURL(commit.Sha) + if err != nil { + return err + } + + self.c.LogAction(self.c.Tr.Actions.CopyCommitURLToClipboard) + if err := self.os.CopyToClipboard(url); err != nil { + return self.c.Error(err) + } + + self.c.Toast(self.c.Tr.CommitURLCopiedToClipboard) + return nil +} + +func (self *BasicCommitsController) copyCommitDiffToClipboard(commit *models.Commit) error { + diff, err := self.git.Commit.GetCommitDiff(commit.Sha) + if err != nil { + return self.c.Error(err) + } + + self.c.LogAction(self.c.Tr.Actions.CopyCommitDiffToClipboard) + if err := self.os.CopyToClipboard(diff); err != nil { + return self.c.Error(err) + } + + self.c.Toast(self.c.Tr.CommitDiffCopiedToClipboard) + return nil +} + +func (self *BasicCommitsController) copyCommitMessageToClipboard(commit *models.Commit) error { + message, err := self.git.Commit.GetCommitMessage(commit.Sha) + if err != nil { + return self.c.Error(err) + } + + self.c.LogAction(self.c.Tr.Actions.CopyCommitMessageToClipboard) + if err := self.os.CopyToClipboard(message); err != nil { + return self.c.Error(err) + } + + self.c.Toast(self.c.Tr.CommitMessageCopiedToClipboard) + return nil +} + +func (self *BasicCommitsController) openInBrowser(commit *models.Commit) error { + url, err := self.helpers.Host.GetCommitURL(commit.Sha) + if err != nil { + return self.c.Error(err) + } + + self.c.LogAction(self.c.Tr.Actions.OpenCommitInBrowser) + if err := self.os.OpenLink(url); err != nil { + return self.c.Error(err) + } + + return nil +} + +func (self *BasicCommitsController) newBranch(commit *models.Commit) error { + return self.helpers.Refs.NewBranch(commit.RefName(), commit.Description(), "") +} + +func (self *BasicCommitsController) createResetMenu(commit *models.Commit) error { + return self.helpers.Refs.CreateGitResetMenu(commit.Sha) +} + +func (self *BasicCommitsController) checkout(commit *models.Commit) error { + return self.c.Ask(types.AskOpts{ + Title: self.c.Tr.LcCheckoutCommit, + Prompt: self.c.Tr.SureCheckoutThisCommit, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.CheckoutCommit) + return self.helpers.Refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) + }, + }) +} + +func (self *BasicCommitsController) copy(commit *models.Commit) error { + return self.helpers.CherryPick.Copy(commit, self.context.GetCommits(), self.context) +} + +func (self *BasicCommitsController) copyRange(*models.Commit) error { + return self.helpers.CherryPick.CopyRange(self.context.GetSelectedLineIdx(), self.model.Commits, self.context) +} diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index 2c3618b82..41433068d 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -3,7 +3,6 @@ package controllers import ( "fmt" - "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" @@ -101,22 +100,6 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ Handler: self.checkSelected(self.revert), Description: self.c.Tr.LcRevertCommit, }, - { - Key: opts.GetKey(opts.Config.Universal.New), - Modifier: gocui.ModNone, - Handler: self.checkSelected(self.newBranch), - Description: self.c.Tr.LcCreateNewBranchFromCommit, - }, - { - Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), - Handler: self.checkSelected(self.copy), - Description: self.c.Tr.LcCherryPickCopy, - }, - { - Key: opts.GetKey(opts.Config.Commits.CherryPickCopyRange), - Handler: self.checkSelected(self.copyRange), - Description: self.c.Tr.LcCherryPickCopyRange, - }, { Key: opts.GetKey(opts.Config.Commits.PasteCommits), Handler: opts.Guards.OutsideFilterMode(self.paste), @@ -149,32 +132,11 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ Description: self.c.Tr.LcOpenLogMenu, OpensMenu: true, }, - { - Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), - Handler: self.checkSelected(self.createResetMenu), - Description: self.c.Tr.LcResetToThisCommit, - }, - { - Key: opts.GetKey(opts.Config.Commits.CheckoutCommit), - Handler: self.checkSelected(self.checkout), - Description: self.c.Tr.LcCheckoutCommit, - }, { Key: opts.GetKey(opts.Config.Commits.TagCommit), Handler: self.checkSelected(self.createTag), Description: self.c.Tr.LcTagCommit, }, - { - Key: opts.GetKey(opts.Config.Commits.CopyCommitAttributeToClipboard), - Handler: self.checkSelected(self.copyCommitAttribute), - Description: self.c.Tr.LcCopyCommitAttributeToClipboard, - OpensMenu: true, - }, - { - Key: opts.GetKey(opts.Config.Commits.OpenInBrowser), - Handler: self.checkSelected(self.openInBrowser), - Description: self.c.Tr.LcOpenCommitInBrowser, - }, }...) return bindings @@ -557,21 +519,6 @@ func (self *LocalCommitsController) createTag(commit *models.Commit) error { return self.helpers.Tags.CreateTagMenu(commit.Sha, func() {}) } -func (self *LocalCommitsController) checkout(commit *models.Commit) error { - return self.c.Ask(types.AskOpts{ - Title: self.c.Tr.LcCheckoutCommit, - Prompt: self.c.Tr.SureCheckoutThisCommit, - HandleConfirm: func() error { - self.c.LogAction(self.c.Tr.Actions.CheckoutCommit) - return self.helpers.Refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) - }, - }) -} - -func (self *LocalCommitsController) createResetMenu(commit *models.Commit) error { - return self.helpers.Refs.CreateGitResetMenu(commit.Sha) -} - func (self *LocalCommitsController) openSearch() error { // we usually lazyload these commits but now that we're searching we need to load them now if self.context().GetLimitCommits() { @@ -600,93 +547,6 @@ func (self *LocalCommitsController) gotoBottom() error { return nil } -func (self *LocalCommitsController) copyCommitAttribute(commit *models.Commit) error { - return self.c.Menu(types.CreateMenuOptions{ - Title: self.c.Tr.Actions.CopyCommitAttributeToClipboard, - Items: []*types.MenuItem{ - { - DisplayString: self.c.Tr.LcCommitSha, - OnPress: func() error { - return self.copyCommitSHAToClipboard(commit) - }, - }, - { - DisplayString: self.c.Tr.LcCommitURL, - OnPress: func() error { - return self.copyCommitURLToClipboard(commit) - }, - }, - { - DisplayString: self.c.Tr.LcCommitDiff, - OnPress: func() error { - return self.copyCommitDiffToClipboard(commit) - }, - }, - { - DisplayString: self.c.Tr.LcCommitMessage, - OnPress: func() error { - return self.copyCommitMessageToClipboard(commit) - }, - }, - }, - }) -} - -func (self *LocalCommitsController) copyCommitSHAToClipboard(commit *models.Commit) error { - self.c.LogAction(self.c.Tr.Actions.CopyCommitSHAToClipboard) - if err := self.os.CopyToClipboard(commit.Sha); err != nil { - return self.c.Error(err) - } - - self.c.Toast(self.c.Tr.CommitSHACopiedToClipboard) - return nil -} - -func (self *LocalCommitsController) copyCommitURLToClipboard(commit *models.Commit) error { - url, err := self.helpers.Host.GetCommitURL(commit.Sha) - if err != nil { - return err - } - - self.c.LogAction(self.c.Tr.Actions.CopyCommitURLToClipboard) - if err := self.os.CopyToClipboard(url); err != nil { - return self.c.Error(err) - } - - self.c.Toast(self.c.Tr.CommitURLCopiedToClipboard) - return nil -} - -func (self *LocalCommitsController) copyCommitDiffToClipboard(commit *models.Commit) error { - diff, err := self.git.Commit.GetCommitDiff(commit.Sha) - if err != nil { - return self.c.Error(err) - } - - self.c.LogAction(self.c.Tr.Actions.CopyCommitDiffToClipboard) - if err := self.os.CopyToClipboard(diff); err != nil { - return self.c.Error(err) - } - - self.c.Toast(self.c.Tr.CommitDiffCopiedToClipboard) - return nil -} - -func (self *LocalCommitsController) copyCommitMessageToClipboard(commit *models.Commit) error { - message, err := self.git.Commit.GetCommitMessage(commit.Sha) - if err != nil { - return self.c.Error(err) - } - - self.c.LogAction(self.c.Tr.Actions.CopyCommitMessageToClipboard) - if err := self.os.CopyToClipboard(message); err != nil { - return self.c.Error(err) - } - - self.c.Toast(self.c.Tr.CommitMessageCopiedToClipboard) - return nil -} - func (self *LocalCommitsController) handleOpenLogMenu() error { return self.c.Menu(types.CreateMenuOptions{ Title: self.c.Tr.LogMenuTitle, @@ -770,20 +630,6 @@ func (self *LocalCommitsController) handleOpenLogMenu() error { }) } -func (self *LocalCommitsController) openInBrowser(commit *models.Commit) error { - url, err := self.helpers.Host.GetCommitURL(commit.Sha) - if err != nil { - return self.c.Error(err) - } - - self.c.LogAction(self.c.Tr.Actions.OpenCommitInBrowser) - if err := self.os.OpenLink(url); err != nil { - return self.c.Error(err) - } - - return nil -} - func (self *LocalCommitsController) checkSelected(callback func(*models.Commit) error) func() error { return func() error { commit := self.context().GetSelected() @@ -803,18 +649,6 @@ func (self *LocalCommitsController) context() *context.LocalCommitsContext { return self.contexts.LocalCommits } -func (self *LocalCommitsController) newBranch(commit *models.Commit) error { - return self.helpers.Refs.NewBranch(commit.RefName(), commit.Description(), "") -} - -func (self *LocalCommitsController) copy(commit *models.Commit) error { - return self.helpers.CherryPick.Copy(commit, self.model.Commits, self.context()) -} - -func (self *LocalCommitsController) copyRange(*models.Commit) error { - return self.helpers.CherryPick.CopyRange(self.context().GetSelectedLineIdx(), self.model.Commits, self.context()) -} - func (self *LocalCommitsController) paste() error { return self.helpers.CherryPick.Paste() } diff --git a/pkg/gui/controllers/reflog_controller.go b/pkg/gui/controllers/reflog_controller.go deleted file mode 100644 index 4085df635..000000000 --- a/pkg/gui/controllers/reflog_controller.go +++ /dev/null @@ -1,103 +0,0 @@ -package controllers - -import ( - "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - -type ReflogController struct { - baseController - *controllerCommon -} - -var _ types.IController = &ReflogController{} - -func NewReflogController( - common *controllerCommon, -) *ReflogController { - return &ReflogController{ - baseController: baseController{}, - controllerCommon: common, - } -} - -func (self *ReflogController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { - bindings := []*types.Binding{ - { - Key: opts.GetKey(opts.Config.Universal.Select), - Handler: self.checkSelected(self.checkout), - Description: self.c.Tr.LcCheckoutCommit, - }, - { - Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), - Handler: self.checkSelected(self.openResetMenu), - Description: self.c.Tr.LcViewResetOptions, - OpensMenu: true, - }, - { - Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), - Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.copy)), - Description: self.c.Tr.LcCherryPickCopy, - }, - { - Key: opts.GetKey(opts.Config.Commits.CherryPickCopyRange), - Handler: opts.Guards.OutsideFilterMode(self.checkSelected(self.copyRange)), - Description: self.c.Tr.LcCherryPickCopyRange, - }, - { - Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), - Handler: self.helpers.CherryPick.Reset, - Description: self.c.Tr.LcResetCherryPick, - }, - } - - return bindings -} - -func (self *ReflogController) checkSelected(callback func(*models.Commit) error) func() error { - return func() error { - commit := self.context().GetSelected() - if commit == nil { - return nil - } - - return callback(commit) - } -} - -func (self *ReflogController) Context() types.Context { - return self.context() -} - -func (self *ReflogController) context() *context.ReflogCommitsContext { - return self.contexts.ReflogCommits -} - -func (self *ReflogController) checkout(commit *models.Commit) error { - err := self.c.Ask(types.AskOpts{ - Title: self.c.Tr.LcCheckoutCommit, - Prompt: self.c.Tr.SureCheckoutThisCommit, - HandleConfirm: func() error { - self.c.LogAction(self.c.Tr.Actions.CheckoutReflogCommit) - return self.helpers.Refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) - }, - }) - if err != nil { - return err - } - - return nil -} - -func (self *ReflogController) openResetMenu(commit *models.Commit) error { - return self.helpers.Refs.CreateGitResetMenu(commit.Sha) -} - -func (self *ReflogController) copy(commit *models.Commit) error { - return self.helpers.CherryPick.Copy(commit, self.model.FilteredReflogCommits, self.context()) -} - -func (self *ReflogController) copyRange(commit *models.Commit) error { - return self.helpers.CherryPick.CopyRange(self.context().GetSelectedLineIdx(), self.model.FilteredReflogCommits, self.context()) -} diff --git a/pkg/gui/controllers/sub_commits_controller.go b/pkg/gui/controllers/sub_commits_controller.go deleted file mode 100644 index 36d8b2315..000000000 --- a/pkg/gui/controllers/sub_commits_controller.go +++ /dev/null @@ -1,114 +0,0 @@ -package controllers - -import ( - "github.com/jesseduffield/lazygit/pkg/commands/models" - "github.com/jesseduffield/lazygit/pkg/gui/context" - "github.com/jesseduffield/lazygit/pkg/gui/types" -) - -type SubCommitsController struct { - baseController - *controllerCommon -} - -var _ types.IController = &SubCommitsController{} - -func NewSubCommitsController( - common *controllerCommon, -) *SubCommitsController { - return &SubCommitsController{ - baseController: baseController{}, - controllerCommon: common, - } -} - -func (self *SubCommitsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { - bindings := []*types.Binding{ - { - Key: opts.GetKey(opts.Config.Universal.Select), - Handler: self.checkSelected(self.checkout), - Description: self.c.Tr.LcCheckoutCommit, - }, - { - Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), - Handler: self.checkSelected(self.openResetMenu), - Description: self.c.Tr.LcViewResetOptions, - OpensMenu: true, - }, - { - Key: opts.GetKey(opts.Config.Universal.New), - Handler: self.checkSelected(self.newBranch), - Description: self.c.Tr.LcNewBranch, - }, - { - Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), - Handler: self.checkSelected(self.copy), - Description: self.c.Tr.LcCherryPickCopy, - }, - { - Key: opts.GetKey(opts.Config.Commits.CherryPickCopyRange), - Handler: self.checkSelected(self.copyRange), - Description: self.c.Tr.LcCherryPickCopyRange, - }, - { - Key: opts.GetKey(opts.Config.Commits.ResetCherryPick), - Handler: self.helpers.CherryPick.Reset, - Description: self.c.Tr.LcResetCherryPick, - }, - } - - return bindings -} - -func (self *SubCommitsController) checkSelected(callback func(*models.Commit) error) func() error { - return func() error { - commit := self.context().GetSelected() - if commit == nil { - return nil - } - - return callback(commit) - } -} - -func (self *SubCommitsController) Context() types.Context { - return self.context() -} - -func (self *SubCommitsController) context() *context.SubCommitsContext { - return self.contexts.SubCommits -} - -func (self *SubCommitsController) checkout(commit *models.Commit) error { - err := self.c.Ask(types.AskOpts{ - Title: self.c.Tr.LcCheckoutCommit, - Prompt: self.c.Tr.SureCheckoutThisCommit, - HandleConfirm: func() error { - self.c.LogAction(self.c.Tr.Actions.CheckoutCommit) - return self.helpers.Refs.CheckoutRef(commit.Sha, types.CheckoutRefOptions{}) - }, - }) - if err != nil { - return err - } - - self.context().SetSelectedLineIdx(0) - - return nil -} - -func (self *SubCommitsController) openResetMenu(commit *models.Commit) error { - return self.helpers.Refs.CreateGitResetMenu(commit.Sha) -} - -func (self *SubCommitsController) newBranch(commit *models.Commit) error { - return self.helpers.Refs.NewBranch(commit.RefName(), commit.Description(), "") -} - -func (self *SubCommitsController) copy(commit *models.Commit) error { - return self.helpers.CherryPick.Copy(commit, self.model.SubCommits, self.context()) -} - -func (self *SubCommitsController) copyRange(commit *models.Commit) error { - return self.helpers.CherryPick.CopyRange(self.context().GetSelectedLineIdx(), self.model.SubCommits, self.context()) -} diff --git a/pkg/i18n/chinese.go b/pkg/i18n/chinese.go index 3f83f6756..400a12da6 100644 --- a/pkg/i18n/chinese.go +++ b/pkg/i18n/chinese.go @@ -474,7 +474,6 @@ func chineseTranslationSet() TranslationSet { Actions: Actions{ // TODO: combine this with the original keybinding descriptions (those are all in lowercase atm) CheckoutCommit: "妫鍑烘彁浜", - CheckoutReflogCommit: "妫鍑 reflog 鎻愪氦", CheckoutTag: "妫鍑烘爣绛", CheckoutBranch: "妫鍑哄垎鏀", ForceCheckoutBranch: "寮哄埗妫鍑哄垎鏀", diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 04e948380..b09b6550c 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -488,7 +488,6 @@ type Bisect struct { type Actions struct { CheckoutCommit string - CheckoutReflogCommit string CheckoutTag string CheckoutBranch string ForceCheckoutBranch string @@ -1060,7 +1059,6 @@ func EnglishTranslationSet() TranslationSet { Actions: Actions{ // TODO: combine this with the original keybinding descriptions (those are all in lowercase atm) CheckoutCommit: "Checkout commit", - CheckoutReflogCommit: "Checkout reflog commit", CheckoutTag: "Checkout tag", CheckoutBranch: "Checkout branch", ForceCheckoutBranch: "Force checkout branch", From 077b6eb8a34f28d9d11c43b65d4b2a54835b0f31 Mon Sep 17 00:00:00 2001 From: Jesse DuffieldDate: Sat, 26 Mar 2022 17:03:30 +1100 Subject: [PATCH 129/385] refactor to make code clearer --- pkg/gui/controllers.go | 24 ++++------ .../controllers/basic_commits_controller.go | 16 +------ ....go => switch_to_diff_files_controller.go} | 46 +++++++------------ ...go => switch_to_sub_commits_controller.go} | 39 ++++++---------- 4 files changed, 42 insertions(+), 83 deletions(-) rename pkg/gui/controllers/{commitish_controller.go => switch_to_diff_files_controller.go} (50%) rename pkg/gui/controllers/{sub_commits_switch_controller.go => switch_to_sub_commits_controller.go} (59%) diff --git a/pkg/gui/controllers.go b/pkg/gui/controllers.go index 13a0eedb5..b0f100f2f 100644 --- a/pkg/gui/controllers.go +++ b/pkg/gui/controllers.go @@ -129,41 +129,35 @@ func (gui *Gui) resetControllers() { stashController := controllers.NewStashController(common) commitFilesController := controllers.NewCommitFilesController(common) - switchToSubCommitsControllerFactory := controllers.NewSubCommitsSwitchControllerFactory( - common, - func(commits []*models.Commit) { gui.State.Model.SubCommits = commits }, - ) + setSubCommits := func(commits []*models.Commit) { gui.State.Model.SubCommits = commits } for _, context := range []controllers.ContextWithRefName{ gui.State.Contexts.Branches, gui.State.Contexts.RemoteBranches, gui.State.Contexts.Tags, } { - controllers.AttachControllers(context, switchToSubCommitsControllerFactory.Create(context)) + controllers.AttachControllers(context, controllers.NewSwitchToSubCommitsController( + common, setSubCommits, context, + )) } - commitishControllerFactory := controllers.NewCommitishControllerFactory( - common, - gui.SwitchToCommitFilesContext, - ) - - for _, context := range []controllers.Commitish{ + for _, context := range []controllers.CanSwitchToDiffFiles{ gui.State.Contexts.LocalCommits, gui.State.Contexts.ReflogCommits, gui.State.Contexts.SubCommits, gui.State.Contexts.Stash, } { - controllers.AttachControllers(context, commitishControllerFactory.Create(context)) + controllers.AttachControllers(context, controllers.NewSwitchToDiffFilesController( + common, gui.SwitchToCommitFilesContext, context, + )) } - basicCommitsControllerFactory := controllers.NewBasicCommitsControllerFactory(common) - for _, context := range []controllers.ContainsCommits{ gui.State.Contexts.LocalCommits, gui.State.Contexts.ReflogCommits, gui.State.Contexts.SubCommits, } { - controllers.AttachControllers(context, basicCommitsControllerFactory.Create(context)) + controllers.AttachControllers(context, controllers.NewBasicCommitsController(common, context)) } controllers.AttachControllers(gui.State.Contexts.Branches, branchesController, gitFlowController) diff --git a/pkg/gui/controllers/basic_commits_controller.go b/pkg/gui/controllers/basic_commits_controller.go index c59686126..bcd180612 100644 --- a/pkg/gui/controllers/basic_commits_controller.go +++ b/pkg/gui/controllers/basic_commits_controller.go @@ -8,10 +8,6 @@ import ( // This controller is for all contexts that contain a list of commits. -type BasicCommitsControllerFactory struct { - controllerCommon *controllerCommon -} - var _ types.IController = &BasicCommitsController{} type ContainsCommits interface { @@ -27,18 +23,10 @@ type BasicCommitsController struct { context ContainsCommits } -func NewBasicCommitsControllerFactory( - common *controllerCommon, -) *BasicCommitsControllerFactory { - return &BasicCommitsControllerFactory{ - controllerCommon: common, - } -} - -func (self *BasicCommitsControllerFactory) Create(context ContainsCommits) *BasicCommitsController { +func NewBasicCommitsController(controllerCommon *controllerCommon, context ContainsCommits) *BasicCommitsController { return &BasicCommitsController{ baseController: baseController{}, - controllerCommon: self.controllerCommon, + controllerCommon: controllerCommon, context: context, } } diff --git a/pkg/gui/controllers/commitish_controller.go b/pkg/gui/controllers/switch_to_diff_files_controller.go similarity index 50% rename from pkg/gui/controllers/commitish_controller.go rename to pkg/gui/controllers/switch_to_diff_files_controller.go index 04e271253..9a3111cae 100644 --- a/pkg/gui/controllers/commitish_controller.go +++ b/pkg/gui/controllers/switch_to_diff_files_controller.go @@ -6,47 +6,35 @@ import ( // This controller is for all contexts that contain commit files. -type CommitishControllerFactory struct { - controllerCommon *controllerCommon - viewFiles func(SwitchToCommitFilesContextOpts) error -} +var _ types.IController = &SwitchToDiffFilesController{} -var _ types.IController = &CommitishController{} - -type Commitish interface { +type CanSwitchToDiffFiles interface { types.Context CanRebase() bool GetSelectedRefName() string } -type CommitishController struct { +type SwitchToDiffFilesController struct { baseController *controllerCommon - context Commitish - + context CanSwitchToDiffFiles viewFiles func(SwitchToCommitFilesContextOpts) error } -func NewCommitishControllerFactory( - common *controllerCommon, +func NewSwitchToDiffFilesController( + controllerCommon *controllerCommon, viewFiles func(SwitchToCommitFilesContextOpts) error, -) *CommitishControllerFactory { - return &CommitishControllerFactory{ - controllerCommon: common, + context CanSwitchToDiffFiles, +) *SwitchToDiffFilesController { + return &SwitchToDiffFilesController{ + baseController: baseController{}, + controllerCommon: controllerCommon, + context: context, viewFiles: viewFiles, } } -func (self *CommitishControllerFactory) Create(context Commitish) *CommitishController { - return &CommitishController{ - baseController: baseController{}, - controllerCommon: self.controllerCommon, - context: context, - viewFiles: self.viewFiles, - } -} - -func (self *CommitishController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { +func (self *SwitchToDiffFilesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { Key: opts.GetKey(opts.Config.Universal.GoInto), @@ -58,11 +46,11 @@ func (self *CommitishController) GetKeybindings(opts types.KeybindingsOpts) []*t return bindings } -func (self *CommitishController) GetOnClick() func() error { +func (self *SwitchToDiffFilesController) GetOnClick() func() error { return self.checkSelected(self.enter) } -func (self *CommitishController) checkSelected(callback func(string) error) func() error { +func (self *SwitchToDiffFilesController) checkSelected(callback func(string) error) func() error { return func() error { refName := self.context.GetSelectedRefName() if refName == "" { @@ -73,7 +61,7 @@ func (self *CommitishController) checkSelected(callback func(string) error) func } } -func (self *CommitishController) enter(refName string) error { +func (self *SwitchToDiffFilesController) enter(refName string) error { return self.viewFiles(SwitchToCommitFilesContextOpts{ RefName: refName, CanRebase: self.context.CanRebase(), @@ -81,6 +69,6 @@ func (self *CommitishController) enter(refName string) error { }) } -func (self *CommitishController) Context() types.Context { +func (self *SwitchToDiffFilesController) Context() types.Context { return self.context } diff --git a/pkg/gui/controllers/sub_commits_switch_controller.go b/pkg/gui/controllers/switch_to_sub_commits_controller.go similarity index 59% rename from pkg/gui/controllers/sub_commits_switch_controller.go rename to pkg/gui/controllers/switch_to_sub_commits_controller.go index 4c8f086a5..f7e9f6702 100644 --- a/pkg/gui/controllers/sub_commits_switch_controller.go +++ b/pkg/gui/controllers/switch_to_sub_commits_controller.go @@ -6,19 +6,14 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/types" ) -type SubCommitsSwitchControllerFactory struct { - controllerCommon *controllerCommon - setSubCommits func([]*models.Commit) -} - -var _ types.IController = &SubCommitsSwitchController{} +var _ types.IController = &SwitchToSubCommitsController{} type ContextWithRefName interface { types.Context GetSelectedRefName() string } -type SubCommitsSwitchController struct { +type SwitchToSubCommitsController struct { baseController *controllerCommon context ContextWithRefName @@ -26,26 +21,20 @@ type SubCommitsSwitchController struct { setSubCommits func([]*models.Commit) } -func NewSubCommitsSwitchControllerFactory( - common *controllerCommon, +func NewSwitchToSubCommitsController( + controllerCommon *controllerCommon, setSubCommits func([]*models.Commit), -) *SubCommitsSwitchControllerFactory { - return &SubCommitsSwitchControllerFactory{ - controllerCommon: common, + context ContextWithRefName, +) *SwitchToSubCommitsController { + return &SwitchToSubCommitsController{ + baseController: baseController{}, + controllerCommon: controllerCommon, + context: context, setSubCommits: setSubCommits, } } -func (self *SubCommitsSwitchControllerFactory) Create(context ContextWithRefName) *SubCommitsSwitchController { - return &SubCommitsSwitchController{ - baseController: baseController{}, - controllerCommon: self.controllerCommon, - context: context, - setSubCommits: self.setSubCommits, - } -} - -func (self *SubCommitsSwitchController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { +func (self *SwitchToSubCommitsController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { bindings := []*types.Binding{ { Handler: self.viewCommits, @@ -57,11 +46,11 @@ func (self *SubCommitsSwitchController) GetKeybindings(opts types.KeybindingsOpt return bindings } -func (self *SubCommitsSwitchController) GetOnClick() func() error { +func (self *SwitchToSubCommitsController) GetOnClick() func() error { return self.viewCommits } -func (self *SubCommitsSwitchController) viewCommits() error { +func (self *SwitchToSubCommitsController) viewCommits() error { refName := self.context.GetSelectedRefName() if refName == "" { return nil @@ -87,6 +76,6 @@ func (self *SubCommitsSwitchController) viewCommits() error { return self.c.PushContext(self.contexts.SubCommits) } -func (self *SubCommitsSwitchController) Context() types.Context { +func (self *SwitchToSubCommitsController) Context() types.Context { return self.context } From e0b05f44647a22bd37515c3dfe1fb97a117716bb Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 26 Mar 2022 17:07:04 +1100 Subject: [PATCH 130/385] fix cherry picking bug --- pkg/gui/controllers/basic_commits_controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/gui/controllers/basic_commits_controller.go b/pkg/gui/controllers/basic_commits_controller.go index bcd180612..2065b54c5 100644 --- a/pkg/gui/controllers/basic_commits_controller.go +++ b/pkg/gui/controllers/basic_commits_controller.go @@ -220,5 +220,5 @@ func (self *BasicCommitsController) copy(commit *models.Commit) error { } func (self *BasicCommitsController) copyRange(*models.Commit) error { - return self.helpers.CherryPick.CopyRange(self.context.GetSelectedLineIdx(), self.model.Commits, self.context) + return self.helpers.CherryPick.CopyRange(self.context.GetSelectedLineIdx(), self.context.GetCommits(), self.context) } From e039429885996f1335430a856b846d8dc6279325 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 26 Mar 2022 17:08:23 +1100 Subject: [PATCH 131/385] better wording again --- pkg/gui/controllers.go | 2 +- pkg/gui/controllers/switch_to_sub_commits_controller.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/gui/controllers.go b/pkg/gui/controllers.go index b0f100f2f..8e28e7f6e 100644 --- a/pkg/gui/controllers.go +++ b/pkg/gui/controllers.go @@ -131,7 +131,7 @@ func (gui *Gui) resetControllers() { setSubCommits := func(commits []*models.Commit) { gui.State.Model.SubCommits = commits } - for _, context := range []controllers.ContextWithRefName{ + for _, context := range []controllers.CanSwitchToSubCommits{ gui.State.Contexts.Branches, gui.State.Contexts.RemoteBranches, gui.State.Contexts.Tags, diff --git a/pkg/gui/controllers/switch_to_sub_commits_controller.go b/pkg/gui/controllers/switch_to_sub_commits_controller.go index f7e9f6702..abd8642d3 100644 --- a/pkg/gui/controllers/switch_to_sub_commits_controller.go +++ b/pkg/gui/controllers/switch_to_sub_commits_controller.go @@ -8,7 +8,7 @@ import ( var _ types.IController = &SwitchToSubCommitsController{} -type ContextWithRefName interface { +type CanSwitchToSubCommits interface { types.Context GetSelectedRefName() string } @@ -16,7 +16,7 @@ type ContextWithRefName interface { type SwitchToSubCommitsController struct { baseController *controllerCommon - context ContextWithRefName + context CanSwitchToSubCommits setSubCommits func([]*models.Commit) } @@ -24,7 +24,7 @@ type SwitchToSubCommitsController struct { func NewSwitchToSubCommitsController( controllerCommon *controllerCommon, setSubCommits func([]*models.Commit), - context ContextWithRefName, + context CanSwitchToSubCommits, ) *SwitchToSubCommitsController { return &SwitchToSubCommitsController{ baseController: baseController{}, From 13b90ac37f40baa648c25fab6d299ae0fa59118b Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Thu, 24 Mar 2022 22:07:30 +1100 Subject: [PATCH 132/385] support viewing commits of reflog entry and show better view title --- docs/keybindings/Keybindings_en.md | 22 +++++++++---- docs/keybindings/Keybindings_nl.md | 22 +++++++++---- docs/keybindings/Keybindings_pl.md | 22 +++++++++---- docs/keybindings/Keybindings_zh.md | 19 +++++++---- pkg/gui/commit_files_panel.go | 8 ++--- pkg/gui/context.go | 33 +++++++++++++++---- pkg/gui/context/base_context.go | 11 +++++++ pkg/gui/context/commit_files_context.go | 8 +++++ pkg/gui/context/sub_commits_context.go | 31 ++++++++++++++--- pkg/gui/controllers.go | 2 +- .../switch_to_sub_commits_controller.go | 8 +++++ pkg/gui/gui.go | 5 +++ pkg/gui/keybindings.go | 5 +-- pkg/gui/layout.go | 12 +++++-- pkg/gui/list_context_config.go | 2 +- pkg/gui/patch_building_panel.go | 2 +- pkg/gui/patch_options_panel.go | 2 +- pkg/gui/refresh.go | 2 +- pkg/gui/types/context.go | 7 ++++ pkg/gui/window.go | 4 ++- pkg/i18n/english.go | 4 +++ 21 files changed, 177 insertions(+), 54 deletions(-) diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index 836bbf791..357468176 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -111,15 +111,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: view commits - ctrl+o: copy the committed file name to the clipboard -- ## Commit Files Panel (Commit Files)+ ctrl+o: copy the committed file name to the clipboard c: checkout file d: discard this commit's changes to this file o: open file @@ -174,7 +169,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct c: copy commit (cherry-pick) C: copy commit range (cherry-pick) ctrl+r: reset cherry-picked (copied) commits selection - enter: view selected item's files + enter: view commits## Extras Panel @@ -307,3 +302,16 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: switch to a recent repo a: show all branch logs+ ctrl+o: copy commit SHA to clipboard + space: checkout commit + g: view reset options + n: new branch + c: copy commit (cherry-pick) + C: copy commit range (cherry-pick) + ctrl+r: reset cherry-picked (copied) commits selection + enter: view selected item's files +diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index 8fbf16ccd..4764eb821 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -151,15 +151,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: bekijk commits- ctrl+o: kopieer de vastgelegde bestandsnaam naar het klembord -- ## Commit bestanden Paneel (Commit bestanden)+ ctrl+o: kopieer de vastgelegde bestandsnaam naar het klembord c: bestand uitchecken d: uitsluit deze commit zijn veranderingen aan dit bestand o: open bestand @@ -214,7 +209,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct c: kopieer commit (cherry-pick) C: kopieer commit reeks (cherry-pick) ctrl+r: reset cherry-picked (gekopieerde) commits selectie - enter: bekijk gecommite bestanden + enter: bekijk commits## Extras Paneel @@ -307,3 +302,16 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: wissel naar een recente repo a: alle logs van de branch laten zien
+ ctrl+o: kopieer commit SHA naar klembord + space: checkout commit + g: bekijk reset opties + n: nieuwe branch + c: kopieer commit (cherry-pick) + C: kopieer commit reeks (cherry-pick) + ctrl+r: reset cherry-picked (gekopieerde) commits selectie + enter: bekijk gecommite bestanden +diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index 93f91050a..f7c9d726c 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -85,7 +85,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct c: kopiuj commit (przebieranie) C: kopiuj zakres commit贸w (przebieranie) ctrl+r: reset cherry-picked (copied) commits selection - enter: przegl膮daj pliki commita + enter: view commits ## Extras Panel @@ -269,15 +269,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct b: view bulk submodule options -## Pliki commita Panel - -
- ctrl+o: copy the committed file name to the clipboard -- ## Pliki commita Panel (Pliki commita)
+ ctrl+o: copy the committed file name to the clipboard c: plik wybierania d: porzu膰 zmiany commita dla tego pliku o: otw贸rz plik @@ -307,3 +302,16 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: switch to a recent repo a: poka偶 wszystkie logi ga艂臋zi+ +## Sub-commits Panel (Sub-commits) + +
+ ctrl+o: copy commit SHA to clipboard + space: checkout commit + g: wy艣wietl opcje resetu + n: nowa ga艂膮藕 + c: kopiuj commit (przebieranie) + C: kopiuj zakres commit贸w (przebieranie) + ctrl+r: reset cherry-picked (copied) commits selection + enter: przegl膮daj pliki commita +diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index 7e1b1c407..7dc0d9f7b 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -185,6 +185,18 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: 鏌ョ湅鎻愪氦鐨勬枃浠 +## 鎻愪氦 闈㈡澘 (Reflog) + +
+ ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 + space: 妫鍑烘彁浜 + g: 鏌ョ湅閲嶇疆閫夐」 + c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 + C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 + ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 + enter: 鏌ョ湅鎻愪氦 ++ ## 鎻愪氦 闈㈡澘 (鎻愪氦)
@@ -217,15 +229,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: 鏌ョ湅鎻愪氦鐨勬枃浠-## 鎻愪氦鏂囦欢 闈㈡澘 - -
- ctrl+o: 灏嗘彁浜ょ殑鏂囦欢鍚嶅鍒跺埌鍓创鏉 -- ## 鎻愪氦鏂囦欢 闈㈡澘 (鎻愪氦鏂囦欢)
+ ctrl+o: 灏嗘彁浜ょ殑鏂囦欢鍚嶅鍒跺埌鍓创鏉
c: 妫鍑烘枃浠
d: 鏀惧純瀵规鏂囦欢鐨勬彁浜ゆ洿鏀
o: 鎵撳紑鏂囦欢
diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go
index 21afc54f4..4f292d3eb 100644
--- a/pkg/gui/commit_files_panel.go
+++ b/pkg/gui/commit_files_panel.go
@@ -39,24 +39,20 @@ func (gui *Gui) commitFilesRenderToMain() error {
}
func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesContextOpts) error {
- // sometimes the commitFiles view is already shown in another window, so we need to ensure that window
- // no longer considers the commitFiles view as its main view.
- gui.resetWindowContext(gui.State.Contexts.CommitFiles)
-
gui.State.Contexts.CommitFiles.SetSelectedLineIdx(0)
gui.State.Contexts.CommitFiles.SetRefName(opts.RefName)
gui.State.Contexts.CommitFiles.SetCanRebase(opts.CanRebase)
gui.State.Contexts.CommitFiles.SetParentContext(opts.Context)
gui.State.Contexts.CommitFiles.SetWindowName(opts.Context.GetWindowName())
- if err := gui.refreshCommitFilesView(); err != nil {
+ if err := gui.refreshCommitFilesContext(); err != nil {
return err
}
return gui.c.PushContext(gui.State.Contexts.CommitFiles)
}
-func (gui *Gui) refreshCommitFilesView() error {
+func (gui *Gui) refreshCommitFilesContext() error {
currentSideContext := gui.currentSideContext()
if currentSideContext.GetKey() == context.COMMIT_FILES_CONTEXT_KEY || currentSideContext.GetKey() == context.LOCAL_COMMITS_CONTEXT_KEY {
if err := gui.handleRefreshPatchBuildingPanel(-1); err != nil {
diff --git a/pkg/gui/context.go b/pkg/gui/context.go
index e75eb0a05..c02411640 100644
--- a/pkg/gui/context.go
+++ b/pkg/gui/context.go
@@ -11,6 +11,7 @@ import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
+ "github.com/samber/lo"
)
func (gui *Gui) popupViewNames() []string {
@@ -99,8 +100,6 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error {
return gui.activateContext(c, opts...)
}
-// asynchronous code idea: functions return an error via a channel, when done
-
// pushContextWithView is to be used when you don't know which context you
// want to switch to: you only know the view that you want to switch to. It will
// look up the context currently active for that view and switch to that context
@@ -136,6 +135,10 @@ func (gui *Gui) returnFromContext() error {
}
func (gui *Gui) deactivateContext(c types.Context) error {
+ if c.IsTransient() {
+ gui.resetWindowContext(c)
+ }
+
view, _ := gui.g.View(c.GetViewName())
if view != nil && view.IsSearching() {
@@ -145,7 +148,11 @@ func (gui *Gui) deactivateContext(c types.Context) error {
}
// if we are the kind of context that is sent to back upon deactivation, we should do that
- if view != nil && (c.GetKind() == types.TEMPORARY_POPUP || c.GetKind() == types.PERSISTENT_POPUP || c.GetKey() == context.COMMIT_FILES_CONTEXT_KEY) {
+ if view != nil &&
+ (c.GetKind() == types.TEMPORARY_POPUP ||
+ c.GetKind() == types.PERSISTENT_POPUP ||
+ c.GetKey() == context.COMMIT_FILES_CONTEXT_KEY ||
+ c.GetKey() == context.SUB_COMMITS_CONTEXT_KEY) {
view.Visible = false
}
@@ -204,6 +211,11 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro
return err
}
+ desiredTitle := c.Title()
+ if desiredTitle != "" {
+ v.Title = desiredTitle
+ }
+
v.Visible = true
// if the new context's view was previously displaying another context, render the new context
@@ -380,10 +392,17 @@ func (gui *Gui) onViewFocusLost(oldView *gocui.View, newView *gocui.View) error
_ = oldView.SetOriginX(0)
- if oldView == gui.Views.CommitFiles && newView != gui.Views.Main && newView != gui.Views.Secondary && newView != gui.Views.Search {
- gui.resetWindowContext(gui.State.Contexts.CommitFiles)
- if err := gui.deactivateContext(gui.State.Contexts.CommitFiles); err != nil {
- return err
+ if !lo.Contains([]*gocui.View{gui.Views.Main, gui.Views.Secondary, gui.Views.Search}, newView) {
+ transientContexts := slices.Filter(gui.State.Contexts.Flatten(), func(context types.Context) bool {
+ return context.IsTransient()
+ })
+
+ for _, context := range transientContexts {
+ if oldView.Name() == context.GetViewName() {
+ if err := gui.deactivateContext(context); err != nil {
+ return err
+ }
+ }
}
}
diff --git a/pkg/gui/context/base_context.go b/pkg/gui/context/base_context.go
index 9b006662f..4e73aa0ff 100644
--- a/pkg/gui/context/base_context.go
+++ b/pkg/gui/context/base_context.go
@@ -17,6 +17,7 @@ type BaseContext struct {
onClickFn func() error
focusable bool
+ transient bool
*ParentContextMgr
}
@@ -29,6 +30,7 @@ type NewBaseContextOpts struct {
ViewName string
WindowName string
Focusable bool
+ Transient bool
OnGetOptionsMap func() map[string]string
}
@@ -41,6 +43,7 @@ func NewBaseContext(opts NewBaseContextOpts) *BaseContext {
windowName: opts.WindowName,
onGetOptionsMap: opts.OnGetOptionsMap,
focusable: opts.Focusable,
+ transient: opts.Transient,
ParentContextMgr: &ParentContextMgr{},
}
}
@@ -115,3 +118,11 @@ func (self *BaseContext) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocu
func (self *BaseContext) IsFocusable() bool {
return self.focusable
}
+
+func (self *BaseContext) IsTransient() bool {
+ return self.transient
+}
+
+func (self *BaseContext) Title() string {
+ return ""
+}
diff --git a/pkg/gui/context/commit_files_context.go b/pkg/gui/context/commit_files_context.go
index 0576be102..5ad7144dc 100644
--- a/pkg/gui/context/commit_files_context.go
+++ b/pkg/gui/context/commit_files_context.go
@@ -1,10 +1,13 @@
package context
import (
+ "fmt"
+
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
"github.com/jesseduffield/lazygit/pkg/gui/types"
+ "github.com/jesseduffield/lazygit/pkg/utils"
)
type CommitFilesContext struct {
@@ -37,6 +40,7 @@ func NewCommitFilesContext(
Key: COMMIT_FILES_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT,
Focusable: true,
+ Transient: true,
}),
ContextCallbackOpts{
OnFocus: onFocus,
@@ -59,3 +63,7 @@ func (self *CommitFilesContext) GetSelectedItemId() string {
return item.ID()
}
+
+func (self *CommitFilesContext) Title() string {
+ return fmt.Sprintf(self.c.Tr.CommitFilesDynamicTitle, utils.TruncateWithEllipsis(self.GetRefName(), 50))
+}
diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go
index 315093f8f..6c1d5910f 100644
--- a/pkg/gui/context/sub_commits_context.go
+++ b/pkg/gui/context/sub_commits_context.go
@@ -1,13 +1,16 @@
package context
import (
+ "fmt"
+
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/types"
+ "github.com/jesseduffield/lazygit/pkg/utils"
)
type SubCommitsContext struct {
- *BasicViewModel[*models.Commit]
+ *SubCommitsViewModel
*ViewportListContextTrait
}
@@ -24,18 +27,22 @@ func NewSubCommitsContext(
c *types.HelperCommon,
) *SubCommitsContext {
- viewModel := NewBasicViewModel(getModel)
+ viewModel := &SubCommitsViewModel{
+ BasicViewModel: NewBasicViewModel(getModel),
+ refName: "",
+ }
return &SubCommitsContext{
- BasicViewModel: viewModel,
+ SubCommitsViewModel: viewModel,
ViewportListContextTrait: &ViewportListContextTrait{
ListContextTrait: &ListContextTrait{
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
- ViewName: "branches",
+ ViewName: "subCommits",
WindowName: "branches",
Key: SUB_COMMITS_CONTEXT_KEY,
Kind: types.SIDE_CONTEXT,
Focusable: true,
+ Transient: true,
}), ContextCallbackOpts{
OnFocus: onFocus,
OnFocusLost: onFocusLost,
@@ -50,6 +57,16 @@ func NewSubCommitsContext(
}
}
+type SubCommitsViewModel struct {
+ // name of the ref that the sub-commits are shown for
+ refName string
+ *BasicViewModel[*models.Commit]
+}
+
+func (self *SubCommitsViewModel) SetRefName(refName string) {
+ self.refName = refName
+}
+
func (self *SubCommitsContext) GetSelectedItemId() string {
item := self.GetSelected()
if item == nil {
@@ -63,6 +80,8 @@ func (self *SubCommitsContext) CanRebase() bool {
return false
}
+// not to be confused with the refName in the view model. This is the ref name of
+// the selected commit
func (self *SubCommitsContext) GetSelectedRefName() string {
item := self.GetSelected()
@@ -76,3 +95,7 @@ func (self *SubCommitsContext) GetSelectedRefName() string {
func (self *SubCommitsContext) GetCommits() []*models.Commit {
return self.getModel()
}
+
+func (self *SubCommitsContext) Title() string {
+ return fmt.Sprintf(self.c.Tr.SubCommitsDynamicTitle, utils.TruncateWithEllipsis(self.refName, 50))
+}
diff --git a/pkg/gui/controllers.go b/pkg/gui/controllers.go
index 8e28e7f6e..9d55625ea 100644
--- a/pkg/gui/controllers.go
+++ b/pkg/gui/controllers.go
@@ -135,6 +135,7 @@ func (gui *Gui) resetControllers() {
gui.State.Contexts.Branches,
gui.State.Contexts.RemoteBranches,
gui.State.Contexts.Tags,
+ gui.State.Contexts.ReflogCommits,
} {
controllers.AttachControllers(context, controllers.NewSwitchToSubCommitsController(
common, setSubCommits, context,
@@ -143,7 +144,6 @@ func (gui *Gui) resetControllers() {
for _, context := range []controllers.CanSwitchToDiffFiles{
gui.State.Contexts.LocalCommits,
- gui.State.Contexts.ReflogCommits,
gui.State.Contexts.SubCommits,
gui.State.Contexts.Stash,
} {
diff --git a/pkg/gui/controllers/switch_to_sub_commits_controller.go b/pkg/gui/controllers/switch_to_sub_commits_controller.go
index abd8642d3..82b52509b 100644
--- a/pkg/gui/controllers/switch_to_sub_commits_controller.go
+++ b/pkg/gui/controllers/switch_to_sub_commits_controller.go
@@ -70,8 +70,16 @@ func (self *SwitchToSubCommitsController) viewCommits() error {
}
self.setSubCommits(commits)
+
self.contexts.SubCommits.SetSelectedLineIdx(0)
self.contexts.SubCommits.SetParentContext(self.context)
+ self.contexts.SubCommits.SetWindowName(self.context.GetWindowName())
+ self.contexts.SubCommits.SetRefName(refName)
+
+ err = self.c.PostRefreshUpdate(self.contexts.SubCommits)
+ if err != nil {
+ return err
+ }
return self.c.PushContext(self.contexts.SubCommits)
}
diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go
index 144be8df5..334133487 100644
--- a/pkg/gui/gui.go
+++ b/pkg/gui/gui.go
@@ -252,6 +252,7 @@ type Views struct {
Menu *gocui.View
CommitMessage *gocui.View
CommitFiles *gocui.View
+ SubCommits *gocui.View
Information *gocui.View
AppStatus *gocui.View
Search *gocui.View
@@ -410,6 +411,7 @@ func initialViewContextMapping(contextTree *context.ContextTree) map[string]type
"branches": contextTree.Branches,
"commits": contextTree.LocalCommits,
"commitFiles": contextTree.CommitFiles,
+ "subCommits": contextTree.SubCommits,
"stash": contextTree.Stash,
"menu": contextTree.Menu,
"confirmation": contextTree.Confirmation,
@@ -601,6 +603,7 @@ func (gui *Gui) createAllViews() error {
{viewPtr: &gui.Views.Commits, name: "commits"},
{viewPtr: &gui.Views.Stash, name: "stash"},
{viewPtr: &gui.Views.CommitFiles, name: "commitFiles"},
+ {viewPtr: &gui.Views.SubCommits, name: "subCommits"},
{viewPtr: &gui.Views.Main, name: "main"},
{viewPtr: &gui.Views.Secondary, name: "secondary"},
{viewPtr: &gui.Views.Options, name: "options"},
@@ -641,6 +644,8 @@ func (gui *Gui) createAllViews() error {
gui.Views.CommitFiles.Title = gui.c.Tr.CommitFiles
gui.Views.CommitFiles.FgColor = theme.GocuiDefaultTextColor
+ gui.Views.SubCommits.FgColor = theme.GocuiDefaultTextColor
+
gui.Views.Branches.Title = gui.c.Tr.BranchesTitle
gui.Views.Branches.FgColor = theme.GocuiDefaultTextColor
diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go
index 13fdf7d26..122fbfd04 100644
--- a/pkg/gui/keybindings.go
+++ b/pkg/gui/keybindings.go
@@ -406,7 +406,7 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi
Description: self.c.Tr.LcCopyCommitShaToClipboard,
},
{
- ViewName: "branches",
+ ViewName: "subCommits",
Contexts: []string{string(context.SUB_COMMITS_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
Handler: self.handleCopySelectedSideContextItemToClipboard,
@@ -426,6 +426,7 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi
},
{
ViewName: "commitFiles",
+ Contexts: []string{string(context.COMMIT_FILES_CONTEXT_KEY)},
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
Handler: self.handleCopySelectedSideContextItemToClipboard,
Description: self.c.Tr.LcCopyCommitFileNameToClipboard,
@@ -998,7 +999,7 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi
mouseKeybindings = append(mouseKeybindings, c.GetMouseKeybindings(opts)...)
}
- for _, viewName := range []string{"status", "branches", "files", "commits", "commitFiles", "stash", "menu"} {
+ for _, viewName := range []string{"status", "branches", "files", "commits", "commitFiles", "subCommits", "stash", "menu"} {
bindings = append(bindings, []*types.Binding{
{ViewName: viewName, Key: opts.GetKey(opts.Config.Universal.PrevBlock), Modifier: gocui.ModNone, Handler: self.previousSideWindow},
{ViewName: viewName, Key: opts.GetKey(opts.Config.Universal.NextBlock), Modifier: gocui.ModNone, Handler: self.nextSideWindow},
diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go
index 350549311..c77c9030d 100644
--- a/pkg/gui/layout.go
+++ b/pkg/gui/layout.go
@@ -2,6 +2,7 @@ package gui
import (
"github.com/jesseduffield/gocui"
+ "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/theme"
)
@@ -96,6 +97,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
{viewName: "files", windowName: "files", frame: true},
{viewName: "branches", windowName: "branches", frame: true},
{viewName: "commitFiles", windowName: gui.State.Contexts.CommitFiles.GetWindowName(), frame: true},
+ {viewName: "subCommits", windowName: gui.State.Contexts.SubCommits.GetWindowName(), frame: true},
{viewName: "commits", windowName: "commits", frame: true},
{viewName: "stash", windowName: "stash", frame: true},
{viewName: "options", windowName: "options", frame: false},
@@ -113,8 +115,13 @@ func (gui *Gui) layout(g *gocui.Gui) error {
}
}
- // if the commit files view is the view to be displayed for its window, we'll display it
- gui.Views.CommitFiles.Visible = gui.getViewNameForWindow(gui.State.Contexts.CommitFiles.GetWindowName()) == "commitFiles"
+ for _, context := range []types.Context{gui.State.Contexts.SubCommits, gui.State.Contexts.CommitFiles} {
+ view, err := gui.g.View(context.GetViewName())
+ if err != nil && err.Error() != UNKNOWN_VIEW_ERROR_MSG {
+ return err
+ }
+ view.Visible = gui.getViewNameForWindow(context.GetWindowName()) == context.GetViewName()
+ }
if gui.PrevLayout.Information != informationStr {
gui.setViewContent(gui.Views.Information, informationStr)
@@ -206,6 +213,7 @@ func (gui *Gui) onInitialViewsCreation() error {
gui.Views.Branches,
gui.Views.Commits,
gui.Views.Stash,
+ gui.Views.SubCommits,
gui.Views.CommitFiles,
gui.Views.Main,
gui.Views.Secondary,
diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go
index 5a3f172f0..b2f267a6a 100644
--- a/pkg/gui/list_context_config.go
+++ b/pkg/gui/list_context_config.go
@@ -141,7 +141,7 @@ func (gui *Gui) branchCommitsListContext() *context.LocalCommitsContext {
func (gui *Gui) subCommitsListContext() *context.SubCommitsContext {
return context.NewSubCommitsContext(
func() []*models.Commit { return gui.State.Model.SubCommits },
- gui.Views.Branches,
+ gui.Views.SubCommits,
func(startIdx int, length int) [][]string {
selectedCommitSha := ""
if gui.currentContext().GetKey() == context.SUB_COMMITS_CONTEXT_KEY {
diff --git a/pkg/gui/patch_building_panel.go b/pkg/gui/patch_building_panel.go
index cae6167a4..b2c3c4ab2 100644
--- a/pkg/gui/patch_building_panel.go
+++ b/pkg/gui/patch_building_panel.go
@@ -90,7 +90,7 @@ func (gui *Gui) handleToggleSelectionForPatch() error {
return err
}
- if err := gui.refreshCommitFilesView(); err != nil {
+ if err := gui.refreshCommitFilesContext(); err != nil {
return err
}
diff --git a/pkg/gui/patch_options_panel.go b/pkg/gui/patch_options_panel.go
index 14de524a5..439b726cb 100644
--- a/pkg/gui/patch_options_panel.go
+++ b/pkg/gui/patch_options_panel.go
@@ -194,5 +194,5 @@ func (gui *Gui) handleResetPatch() error {
return err
}
}
- return gui.refreshCommitFilesView()
+ return gui.refreshCommitFilesContext()
}
diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go
index 602eb37e9..f56cb55d7 100644
--- a/pkg/gui/refresh.go
+++ b/pkg/gui/refresh.go
@@ -187,7 +187,7 @@ func (gui *Gui) refreshCommits() {
commit := gui.getSelectedLocalCommit()
if commit != nil {
gui.State.Contexts.CommitFiles.SetRefName(commit.RefName())
- _ = gui.refreshCommitFilesView()
+ _ = gui.refreshCommitFilesContext()
}
}
wg.Done()
diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go
index 58dee1c0e..bf4051538 100644
--- a/pkg/gui/types/context.go
+++ b/pkg/gui/types/context.go
@@ -33,6 +33,13 @@ type IBaseContext interface {
SetWindowName(string)
GetKey() ContextKey
IsFocusable() bool
+ // if a context is transient, then when it loses focus, its corresponding view
+ // returns control of the window to the default view for that window
+ IsTransient() bool
+
+ // returns the desired title for the view upon activation. If there is no desired title (returns empty string), then
+ // no title will be set
+ Title() string
GetOptionsMap() map[string]string
diff --git a/pkg/gui/window.go b/pkg/gui/window.go
index 4ea33292a..88d93d5ae 100644
--- a/pkg/gui/window.go
+++ b/pkg/gui/window.go
@@ -35,5 +35,7 @@ func (gui *Gui) currentWindow() string {
func (gui *Gui) resetWindowContext(c types.Context) {
// we assume here that the window contains as its default view a view with the same name as the window
windowName := c.GetWindowName()
- gui.State.WindowViewNameMap[windowName] = windowName
+ if gui.State.WindowViewNameMap[windowName] == c.GetViewName() {
+ gui.State.WindowViewNameMap[windowName] = windowName
+ }
}
diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go
index b09b6550c..a5cadb47d 100644
--- a/pkg/i18n/english.go
+++ b/pkg/i18n/english.go
@@ -230,6 +230,8 @@ type TranslationSet struct {
CheckingOutStatus string
CommittingStatus string
CommitFiles string
+ SubCommitsDynamicTitle string
+ CommitFilesDynamicTitle string
LcViewItemFiles string
CommitFilesTitle string
LcCheckoutCommitFile string
@@ -819,6 +821,8 @@ func EnglishTranslationSet() TranslationSet {
CheckingOutStatus: "checking out",
CommittingStatus: "committing",
CommitFiles: "Commit files",
+ SubCommitsDynamicTitle: "Commits for %s",
+ CommitFilesDynamicTitle: "Diff files for %s",
LcViewItemFiles: "view selected item's files",
CommitFilesTitle: "Commit Files",
LcCheckoutCommitFile: "checkout file",
From ad7703df65e09d23bb7e709ca9b22251673ac272 Mon Sep 17 00:00:00 2001
From: Jesse Duffield
Date: Sat, 26 Mar 2022 14:44:30 +1100
Subject: [PATCH 133/385] show namesake for child views
---
docs/keybindings/Keybindings_en.md | 154 ++++------
docs/keybindings/Keybindings_nl.md | 170 +++++-----
docs/keybindings/Keybindings_pl.md | 290 ++++++++----------
docs/keybindings/Keybindings_zh.md | 253 +++++++--------
pkg/cheatsheet/generate.go | 39 +--
pkg/cheatsheet/generate_test.go | 70 ++---
pkg/gui/commit_files_panel.go | 4 +-
pkg/gui/context.go | 15 +-
pkg/gui/context/branches_context.go | 10 +
pkg/gui/context/commit_files_context.go | 9 +-
pkg/gui/context/context.go | 19 +-
pkg/gui/context/dynamic_title_builder.go | 23 ++
pkg/gui/context/local_commits_context.go | 10 +
pkg/gui/context/reflog_commits_context.go | 10 +
pkg/gui/context/remote_branches_context.go | 17 +-
pkg/gui/context/stash_context.go | 10 +
pkg/gui/context/sub_commits_context.go | 12 +
pkg/gui/context/tags_context.go | 10 +
.../controllers/local_commits_controller.go | 15 +-
pkg/gui/controllers/remotes_controller.go | 5 +
.../switch_to_diff_files_controller.go | 8 +-
.../switch_to_sub_commits_controller.go | 2 +
pkg/gui/controllers/types.go | 14 +-
pkg/gui/gui.go | 71 +++--
pkg/gui/keybindings.go | 2 +-
pkg/gui/layout.go | 5 +-
pkg/gui/list_context_config.go | 2 +-
pkg/gui/refresh.go | 2 +
pkg/i18n/chinese.go | 2 +-
pkg/i18n/dutch.go | 10 +-
pkg/i18n/english.go | 26 +-
.../reflogCommitFiles/recording.json | 126 +++++++-
32 files changed, 766 insertions(+), 649 deletions(-)
create mode 100644 pkg/gui/context/dynamic_title_builder.go
diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md
index 357468176..eda2fa1a4 100644
--- a/docs/keybindings/Keybindings_en.md
+++ b/docs/keybindings/Keybindings_en.md
@@ -41,7 +41,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
[: previous tab
-## Branches Panel (Branches Tab)
+## Branches
ctrl+o: copy branch name to clipboard @@ -62,56 +62,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: view commits-## Branches Panel (Remote Branches (in Remotes tab)) - -
- space: checkout - n: new branch - M: merge into currently checked out branch - r: rebase checked-out branch onto this branch - d: delete branch - u: set as upstream of checked-out branch - esc: Return to remotes list - g: view reset options - enter: view commits -- -## Branches Panel (Remotes Tab) - -
- f: fetch remote - n: add new remote - d: remove remote - e: edit remote -- -## Branches Panel (Sub-commits) - -
- ctrl+o: copy commit SHA to clipboard - space: checkout commit - y: copy commit attribute - o: open commit in browser - n: create new branch off of commit - g: reset to this commit - c: copy commit (cherry-pick) - C: copy commit range (cherry-pick) - ctrl+r: reset cherry-picked (copied) commits selection - enter: view selected item's files -- -## Branches Panel (Tags Tab) - -
- space: checkout - d: delete tag - P: push tag - n: create tag - g: view reset options - enter: view commits -- -## Commit Files Panel (Commit Files) +## Commit Files
ctrl+o: copy the committed file name to the clipboard @@ -125,7 +76,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct `: toggle file tree view-## Commits Panel (Commits) +## Commits
ctrl+o: copy commit SHA to clipboard @@ -157,28 +108,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: view selected item's files-## Commits Panel (Reflog Tab) - -
- ctrl+o: copy commit SHA to clipboard - space: checkout commit - y: copy commit attribute - o: open commit in browser - n: create new branch off of commit - g: reset to this commit - c: copy commit (cherry-pick) - C: copy commit range (cherry-pick) - ctrl+r: reset cherry-picked (copied) commits selection - enter: view commits -- -## Extras Panel - -
- @: open command log menu -- -## Files Panel (Files) +## Files
ctrl+o: copy the file name to the clipboard @@ -205,19 +135,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct f: fetch-## Files Panel (Submodules) - -
- ctrl+o: copy submodule name to clipboard - enter: enter submodule - d: remove submodule - u: update submodule - n: add new submodule - e: update submodule URL - i: initialize submodule - b: view bulk submodule options -- ## Main Panel (Merging)
@@ -277,13 +194,42 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct C: commit changes using git editor-## Menu Panel +## Reflog
- esc: close menu + ctrl+o: copy commit SHA to clipboard + space: checkout commit + g: view reset options + c: copy commit (cherry-pick) + C: copy commit range (cherry-pick) + ctrl+r: reset cherry-picked (copied) commits selection + enter: view commits-## Stash Panel (Stash) +## Remote Branches + +
+ space: checkout + n: new branch + M: merge into currently checked out branch + r: rebase checked-out branch onto this branch + d: delete branch + u: set as upstream of checked-out branch + esc: Return to remotes list + g: view reset options + enter: view commits ++ +## Remotes + +
+ f: fetch remote + n: add new remote + d: remove remote + e: edit remote ++ +## Stash
space: apply @@ -293,7 +239,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: view selected item's files-## Status Panel (Status) +## Status
e: edit config file @@ -303,7 +249,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct a: show all branch logs-## Sub-commits Panel (Sub-commits) +## Sub-commits
ctrl+o: copy commit SHA to clipboard @@ -315,3 +261,27 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+r: reset cherry-picked (copied) commits selection enter: view selected item's files+ +## Submodules + +
+ ctrl+o: copy submodule name to clipboard + enter: enter submodule + d: remove submodule + u: update submodule + n: add new submodule + e: update submodule URL + i: initialize submodule + b: view bulk submodule options ++ +## Tags + +
+ space: checkout + d: delete tag + P: push tag + n: create tag + g: view reset options + enter: view commits +diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index 4764eb821..b6220463f 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -41,7 +41,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct [: vorige tabblad -## Bestanden Paneel (Bestanden) +## Bestanden
ctrl+o: kopieer de bestandsnaam naar het klembord @@ -68,20 +68,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct f: fetch-## Bestanden Paneel (Submodules) - -
- ctrl+o: kopieer submodule naam naar klembord - enter: enter submodule - d: remove submodule - u: update submodule - n: voeg nieuwe submodule toe - e: update submodule URL - i: initialiseer submodule - b: bekijk bulk submodule opties -- -## Branches Paneel (Branches Tabblad) +## Branches
ctrl+o: kopieer branch name naar klembord @@ -102,56 +89,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: bekijk commits-## Branches Paneel (Remote Branches (in Remotes tabblad)) - -
- space: uitchecken - n: nieuwe branch - M: merge in met huidige checked out branch - r: rebase branch - d: verwijder branch - u: stel in als upstream van uitgecheckte branch - esc: ga terug naar remotes lijst - g: bekijk reset opties - enter: bekijk commits -- -## Branches Paneel (Remotes Tabblad) - -
- f: fetch remote - n: voeg een nieuwe remote toe - d: verwijder remote - e: wijzig remote -- -## Branches Paneel (Sub-commits) - -
- ctrl+o: kopieer commit SHA naar klembord - space: checkout commit - y: copy commit attribute - o: open commit in browser - n: cre毛er nieuwe branch van commit - g: reset naar deze commit - c: kopieer commit (cherry-pick) - C: kopieer commit reeks (cherry-pick) - ctrl+r: reset cherry-picked (gekopieerde) commits selectie - enter: bekijk gecommite bestanden -- -## Branches Paneel (Tags Tabblad) - -
- space: uitchecken - d: verwijder tag - P: push tag - n: cre毛er tag - g: bekijk reset opties - enter: bekijk commits -- -## Commit bestanden Paneel (Commit bestanden) +## Commit bestanden
ctrl+o: kopieer de vastgelegde bestandsnaam naar het klembord @@ -165,7 +103,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct `: toggle bestandsboom weergave-## Commits Paneel (Commits) +## Commits
ctrl+o: kopieer commit SHA naar klembord @@ -197,28 +135,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: bekijk gecommite bestanden-## Commits Paneel (Reflog Tabblad) - -
- ctrl+o: kopieer commit SHA naar klembord - space: checkout commit - y: copy commit attribute - o: open commit in browser - n: cre毛er nieuwe branch van commit - g: reset naar deze commit - c: kopieer commit (cherry-pick) - C: kopieer commit reeks (cherry-pick) - ctrl+r: reset cherry-picked (gekopieerde) commits selectie - enter: bekijk commits -- -## Extras Paneel - -
- @: open command log menu -- -## Hoofd Paneel (Mergen) +## Mergen
esc: ga terug naar het bestanden paneel @@ -232,14 +149,14 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct z: ongedaan maken-## Hoofd Paneel (Normaal) +## Normaal
mouse wheel down: scroll omlaag (fn+up) mouse wheel up: scroll omhoog (fn+down)-## Hoofd Paneel (Patch Bouwen) +## Patch Bouwen
esc: sluit lijn-bij-lijn modus @@ -255,7 +172,42 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct a: toggle selecteer hunk-## Hoofd Paneel (Staging) +## Reflog + +
+ ctrl+o: kopieer commit SHA naar klembord + space: checkout commit + g: bekijk reset opties + c: kopieer commit (cherry-pick) + C: kopieer commit reeks (cherry-pick) + ctrl+r: reset cherry-picked (gekopieerde) commits selectie + enter: bekijk commits ++ +## Remote Branches + +
+ space: uitchecken + n: nieuwe branch + M: merge in met huidige checked out branch + r: rebase branch + d: verwijder branch + u: stel in als upstream van uitgecheckte branch + esc: ga terug naar remotes lijst + g: bekijk reset opties + enter: bekijk commits ++ +## Remotes + +
+ f: fetch remote + n: voeg een nieuwe remote toe + d: verwijder remote + e: wijzig remote ++ +## Staging
esc: ga terug naar het bestanden paneel @@ -277,13 +229,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct C: commit veranderingen met de git editor-## Menu Paneel - -
- esc: sluit menu -- -## Stash Paneel (Stash) +## Stash
space: toepassen @@ -293,7 +239,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: bekijk gecommite bestanden-## Status Paneel (Status) +## Status
e: verander config bestand @@ -303,7 +249,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct a: alle logs van de branch laten zien-## Sub-commits Paneel (Sub-commits) +## Sub-commits
ctrl+o: kopieer commit SHA naar klembord @@ -315,3 +261,27 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+r: reset cherry-picked (gekopieerde) commits selectie enter: bekijk gecommite bestanden+ +## Submodules + +
+ ctrl+o: kopieer submodule naam naar klembord + enter: enter submodule + d: remove submodule + u: update submodule + n: voeg nieuwe submodule toe + e: update submodule URL + i: initialiseer submodule + b: bekijk bulk submodule opties ++ +## Tags + +
+ space: uitchecken + d: verwijder tag + P: push tag + n: cre毛er tag + g: bekijk reset opties + enter: bekijk commits +diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index f7c9d726c..aa1b9295b 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -41,7 +41,28 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct [: previous tab -## Commity Panel (Commity) +## Branches + +
+ ctrl+o: copy branch name to clipboard + i: show git-flow options + space: prze艂膮cz + n: nowa ga艂膮藕 + o: utw贸rz 偶膮danie pobrania + O: utw贸rz opcje 偶膮dania 艣ci膮gni臋cia + ctrl+y: skopiuj adres URL 偶膮dania pobrania do schowka + c: prze艂膮cz u偶ywaj膮c nazwy + F: wymu艣 prze艂膮czenie + d: usu艅 ga艂膮藕 + r: zmiana bazy ga艂臋zi + M: scal do obecnej ga艂臋zi + f: fast-forward this branch from its upstream + g: wy艣wietl opcje resetu + R: rename branch + enter: view commits ++ +## Commity
ctrl+o: copy commit SHA to clipboard @@ -73,98 +94,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: przegl膮daj pliki commita-## Commity Panel (Reflog Tab) - -
- ctrl+o: copy commit SHA to clipboard - space: checkout commit - y: copy commit attribute - o: open commit in browser - n: create new branch off of commit - g: zresetuj do tego commita - c: kopiuj commit (przebieranie) - C: kopiuj zakres commit贸w (przebieranie) - ctrl+r: reset cherry-picked (copied) commits selection - enter: view commits -- -## Extras Panel - -
- @: open command log menu -- -## Ga艂臋zie Panel (Branches Tab) - -
- ctrl+o: copy branch name to clipboard - i: show git-flow options - space: prze艂膮cz - n: nowa ga艂膮藕 - o: utw贸rz 偶膮danie pobrania - O: utw贸rz opcje 偶膮dania 艣ci膮gni臋cia - ctrl+y: skopiuj adres URL 偶膮dania pobrania do schowka - c: prze艂膮cz u偶ywaj膮c nazwy - F: wymu艣 prze艂膮czenie - d: usu艅 ga艂膮藕 - r: zmiana bazy ga艂臋zi - M: scal do obecnej ga艂臋zi - f: fast-forward this branch from its upstream - g: wy艣wietl opcje resetu - R: rename branch - enter: view commits -- -## Ga艂臋zie Panel (Remote Branches (in Remotes tab)) - -
- space: prze艂膮cz - n: nowa ga艂膮藕 - M: scal do obecnej ga艂臋zi - r: zmiana bazy ga艂臋zi - d: usu艅 ga艂膮藕 - u: set as upstream of checked-out branch - esc: wr贸膰 do listy repozytori贸w zdalnych - g: wy艣wietl opcje resetu - enter: view commits -- -## Ga艂臋zie Panel (Remotes Tab) - -
- f: fetch remote - n: add new remote - d: remove remote - e: edit remote -- -## Ga艂臋zie Panel (Sub-commits) - -
- ctrl+o: copy commit SHA to clipboard - space: checkout commit - y: copy commit attribute - o: open commit in browser - n: create new branch off of commit - g: zresetuj do tego commita - c: kopiuj commit (przebieranie) - C: kopiuj zakres commit贸w (przebieranie) - ctrl+r: reset cherry-picked (copied) commits selection - enter: przegl膮daj pliki commita -- -## Ga艂臋zie Panel (Tags Tab) - -
- space: prze艂膮cz - d: delete tag - P: push tag - n: create tag - g: wy艣wietl opcje resetu - enter: view commits -- -## G艂贸wne Panel (Patch Building) +## Main Panel (Patch Building)
esc: wy艣cie z trybu "linia po linii" @@ -180,56 +110,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct a: toggle select hunk-## G艂贸wne Panel (Poczekalnia) - -
- esc: wr贸膰 do panelu plik贸w - space: toggle line staged / unstaged - d: delete change (git reset) - tab: switch to other panel - o: otw贸rz plik - 鈻: poprzednia linia - 鈻: nast臋pna linia - 鈼: poprzedni kawa艂ek - 鈻: nast臋pny kawa艂ek - ctrl+o: copy the selected text to the clipboard - e: edytuj plik - v: toggle drag select - V: toggle drag select - a: toggle select hunk - c: Zatwierd藕 zmiany - w: zatwierd藕 zmiany bez skryptu pre-commit - C: Zatwierd藕 zmiany u偶ywaj膮c edytora -- -## G艂贸wne Panel (Scalanie) - -
- esc: wr贸膰 do panelu plik贸w - M: open external merge tool (git mergetool) - space: wybierz kawa艂ek - b: wybierz wszystkie kawa艂ki - 鈼: poprzedni konflikt - 鈻: nast臋pny konflikt - 鈻: wybierz poprzedni kawa艂ek - 鈻: wybierz nast臋pny kawa艂ek - z: cofnij -- -## G艂贸wne Panel (Zwyk艂e) - -
- mouse wheel down: przewi艅 w d贸艂 (fn+up) - mouse wheel up: przewi艅 w g贸r臋 (fn+down) -- -## Menu Panel - -
- esc: close menu -- -## Pliki Panel (Pliki) +## Pliki
ctrl+o: copy the file name to the clipboard @@ -256,20 +137,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct f: pobierz-## Pliki Panel (Submodules) - -
- ctrl+o: copy submodule name to clipboard - enter: enter submodule - d: remove submodule - u: update submodule - n: add new submodule - e: update submodule URL - i: initialize submodule - b: view bulk submodule options -- -## Pliki commita Panel (Pliki commita) +## Pliki commita
ctrl+o: copy the committed file name to the clipboard @@ -283,7 +151,78 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct `: toggle file tree view-## Schowek Panel (Schowek) +## Poczekalnia + +
+ esc: wr贸膰 do panelu plik贸w + space: toggle line staged / unstaged + d: delete change (git reset) + tab: switch to other panel + o: otw贸rz plik + 鈻: poprzednia linia + 鈻: nast臋pna linia + 鈼: poprzedni kawa艂ek + 鈻: nast臋pny kawa艂ek + ctrl+o: copy the selected text to the clipboard + e: edytuj plik + v: toggle drag select + V: toggle drag select + a: toggle select hunk + c: Zatwierd藕 zmiany + w: zatwierd藕 zmiany bez skryptu pre-commit + C: Zatwierd藕 zmiany u偶ywaj膮c edytora ++ +## Reflog + +
+ ctrl+o: copy commit SHA to clipboard + space: checkout commit + g: wy艣wietl opcje resetu + c: kopiuj commit (przebieranie) + C: kopiuj zakres commit贸w (przebieranie) + ctrl+r: reset cherry-picked (copied) commits selection + enter: view commits ++ +## Remote Branches + +
+ space: prze艂膮cz + n: nowa ga艂膮藕 + M: scal do obecnej ga艂臋zi + r: zmiana bazy ga艂臋zi + d: usu艅 ga艂膮藕 + u: set as upstream of checked-out branch + esc: wr贸膰 do listy repozytori贸w zdalnych + g: wy艣wietl opcje resetu + enter: view commits ++ +## Remotes + +
+ f: fetch remote + n: add new remote + d: remove remote + e: edit remote ++ +## Scalanie + +
+ esc: wr贸膰 do panelu plik贸w + M: open external merge tool (git mergetool) + space: wybierz kawa艂ek + b: wybierz wszystkie kawa艂ki + 鈼: poprzedni konflikt + 鈻: nast臋pny konflikt + 鈻: wybierz poprzedni kawa艂ek + 鈻: wybierz nast臋pny kawa艂ek + z: cofnij ++ +## Schowek
space: zastosuj @@ -293,7 +232,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: przegl膮daj pliki commita-## Status Panel (Status) +## Status
e: edytuj konfiguracj臋 @@ -303,7 +242,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct a: poka偶 wszystkie logi ga艂臋zi-## Sub-commits Panel (Sub-commits) +## Sub-commits
ctrl+o: copy commit SHA to clipboard @@ -315,3 +254,34 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct ctrl+r: reset cherry-picked (copied) commits selection enter: przegl膮daj pliki commita+ +## Submodules + +
+ ctrl+o: copy submodule name to clipboard + enter: enter submodule + d: remove submodule + u: update submodule + n: add new submodule + e: update submodule URL + i: initialize submodule + b: view bulk submodule options ++ +## Tags + +
+ space: prze艂膮cz + d: delete tag + P: push tag + n: create tag + g: wy艣wietl opcje resetu + enter: view commits ++ +## Zwyk艂e + +
+ mouse wheel down: przewi艅 w d贸艂 (fn+up) + mouse wheel up: przewi艅 w g贸r臋 (fn+down) +diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index 7dc0d9f7b..3af2b795b 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -41,66 +41,19 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct [: 涓婁竴涓爣绛 -## 涓昏 闈㈡澘 (鏋勫缓琛ヤ竵涓) +## Reflog 椤甸潰
- esc: 閫鍑洪愯妯″紡 - o: 鎵撳紑鏂囦欢 - 鈻: 閫夋嫨涓婁竴琛 - 鈻: 閫夋嫨涓嬩竴琛 - 鈼: 閫夋嫨涓婁竴涓尯鍧 - 鈻: 閫夋嫨涓嬩竴涓尯鍧 - ctrl+o: 灏嗛変腑鏂囨湰澶嶅埗鍒板壀璐存澘 - space: 娣诲姞/绉婚櫎 琛屽埌琛ヤ竵 - v: 鍒囨崲鎷栧姩閫夋嫨 - V: 鍒囨崲鎷栧姩閫夋嫨 - a: 鍒囨崲閫夋嫨鍖哄潡 + ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 + space: 妫鍑烘彁浜 + g: 鏌ョ湅閲嶇疆閫夐」 + c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 + C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 + ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 + enter: 鏌ョ湅鎻愪氦-## 涓昏 闈㈡澘 (姝e湪鍚堝苟) - -
- esc: 杩斿洖鏂囦欢闈㈡澘 - M: 鎵撳紑澶栭儴鍚堝苟宸ュ叿 (git mergetool) - space: 閫変腑鍖哄潡 - b: 閫変腑鎵鏈夊尯鍧 - 鈼: 閫夋嫨涓婁竴涓啿绐 - 鈻: 閫夋嫨涓嬩竴涓啿绐 - 鈻: 閫夋嫨椤堕儴鍧 - 鈻: 閫夋嫨搴曢儴鍧 - z: 鎾ら攢 -- -## 涓昏 闈㈡澘 (姝e湪鏆傚瓨) - -
- esc: 杩斿洖鏂囦欢闈㈡澘 - space: 鍒囨崲琛屾殏瀛樼姸鎬 - d: 鍙栨秷鍙樻洿 (git reset) - tab: 鍒囨崲鍒板叾浠栭潰鏉 - o: 鎵撳紑鏂囦欢 - 鈻: 閫夋嫨涓婁竴琛 - 鈻: 閫夋嫨涓嬩竴琛 - 鈼: 閫夋嫨涓婁竴涓尯鍧 - 鈻: 閫夋嫨涓嬩竴涓尯鍧 - ctrl+o: 灏嗛変腑鏂囨湰澶嶅埗鍒板壀璐存澘 - e: 缂栬緫鏂囦欢 - v: 鍒囨崲鎷栧姩閫夋嫨 - V: 鍒囨崲鎷栧姩閫夋嫨 - a: 鍒囨崲閫夋嫨鍖哄潡 - c: 鎻愪氦鏇存敼 - w: 鎻愪氦鏇存敼鑰屾棤闇棰勫厛鎻愪氦閽╁瓙 - C: 鎻愪氦鏇存敼锛堜娇鐢ㄧ紪杈戝櫒缂栬緫鎻愪氦淇℃伅锛 -- -## 涓昏 闈㈡澘 (姝e父) - -
- mouse wheel down: 鍚戜笅婊氬姩 (fn+up) - mouse wheel up: 鍚戜笂婊氬姩 (fn+down) -- -## 鍒嗘敮 闈㈡澘 (鍒嗘敮椤甸潰) +## 鍒嗘敮椤甸潰
ctrl+o: 灏嗗垎鏀悕绉板鍒跺埌鍓创鏉 @@ -121,7 +74,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: 鏌ョ湅鎻愪氦-## 鍒嗘敮 闈㈡澘 (瀛愭彁浜) +## 瀛愭彁浜
ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 @@ -136,68 +89,20 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: 鏌ョ湅鎻愪氦鐨勬枃浠-## 鍒嗘敮 闈㈡澘 (鏍囩椤甸潰) +## 瀛愭ā鍧
- space: 妫鍑 - d: 鍒犻櫎鏍囩 - P: 鎺ㄩ佹爣绛 - n: 鍒涘缓鏍囩 - g: 鏌ョ湅閲嶇疆閫夐」 - enter: 鏌ョ湅鎻愪氦 + ctrl+o: 灏嗗瓙妯″潡鍚嶇О澶嶅埗鍒板壀璐存澘 + enter: 杈撳叆瀛愭ā鍧 + d: 鍒犻櫎瀛愭ā鍧 + u: 鏇存柊瀛愭ā鍧 + n: 娣诲姞鏂扮殑瀛愭ā鍧 + e: 鏇存柊瀛愭ā鍧 URL + i: 鍒濆鍖栧瓙妯″潡 + b: 鏌ョ湅鎵归噺瀛愭ā鍧楅夐」-## 鍒嗘敮 闈㈡澘 (杩滅▼鍒嗘敮锛堝湪杩滅▼椤甸潰涓級) - -
- space: 妫鍑 - n: 鏂板垎鏀 - M: 鍚堝苟鍒板綋鍓嶆鍑虹殑鍒嗘敮 - r: 灏嗗凡妫鍑虹殑鍒嗘敮鍙樺熀鍒拌鍒嗘敮 - d: 鍒犻櫎鍒嗘敮 - u: 璁剧疆涓烘鍑哄垎鏀殑涓婃父 - esc: 杩斿洖杩滅▼浠撳簱鍒楄〃 - g: 鏌ョ湅閲嶇疆閫夐」 - enter: 鏌ョ湅鎻愪氦 -- -## 鍒嗘敮 闈㈡澘 (杩滅▼椤甸潰) - -
- f: 鎶撳彇杩滅▼浠撳簱 - n: 娣诲姞鏂扮殑杩滅▼浠撳簱 - d: 鍒犻櫎杩滅▼ - e: 缂栬緫杩滅▼浠撳簱 -- -## 鎻愪氦 闈㈡澘 (Reflog 椤甸潰) - -
- ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 - space: 妫鍑烘彁浜 - y: copy commit attribute - o: 鍦ㄦ祻瑙堝櫒涓墦寮鎻愪氦 - n: 浠庢彁浜ゅ垱寤烘柊鍒嗘敮 - g: 閲嶇疆涓烘鎻愪氦 - c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 - C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 - ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 - enter: 鏌ョ湅鎻愪氦鐨勬枃浠 -- -## 鎻愪氦 闈㈡澘 (Reflog) - -
- ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 - space: 妫鍑烘彁浜 - g: 鏌ョ湅閲嶇疆閫夐」 - c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 - C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 - ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 - enter: 鏌ョ湅鎻愪氦 -- -## 鎻愪氦 闈㈡澘 (鎻愪氦) +## 鎻愪氦
ctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 @@ -229,7 +134,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: 鏌ョ湅鎻愪氦鐨勬枃浠-## 鎻愪氦鏂囦欢 闈㈡澘 (鎻愪氦鏂囦欢) +## 鎻愪氦鏂囦欢
ctrl+o: 灏嗘彁浜ょ殑鏂囦欢鍚嶅鍒跺埌鍓创鏉 @@ -243,20 +148,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct `: 鍒囨崲鏂囦欢鏍戣鍥-## 鏂囦欢 闈㈡澘 (瀛愭ā鍧) - -
- ctrl+o: 灏嗗瓙妯″潡鍚嶇О澶嶅埗鍒板壀璐存澘 - enter: 杈撳叆瀛愭ā鍧 - d: 鍒犻櫎瀛愭ā鍧 - u: 鏇存柊瀛愭ā鍧 - n: 娣诲姞鏂扮殑瀛愭ā鍧 - e: 鏇存柊瀛愭ā鍧 URL - i: 鍒濆鍖栧瓙妯″潡 - b: 鏌ョ湅鎵归噺瀛愭ā鍧楅夐」 -- -## 鏂囦欢 闈㈡澘 (鏂囦欢) +## 鏂囦欢
ctrl+o: 灏嗘枃浠跺悕澶嶅埗鍒板壀璐存澘 @@ -283,7 +175,77 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct f: 鎶撳彇-## 鐘舵 闈㈡澘 (鐘舵) +## 鏋勫缓琛ヤ竵涓 + +
+ esc: 閫鍑洪愯妯″紡 + o: 鎵撳紑鏂囦欢 + 鈻: 閫夋嫨涓婁竴琛 + 鈻: 閫夋嫨涓嬩竴琛 + 鈼: 閫夋嫨涓婁竴涓尯鍧 + 鈻: 閫夋嫨涓嬩竴涓尯鍧 + ctrl+o: 灏嗛変腑鏂囨湰澶嶅埗鍒板壀璐存澘 + space: 娣诲姞/绉婚櫎 琛屽埌琛ヤ竵 + v: 鍒囨崲鎷栧姩閫夋嫨 + V: 鍒囨崲鎷栧姩閫夋嫨 + a: 鍒囨崲閫夋嫨鍖哄潡 ++ +## 鏍囩椤甸潰 + +
+ space: 妫鍑 + d: 鍒犻櫎鏍囩 + P: 鎺ㄩ佹爣绛 + n: 鍒涘缓鏍囩 + g: 鏌ョ湅閲嶇疆閫夐」 + enter: 鏌ョ湅鎻愪氦 ++ +## 姝e湪鍚堝苟 + +
+ esc: 杩斿洖鏂囦欢闈㈡澘 + M: 鎵撳紑澶栭儴鍚堝苟宸ュ叿 (git mergetool) + space: 閫変腑鍖哄潡 + b: 閫変腑鎵鏈夊尯鍧 + 鈼: 閫夋嫨涓婁竴涓啿绐 + 鈻: 閫夋嫨涓嬩竴涓啿绐 + 鈻: 閫夋嫨椤堕儴鍧 + 鈻: 閫夋嫨搴曢儴鍧 + z: 鎾ら攢 ++ +## 姝e湪鏆傚瓨 + +
+ esc: 杩斿洖鏂囦欢闈㈡澘 + space: 鍒囨崲琛屾殏瀛樼姸鎬 + d: 鍙栨秷鍙樻洿 (git reset) + tab: 鍒囨崲鍒板叾浠栭潰鏉 + o: 鎵撳紑鏂囦欢 + 鈻: 閫夋嫨涓婁竴琛 + 鈻: 閫夋嫨涓嬩竴琛 + 鈼: 閫夋嫨涓婁竴涓尯鍧 + 鈻: 閫夋嫨涓嬩竴涓尯鍧 + ctrl+o: 灏嗛変腑鏂囨湰澶嶅埗鍒板壀璐存澘 + e: 缂栬緫鏂囦欢 + v: 鍒囨崲鎷栧姩閫夋嫨 + V: 鍒囨崲鎷栧姩閫夋嫨 + a: 鍒囨崲閫夋嫨鍖哄潡 + c: 鎻愪氦鏇存敼 + w: 鎻愪氦鏇存敼鑰屾棤闇棰勫厛鎻愪氦閽╁瓙 + C: 鎻愪氦鏇存敼锛堜娇鐢ㄧ紪杈戝櫒缂栬緫鎻愪氦淇℃伅锛 ++ +## 姝e父 + +
+ mouse wheel down: 鍚戜笅婊氬姩 (fn+up) + mouse wheel up: 鍚戜笂婊氬姩 (fn+down) ++ +## 鐘舵
e: 缂栬緫閰嶇疆鏂囦欢 @@ -293,13 +255,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct a: 鏄剧ず鎵鏈夊垎鏀殑鏃ュ織-## 鑿滃崟 闈㈡澘 - -
- esc: 鍏抽棴鑿滃崟 -- -## 璐棌 闈㈡澘 (璐棌) +## 璐棌
space: 搴旂敤 @@ -309,8 +265,25 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct enter: 鏌ョ湅鎻愪氦鐨勬枃浠-## 闄勫姞 闈㈡澘 +## 杩滅▼鍒嗘敮
- @: 鎵撳紑鍛戒护鏃ュ織鑿滃崟 + space: 妫鍑 + n: 鏂板垎鏀 + M: 鍚堝苟鍒板綋鍓嶆鍑虹殑鍒嗘敮 + r: 灏嗗凡妫鍑虹殑鍒嗘敮鍙樺熀鍒拌鍒嗘敮 + d: 鍒犻櫎鍒嗘敮 + u: 璁剧疆涓烘鍑哄垎鏀殑涓婃父 + esc: 杩斿洖杩滅▼浠撳簱鍒楄〃 + g: 鏌ョ湅閲嶇疆閫夐」 + enter: 鏌ョ湅鎻愪氦 ++ +## 杩滅▼椤甸潰 + +
+ f: 鎶撳彇杩滅▼浠撳簱 + n: 娣诲姞鏂扮殑杩滅▼浠撳簱 + d: 鍒犻櫎杩滅▼ + e: 缂栬緫杩滅▼浠撳簱diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index d20a0c71a..6c641fa1f 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -131,16 +131,19 @@ func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*b return getHeaders(binding, tr) }) - bindingGroups := maps.MapToSlice(bindingsByHeader, func(header header, hBindings []*types.Binding) headerWithBindings { - uniqBindings := lo.UniqBy(hBindings, func(binding *types.Binding) string { - return binding.Description + gui.GetKeyDisplay(binding.Key) - }) + bindingGroups := maps.MapToSlice( + bindingsByHeader, + func(header header, hBindings []*types.Binding) headerWithBindings { + uniqBindings := lo.UniqBy(hBindings, func(binding *types.Binding) string { + return binding.Description + gui.GetKeyDisplay(binding.Key) + }) - return headerWithBindings{ - header: header, - bindings: uniqBindings, - } - }) + return headerWithBindings{ + header: header, + bindings: uniqBindings, + } + }, + ) slices.SortFunc(bindingGroups, func(a, b headerWithBindings) bool { if a.header.priority != b.header.priority { @@ -169,18 +172,11 @@ func getHeaders(binding *types.Binding, tr *i18n.TranslationSet) []header { } if len(binding.Contexts) == 0 { - translatedView := localisedTitle(tr, binding.ViewName) - title := fmt.Sprintf("%s %s", translatedView, tr.Panel) - - return []header{{priority: 1, title: title}} + return []header{} } return slices.Map(binding.Contexts, func(context string) header { - translatedView := localisedTitle(tr, binding.ViewName) - translatedContextName := localisedTitle(tr, context) - title := fmt.Sprintf("%s %s (%s)", translatedView, tr.Panel, translatedContextName) - - return header{priority: 1, title: title} + return header{priority: 1, title: localisedTitle(tr, context)} }) } @@ -205,7 +201,12 @@ func formatTitle(title string) string { func formatBinding(binding *types.Binding) string { if binding.Alternative != "" { - return fmt.Sprintf(" %s: %s (%s)\n", gui.GetKeyDisplay(binding.Key), binding.Description, binding.Alternative) + return fmt.Sprintf( + " %s: %s (%s)\n", + gui.GetKeyDisplay(binding.Key), + binding.Description, + binding.Alternative, + ) } return fmt.Sprintf(" %s: %s\n", gui.GetKeyDisplay(binding.Key), binding.Description) } diff --git a/pkg/cheatsheet/generate_test.go b/pkg/cheatsheet/generate_test.go index 94b571454..149ed28c7 100644 --- a/pkg/cheatsheet/generate_test.go +++ b/pkg/cheatsheet/generate_test.go @@ -26,43 +26,23 @@ func TestGetBindingSections(t *testing.T) { bindings: []*types.Binding{ { ViewName: "files", + Contexts: []string{"files"}, Description: "stage file", }, }, expected: []*bindingSection{ { - title: "Files Panel", + title: "Files", bindings: []*types.Binding{ { ViewName: "files", + Contexts: []string{"files"}, Description: "stage file", }, }, }, }, }, - { - testName: "one binding with context", - bindings: []*types.Binding{ - { - ViewName: "files", - Description: "stage file", - Contexts: []string{"submodules"}, - }, - }, - expected: []*bindingSection{ - { - title: "Files Panel (Submodules)", - bindings: []*types.Binding{ - { - ViewName: "files", - Description: "stage file", - Contexts: []string{"submodules"}, - }, - }, - }, - }, - }, { testName: "global binding", bindings: []*types.Binding{ @@ -101,23 +81,10 @@ func TestGetBindingSections(t *testing.T) { Description: "drop submodule", Contexts: []string{"submodules"}, }, - { - ViewName: "commits", - Description: "revert commit", - }, }, expected: []*bindingSection{ { - title: "Commits Panel", - bindings: []*types.Binding{ - { - ViewName: "commits", - Description: "revert commit", - }, - }, - }, - { - title: "Files Panel (Files)", + title: "Files", bindings: []*types.Binding{ { ViewName: "files", @@ -132,7 +99,7 @@ func TestGetBindingSections(t *testing.T) { }, }, { - title: "Files Panel (Submodules)", + title: "Submodules", bindings: []*types.Binding{ { ViewName: "files", @@ -148,19 +115,23 @@ func TestGetBindingSections(t *testing.T) { bindings: []*types.Binding{ { ViewName: "files", + Contexts: []string{"files"}, Description: "stage file", }, { ViewName: "files", + Contexts: []string{"files"}, Description: "unstage file", }, { ViewName: "files", + Contexts: []string{"files"}, Description: "scroll", Tag: "navigation", }, { ViewName: "commits", + Contexts: []string{"commits"}, Description: "revert commit", }, }, @@ -170,29 +141,33 @@ func TestGetBindingSections(t *testing.T) { bindings: []*types.Binding{ { ViewName: "files", + Contexts: []string{"files"}, Description: "scroll", Tag: "navigation", }, }, }, { - title: "Commits Panel", + title: "Commits", bindings: []*types.Binding{ { ViewName: "commits", + Contexts: []string{"commits"}, Description: "revert commit", }, }, }, { - title: "Files Panel", + title: "Files", bindings: []*types.Binding{ { ViewName: "files", + Contexts: []string{"files"}, Description: "stage file", }, { ViewName: "files", + Contexts: []string{"files"}, Description: "unstage file", }, }, @@ -204,28 +179,34 @@ func TestGetBindingSections(t *testing.T) { bindings: []*types.Binding{ { ViewName: "files", + Contexts: []string{"files"}, Description: "stage file", }, { ViewName: "files", + Contexts: []string{"files"}, Description: "unstage file", }, { ViewName: "files", + Contexts: []string{"files"}, Description: "scroll", Tag: "navigation", }, { ViewName: "commits", + Contexts: []string{"commits"}, Description: "revert commit", }, { ViewName: "commits", + Contexts: []string{"commits"}, Description: "scroll", Tag: "navigation", }, { ViewName: "commits", + Contexts: []string{"commits"}, Description: "page up", Tag: "navigation", }, @@ -236,34 +217,39 @@ func TestGetBindingSections(t *testing.T) { bindings: []*types.Binding{ { ViewName: "files", + Contexts: []string{"files"}, Description: "scroll", Tag: "navigation", }, { ViewName: "commits", + Contexts: []string{"commits"}, Description: "page up", Tag: "navigation", }, }, }, { - title: "Commits Panel", + title: "Commits", bindings: []*types.Binding{ { ViewName: "commits", + Contexts: []string{"commits"}, Description: "revert commit", }, }, }, { - title: "Files Panel", + title: "Files", bindings: []*types.Binding{ { ViewName: "files", + Contexts: []string{"files"}, Description: "stage file", }, { ViewName: "files", + Contexts: []string{"files"}, Description: "unstage file", }, }, diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index 4f292d3eb..a93486b07 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -41,6 +41,7 @@ func (gui *Gui) commitFilesRenderToMain() error { func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesContextOpts) error { gui.State.Contexts.CommitFiles.SetSelectedLineIdx(0) gui.State.Contexts.CommitFiles.SetRefName(opts.RefName) + gui.State.Contexts.CommitFiles.SetTitleRef(opts.RefDescription) gui.State.Contexts.CommitFiles.SetCanRebase(opts.CanRebase) gui.State.Contexts.CommitFiles.SetParentContext(opts.Context) gui.State.Contexts.CommitFiles.SetWindowName(opts.Context.GetWindowName()) @@ -54,7 +55,8 @@ func (gui *Gui) SwitchToCommitFilesContext(opts controllers.SwitchToCommitFilesC func (gui *Gui) refreshCommitFilesContext() error { currentSideContext := gui.currentSideContext() - if currentSideContext.GetKey() == context.COMMIT_FILES_CONTEXT_KEY || currentSideContext.GetKey() == context.LOCAL_COMMITS_CONTEXT_KEY { + if currentSideContext.GetKey() == context.COMMIT_FILES_CONTEXT_KEY || + currentSideContext.GetKey() == context.LOCAL_COMMITS_CONTEXT_KEY { if err := gui.handleRefreshPatchBuildingPanel(-1); err != nil { return err } diff --git a/pkg/gui/context.go b/pkg/gui/context.go index c02411640..c63defba4 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -151,8 +151,7 @@ func (gui *Gui) deactivateContext(c types.Context) error { if view != nil && (c.GetKind() == types.TEMPORARY_POPUP || c.GetKind() == types.PERSISTENT_POPUP || - c.GetKey() == context.COMMIT_FILES_CONTEXT_KEY || - c.GetKey() == context.SUB_COMMITS_CONTEXT_KEY) { + c.IsTransient()) { view.Visible = false } @@ -393,11 +392,7 @@ func (gui *Gui) onViewFocusLost(oldView *gocui.View, newView *gocui.View) error _ = oldView.SetOriginX(0) if !lo.Contains([]*gocui.View{gui.Views.Main, gui.Views.Secondary, gui.Views.Search}, newView) { - transientContexts := slices.Filter(gui.State.Contexts.Flatten(), func(context types.Context) bool { - return context.IsTransient() - }) - - for _, context := range transientContexts { + for _, context := range gui.TransientContexts() { if oldView.Name() == context.GetViewName() { if err := gui.deactivateContext(context); err != nil { return err @@ -409,6 +404,12 @@ func (gui *Gui) onViewFocusLost(oldView *gocui.View, newView *gocui.View) error return nil } +func (gui *Gui) TransientContexts() []types.Context { + return slices.Filter(gui.State.Contexts.Flatten(), func(context types.Context) bool { + return context.IsTransient() + }) +} + // changeContext is a helper function for when we want to change a 'main' context // which currently just means a context that affects both the main and secondary views // other views can have their context changed directly but this function helps diff --git a/pkg/gui/context/branches_context.go b/pkg/gui/context/branches_context.go index e5de639d9..302f0c1d9 100644 --- a/pkg/gui/context/branches_context.go +++ b/pkg/gui/context/branches_context.go @@ -65,3 +65,13 @@ func (self *BranchesContext) GetSelectedRefName() string { return item.RefName() } + +func (self *BranchesContext) GetSelectedDescription() string { + item := self.GetSelected() + + if item == nil { + return "" + } + + return item.Description() +} diff --git a/pkg/gui/context/commit_files_context.go b/pkg/gui/context/commit_files_context.go index 5ad7144dc..c95486cbf 100644 --- a/pkg/gui/context/commit_files_context.go +++ b/pkg/gui/context/commit_files_context.go @@ -1,18 +1,16 @@ package context import ( - "fmt" - "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/filetree" "github.com/jesseduffield/lazygit/pkg/gui/types" - "github.com/jesseduffield/lazygit/pkg/utils" ) type CommitFilesContext struct { *filetree.CommitFileTreeViewModel *ListContextTrait + *DynamicTitleBuilder } var _ types.IListContext = (*CommitFilesContext)(nil) @@ -32,6 +30,7 @@ func NewCommitFilesContext( return &CommitFilesContext{ CommitFileTreeViewModel: viewModel, + DynamicTitleBuilder: NewDynamicTitleBuilder(c.Tr.CommitFilesDynamicTitle), ListContextTrait: &ListContextTrait{ Context: NewSimpleContext( NewBaseContext(NewBaseContextOpts{ @@ -63,7 +62,3 @@ func (self *CommitFilesContext) GetSelectedItemId() string { return item.ID() } - -func (self *CommitFilesContext) Title() string { - return fmt.Sprintf(self.c.Tr.CommitFilesDynamicTitle, utils.TruncateWithEllipsis(self.GetRefName(), 50)) -} diff --git a/pkg/gui/context/context.go b/pkg/gui/context/context.go index add336cfd..fb5a4bd64 100644 --- a/pkg/gui/context/context.go +++ b/pkg/gui/context/context.go @@ -152,11 +152,8 @@ func (tree ContextTree) InitialViewTabContextMap() map[string][]TabContext { Contexts: []types.Context{tree.Branches}, }, { - Tab: "Remotes", - Contexts: []types.Context{ - tree.Remotes, - tree.RemoteBranches, - }, + Tab: "Remotes", + Contexts: []types.Context{tree.Remotes}, }, { Tab: "Tags", @@ -169,10 +166,8 @@ func (tree ContextTree) InitialViewTabContextMap() map[string][]TabContext { Contexts: []types.Context{tree.LocalCommits}, }, { - Tab: "Reflog", - Contexts: []types.Context{ - tree.ReflogCommits, - }, + Tab: "Reflog", + Contexts: []types.Context{tree.ReflogCommits}, }, }, "files": { @@ -181,10 +176,8 @@ func (tree ContextTree) InitialViewTabContextMap() map[string][]TabContext { Contexts: []types.Context{tree.Files}, }, { - Tab: "Submodules", - Contexts: []types.Context{ - tree.Submodules, - }, + Tab: "Submodules", + Contexts: []types.Context{tree.Submodules}, }, }, } diff --git a/pkg/gui/context/dynamic_title_builder.go b/pkg/gui/context/dynamic_title_builder.go new file mode 100644 index 000000000..ee4facad2 --- /dev/null +++ b/pkg/gui/context/dynamic_title_builder.go @@ -0,0 +1,23 @@ +package context + +import "fmt" + +type DynamicTitleBuilder struct { + formatStr string // e.g. 'remote branches for %s' + + titleRef string // e.g. 'origin' +} + +func NewDynamicTitleBuilder(formatStr string) *DynamicTitleBuilder { + return &DynamicTitleBuilder{ + formatStr: formatStr, + } +} + +func (self *DynamicTitleBuilder) SetTitleRef(titleRef string) { + self.titleRef = titleRef +} + +func (self *DynamicTitleBuilder) Title() string { + return fmt.Sprintf(self.formatStr, self.titleRef) +} diff --git a/pkg/gui/context/local_commits_context.go b/pkg/gui/context/local_commits_context.go index cc7a2a0d2..0d7cc2f54 100644 --- a/pkg/gui/context/local_commits_context.go +++ b/pkg/gui/context/local_commits_context.go @@ -93,6 +93,16 @@ func (self *LocalCommitsContext) GetSelectedRefName() string { return item.RefName() } +func (self *LocalCommitsViewModel) GetSelectedDescription() string { + item := self.GetSelected() + + if item == nil { + return "" + } + + return item.Description() +} + func (self *LocalCommitsViewModel) SetLimitCommits(value bool) { self.limitCommits = value } diff --git a/pkg/gui/context/reflog_commits_context.go b/pkg/gui/context/reflog_commits_context.go index a1ad6cfda..0274a921e 100644 --- a/pkg/gui/context/reflog_commits_context.go +++ b/pkg/gui/context/reflog_commits_context.go @@ -74,3 +74,13 @@ func (self *ReflogCommitsContext) GetSelectedRefName() string { func (self *ReflogCommitsContext) GetCommits() []*models.Commit { return self.getModel() } + +func (self *ReflogCommitsContext) GetSelectedDescription() string { + item := self.GetSelected() + + if item == nil { + return "" + } + + return item.Description() +} diff --git a/pkg/gui/context/remote_branches_context.go b/pkg/gui/context/remote_branches_context.go index 3cdd43a69..52217ef11 100644 --- a/pkg/gui/context/remote_branches_context.go +++ b/pkg/gui/context/remote_branches_context.go @@ -9,6 +9,7 @@ import ( type RemoteBranchesContext struct { *BasicViewModel[*models.RemoteBranch] *ListContextTrait + *DynamicTitleBuilder } var _ types.IListContext = (*RemoteBranchesContext)(nil) @@ -27,14 +28,16 @@ func NewRemoteBranchesContext( viewModel := NewBasicViewModel(getModel) return &RemoteBranchesContext{ - BasicViewModel: viewModel, + BasicViewModel: viewModel, + DynamicTitleBuilder: NewDynamicTitleBuilder(c.Tr.RemoteBranchesDynamicTitle), ListContextTrait: &ListContextTrait{ Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ - ViewName: "branches", + ViewName: "remoteBranches", WindowName: "branches", Key: REMOTE_BRANCHES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, Focusable: true, + Transient: true, }), ContextCallbackOpts{ OnFocus: onFocus, OnFocusLost: onFocusLost, @@ -65,3 +68,13 @@ func (self *RemoteBranchesContext) GetSelectedRefName() string { return item.RefName() } + +func (self *RemoteBranchesContext) GetSelectedDescription() string { + item := self.GetSelected() + + if item == nil { + return "" + } + + return item.Description() +} diff --git a/pkg/gui/context/stash_context.go b/pkg/gui/context/stash_context.go index e2af64d10..ef443846f 100644 --- a/pkg/gui/context/stash_context.go +++ b/pkg/gui/context/stash_context.go @@ -70,3 +70,13 @@ func (self *StashContext) GetSelectedRefName() string { return item.RefName() } + +func (self *StashContext) GetSelectedDescription() string { + item := self.GetSelected() + + if item == nil { + return "" + } + + return item.Description() +} diff --git a/pkg/gui/context/sub_commits_context.go b/pkg/gui/context/sub_commits_context.go index 6c1d5910f..ffc053267 100644 --- a/pkg/gui/context/sub_commits_context.go +++ b/pkg/gui/context/sub_commits_context.go @@ -12,6 +12,7 @@ import ( type SubCommitsContext struct { *SubCommitsViewModel *ViewportListContextTrait + *DynamicTitleBuilder } var _ types.IListContext = (*SubCommitsContext)(nil) @@ -34,6 +35,7 @@ func NewSubCommitsContext( return &SubCommitsContext{ SubCommitsViewModel: viewModel, + DynamicTitleBuilder: NewDynamicTitleBuilder(c.Tr.SubCommitsDynamicTitle), ViewportListContextTrait: &ViewportListContextTrait{ ListContextTrait: &ListContextTrait{ Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ @@ -99,3 +101,13 @@ func (self *SubCommitsContext) GetCommits() []*models.Commit { func (self *SubCommitsContext) Title() string { return fmt.Sprintf(self.c.Tr.SubCommitsDynamicTitle, utils.TruncateWithEllipsis(self.refName, 50)) } + +func (self *SubCommitsContext) GetSelectedDescription() string { + item := self.GetSelected() + + if item == nil { + return "" + } + + return item.Description() +} diff --git a/pkg/gui/context/tags_context.go b/pkg/gui/context/tags_context.go index fd411ec9a..d6f8d78ac 100644 --- a/pkg/gui/context/tags_context.go +++ b/pkg/gui/context/tags_context.go @@ -65,3 +65,13 @@ func (self *TagsContext) GetSelectedRefName() string { return item.RefName() } + +func (self *TagsContext) GetSelectedDescription() string { + item := self.GetSelected() + + if item == nil { + return "" + } + + return item.Description() +} diff --git a/pkg/gui/controllers/local_commits_controller.go b/pkg/gui/controllers/local_commits_controller.go index 41433068d..1df223365 100644 --- a/pkg/gui/controllers/local_commits_controller.go +++ b/pkg/gui/controllers/local_commits_controller.go @@ -497,9 +497,7 @@ func (self *LocalCommitsController) createFixupCommit(commit *models.Commit) err func (self *LocalCommitsController) squashAllAboveFixupCommits(commit *models.Commit) error { prompt := utils.ResolvePlaceholderString( self.c.Tr.SureSquashAboveCommits, - map[string]string{ - "commit": commit.Sha, - }, + map[string]string{"commit": commit.Sha}, ) return self.c.Ask(types.AskOpts{ @@ -561,7 +559,9 @@ func (self *LocalCommitsController) handleOpenLogMenu() error { } return self.c.WithWaitingStatus(self.c.Tr.LcLoadingCommits, func() error { - return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}) + return self.c.Refresh( + types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}, + ) }) }, }, @@ -602,7 +602,12 @@ func (self *LocalCommitsController) handleOpenLogMenu() error { return func() error { self.c.UserConfig.Git.Log.Order = value return self.c.WithWaitingStatus(self.c.Tr.LcLoadingCommits, func() error { - return self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.COMMITS}}) + return self.c.Refresh( + types.RefreshOptions{ + Mode: types.SYNC, + Scope: []types.RefreshableView{types.COMMITS}, + }, + ) }) } } diff --git a/pkg/gui/controllers/remotes_controller.go b/pkg/gui/controllers/remotes_controller.go index fd4b34297..208f36af7 100644 --- a/pkg/gui/controllers/remotes_controller.go +++ b/pkg/gui/controllers/remotes_controller.go @@ -73,6 +73,11 @@ func (self *RemotesController) enter(remote *models.Remote) error { newSelectedLine = -1 } self.contexts.RemoteBranches.SetSelectedLineIdx(newSelectedLine) + self.contexts.RemoteBranches.SetTitleRef(remote.Name) + + if err := self.c.PostRefreshUpdate(self.contexts.RemoteBranches); err != nil { + return err + } return self.c.PushContext(self.contexts.RemoteBranches) } diff --git a/pkg/gui/controllers/switch_to_diff_files_controller.go b/pkg/gui/controllers/switch_to_diff_files_controller.go index 9a3111cae..c41dbdd37 100644 --- a/pkg/gui/controllers/switch_to_diff_files_controller.go +++ b/pkg/gui/controllers/switch_to_diff_files_controller.go @@ -12,6 +12,7 @@ type CanSwitchToDiffFiles interface { types.Context CanRebase() bool GetSelectedRefName() string + GetSelectedDescription() string } type SwitchToDiffFilesController struct { @@ -63,9 +64,10 @@ func (self *SwitchToDiffFilesController) checkSelected(callback func(string) err func (self *SwitchToDiffFilesController) enter(refName string) error { return self.viewFiles(SwitchToCommitFilesContextOpts{ - RefName: refName, - CanRebase: self.context.CanRebase(), - Context: self.context, + RefName: refName, + RefDescription: self.context.GetSelectedDescription(), + CanRebase: self.context.CanRebase(), + Context: self.context, }) } diff --git a/pkg/gui/controllers/switch_to_sub_commits_controller.go b/pkg/gui/controllers/switch_to_sub_commits_controller.go index 82b52509b..d59f4fdbf 100644 --- a/pkg/gui/controllers/switch_to_sub_commits_controller.go +++ b/pkg/gui/controllers/switch_to_sub_commits_controller.go @@ -11,6 +11,7 @@ var _ types.IController = &SwitchToSubCommitsController{} type CanSwitchToSubCommits interface { types.Context GetSelectedRefName() string + GetSelectedDescription() string } type SwitchToSubCommitsController struct { @@ -74,6 +75,7 @@ func (self *SwitchToSubCommitsController) viewCommits() error { self.contexts.SubCommits.SetSelectedLineIdx(0) self.contexts.SubCommits.SetParentContext(self.context) self.contexts.SubCommits.SetWindowName(self.context.GetWindowName()) + self.contexts.SubCommits.SetTitleRef(self.context.GetSelectedDescription()) self.contexts.SubCommits.SetRefName(refName) err = self.c.PostRefreshUpdate(self.contexts.SubCommits) diff --git a/pkg/gui/controllers/types.go b/pkg/gui/controllers/types.go index 9783ca3b7..e9af41089 100644 --- a/pkg/gui/controllers/types.go +++ b/pkg/gui/controllers/types.go @@ -6,7 +6,17 @@ import ( // all fields mandatory (except `CanRebase` because it's boolean) type SwitchToCommitFilesContextOpts struct { - RefName string + // this is something like a commit sha or branch name + RefName string + + // this will be displayed in the title of the view so we know whose diff files + // we're viewing + RefDescription string + + // from the local commits view we're allowed to do rebase stuff with any patch + // we generate from the diff files context, but we don't have that same ability + // with say the sub commits context or the reflog context. CanRebase bool - Context types.Context + + Context types.Context } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 334133487..b4e0f8de4 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -240,26 +240,27 @@ type panelStates struct { } type Views struct { - Status *gocui.View - Files *gocui.View - Branches *gocui.View - Commits *gocui.View - Stash *gocui.View - Main *gocui.View - Secondary *gocui.View - Options *gocui.View - Confirmation *gocui.View - Menu *gocui.View - CommitMessage *gocui.View - CommitFiles *gocui.View - SubCommits *gocui.View - Information *gocui.View - AppStatus *gocui.View - Search *gocui.View - SearchPrefix *gocui.View - Limit *gocui.View - Suggestions *gocui.View - Extras *gocui.View + Status *gocui.View + Files *gocui.View + Branches *gocui.View + RemoteBranches *gocui.View + Commits *gocui.View + Stash *gocui.View + Main *gocui.View + Secondary *gocui.View + Options *gocui.View + Confirmation *gocui.View + Menu *gocui.View + CommitMessage *gocui.View + CommitFiles *gocui.View + SubCommits *gocui.View + Information *gocui.View + AppStatus *gocui.View + Search *gocui.View + SearchPrefix *gocui.View + Limit *gocui.View + Suggestions *gocui.View + Extras *gocui.View } type searchingState struct { @@ -406,19 +407,20 @@ func (gui *Gui) syncViewContexts() { func initialViewContextMapping(contextTree *context.ContextTree) map[string]types.Context { return map[string]types.Context{ - "status": contextTree.Status, - "files": contextTree.Files, - "branches": contextTree.Branches, - "commits": contextTree.LocalCommits, - "commitFiles": contextTree.CommitFiles, - "subCommits": contextTree.SubCommits, - "stash": contextTree.Stash, - "menu": contextTree.Menu, - "confirmation": contextTree.Confirmation, - "commitMessage": contextTree.CommitMessage, - "main": contextTree.Normal, - "secondary": contextTree.Normal, - "extras": contextTree.CommandLog, + "status": contextTree.Status, + "files": contextTree.Files, + "branches": contextTree.Branches, + "remoteBranches": contextTree.RemoteBranches, + "commits": contextTree.LocalCommits, + "commitFiles": contextTree.CommitFiles, + "subCommits": contextTree.SubCommits, + "stash": contextTree.Stash, + "menu": contextTree.Menu, + "confirmation": contextTree.Confirmation, + "commitMessage": contextTree.CommitMessage, + "main": contextTree.Normal, + "secondary": contextTree.Normal, + "extras": contextTree.CommandLog, } } @@ -600,6 +602,7 @@ func (gui *Gui) createAllViews() error { {viewPtr: &gui.Views.Status, name: "status"}, {viewPtr: &gui.Views.Files, name: "files"}, {viewPtr: &gui.Views.Branches, name: "branches"}, + {viewPtr: &gui.Views.RemoteBranches, name: "remoteBranches"}, {viewPtr: &gui.Views.Commits, name: "commits"}, {viewPtr: &gui.Views.Stash, name: "stash"}, {viewPtr: &gui.Views.CommitFiles, name: "commitFiles"}, @@ -649,6 +652,8 @@ func (gui *Gui) createAllViews() error { gui.Views.Branches.Title = gui.c.Tr.BranchesTitle gui.Views.Branches.FgColor = theme.GocuiDefaultTextColor + gui.Views.RemoteBranches.FgColor = theme.GocuiDefaultTextColor + gui.Views.Files.Highlight = true gui.Views.Files.Title = gui.c.Tr.FilesTitle gui.Views.Files.FgColor = theme.GocuiDefaultTextColor diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 122fbfd04..e19f42935 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -999,7 +999,7 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi mouseKeybindings = append(mouseKeybindings, c.GetMouseKeybindings(opts)...) } - for _, viewName := range []string{"status", "branches", "files", "commits", "commitFiles", "subCommits", "stash", "menu"} { + for _, viewName := range []string{"status", "branches", "remoteBranches", "files", "commits", "commitFiles", "subCommits", "stash", "menu"} { bindings = append(bindings, []*types.Binding{ {ViewName: viewName, Key: opts.GetKey(opts.Config.Universal.PrevBlock), Modifier: gocui.ModNone, Handler: self.previousSideWindow}, {ViewName: viewName, Key: opts.GetKey(opts.Config.Universal.NextBlock), Modifier: gocui.ModNone, Handler: self.nextSideWindow}, diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index c77c9030d..2fb165ff4 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -2,7 +2,6 @@ package gui import ( "github.com/jesseduffield/gocui" - "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/theme" ) @@ -96,6 +95,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { {viewName: "status", windowName: "status", frame: true}, {viewName: "files", windowName: "files", frame: true}, {viewName: "branches", windowName: "branches", frame: true}, + {viewName: "remoteBranches", windowName: "branches", frame: true}, {viewName: "commitFiles", windowName: gui.State.Contexts.CommitFiles.GetWindowName(), frame: true}, {viewName: "subCommits", windowName: gui.State.Contexts.SubCommits.GetWindowName(), frame: true}, {viewName: "commits", windowName: "commits", frame: true}, @@ -115,7 +115,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { } } - for _, context := range []types.Context{gui.State.Contexts.SubCommits, gui.State.Contexts.CommitFiles} { + for _, context := range gui.TransientContexts() { view, err := gui.g.View(context.GetViewName()) if err != nil && err.Error() != UNKNOWN_VIEW_ERROR_MSG { return err @@ -211,6 +211,7 @@ func (gui *Gui) onInitialViewsCreation() error { gui.Views.Status, gui.Views.Files, gui.Views.Branches, + gui.Views.RemoteBranches, gui.Views.Commits, gui.Views.Stash, gui.Views.SubCommits, diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index b2f267a6a..e8a65d6da 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -71,7 +71,7 @@ func (gui *Gui) remotesListContext() *context.RemotesContext { func (gui *Gui) remoteBranchesListContext() *context.RemoteBranchesContext { return context.NewRemoteBranchesContext( func() []*models.RemoteBranch { return gui.State.Model.RemoteBranches }, - gui.Views.Branches, + gui.Views.RemoteBranches, func(startIdx int, length int) [][]string { return presentation.GetRemoteBranchListDisplayStrings(gui.State.Model.RemoteBranches, gui.State.Modes.Diffing.Ref) }, diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go index f56cb55d7..244c0c050 100644 --- a/pkg/gui/refresh.go +++ b/pkg/gui/refresh.go @@ -187,6 +187,7 @@ func (gui *Gui) refreshCommits() { commit := gui.getSelectedLocalCommit() if commit != nil { gui.State.Contexts.CommitFiles.SetRefName(commit.RefName()) + gui.State.Contexts.CommitFiles.SetTitleRef(commit.RefName()) _ = gui.refreshCommitFilesContext() } } @@ -490,6 +491,7 @@ func (gui *Gui) refreshRemotes() error { for _, remote := range remotes { if remote.Name == prevSelectedRemote.Name { gui.State.Model.RemoteBranches = remote.Branches + break } } } diff --git a/pkg/i18n/chinese.go b/pkg/i18n/chinese.go index 400a12da6..3b33f3841 100644 --- a/pkg/i18n/chinese.go +++ b/pkg/i18n/chinese.go @@ -196,7 +196,7 @@ func chineseTranslationSet() TranslationSet { TagsTitle: "鏍囩椤甸潰", MenuTitle: "鑿滃崟", RemotesTitle: "杩滅▼椤甸潰", - RemoteBranchesTitle: "杩滅▼鍒嗘敮锛堝湪杩滅▼椤甸潰涓級", + RemoteBranchesTitle: "杩滅▼鍒嗘敮", PatchBuildingTitle: "鏋勫缓琛ヤ竵涓", InformationTitle: "淇℃伅", SecondaryTitle: "娆¤", diff --git a/pkg/i18n/dutch.go b/pkg/i18n/dutch.go index c77321ae2..394b4abc4 100644 --- a/pkg/i18n/dutch.go +++ b/pkg/i18n/dutch.go @@ -156,16 +156,16 @@ func dutchTranslationSet() TranslationSet { MergeOptionsTitle: "Merge Opties", RebaseOptionsTitle: "Rebase Opties", CommitMessageTitle: "Commit Bericht", - LocalBranchesTitle: "Branches Tabblad", + LocalBranchesTitle: "Branches", SearchTitle: "Zoek", - TagsTitle: "Tags Tabblad", + TagsTitle: "Tags", MenuTitle: "Menu", - RemotesTitle: "Remotes Tabblad", - RemoteBranchesTitle: "Remote Branches (in Remotes tabblad)", + RemotesTitle: "Remotes", + RemoteBranchesTitle: "Remote Branches", PatchBuildingTitle: "Patch Bouwen", InformationTitle: "Informatie", SecondaryTitle: "Secondary", - ReflogCommitsTitle: "Reflog Tabblad", + ReflogCommitsTitle: "Reflog", GlobalTitle: "Globale Sneltoetsen", ConflictsResolved: "alle merge conflicten zijn opgelost. Wilt je verder gaan?", RebasingTitle: "Rebasen", diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index a5cadb47d..678b8cd18 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -232,6 +232,7 @@ type TranslationSet struct { CommitFiles string SubCommitsDynamicTitle string CommitFilesDynamicTitle string + RemoteBranchesDynamicTitle string LcViewItemFiles string CommitFilesTitle string LcCheckoutCommitFile string @@ -611,9 +612,9 @@ func EnglishTranslationSet() TranslationSet { UnstagedChanges: `Unstaged Changes`, StagedChanges: `Staged Changes`, MainTitle: "Main", - StagingTitle: "Staging", - MergingTitle: "Merging", - NormalTitle: "Normal", + StagingTitle: "Main Panel (Staging)", + MergingTitle: "Main Panel (Merging)", + NormalTitle: "Main Panel (Normal)", CommitMessage: "Commit message", CredentialsUsername: "Username", CredentialsPassword: "Password", @@ -762,16 +763,16 @@ func EnglishTranslationSet() TranslationSet { MergeOptionsTitle: "Merge Options", RebaseOptionsTitle: "Rebase Options", CommitMessageTitle: "Commit Message", - LocalBranchesTitle: "Branches Tab", + LocalBranchesTitle: "Branches", SearchTitle: "Search", - TagsTitle: "Tags Tab", + TagsTitle: "Tags", MenuTitle: "Menu", - RemotesTitle: "Remotes Tab", - RemoteBranchesTitle: "Remote Branches (in Remotes tab)", - PatchBuildingTitle: "Patch Building", + RemotesTitle: "Remotes", + RemoteBranchesTitle: "Remote Branches", + PatchBuildingTitle: "Main Panel (Patch Building)", InformationTitle: "Information", SecondaryTitle: "Secondary", - ReflogCommitsTitle: "Reflog Tab", + ReflogCommitsTitle: "Reflog", GlobalTitle: "Global Keybindings", ConflictsResolved: "all merge conflicts resolved. Continue?", RebasingTitle: "Rebasing", @@ -821,8 +822,9 @@ func EnglishTranslationSet() TranslationSet { CheckingOutStatus: "checking out", CommittingStatus: "committing", CommitFiles: "Commit files", - SubCommitsDynamicTitle: "Commits for %s", - CommitFilesDynamicTitle: "Diff files for %s", + SubCommitsDynamicTitle: "Commits (%s)", + CommitFilesDynamicTitle: "Diff files (%s)", + RemoteBranchesDynamicTitle: "Remote branches (%s)", LcViewItemFiles: "view selected item's files", CommitFilesTitle: "Commit Files", LcCheckoutCommitFile: "checkout file", @@ -1010,7 +1012,7 @@ func EnglishTranslationSet() TranslationSet { NavigationTitle: "List Panel Navigation", SuggestionsCheatsheetTitle: "Suggestions", SuggestionsTitle: "Suggestions (press %s to focus)", - ExtrasTitle: "Extras", + ExtrasTitle: "Command Log", PushingTagStatus: "pushing tag", PullRequestURLCopiedToClipboard: "Pull request URL copied to clipboard", CommitDiffCopiedToClipboard: "Commit diff copied to clipboard", diff --git a/test/integration/reflogCommitFiles/recording.json b/test/integration/reflogCommitFiles/recording.json index bf91fbcf3..8339b7ea7 100644 --- a/test/integration/reflogCommitFiles/recording.json +++ b/test/integration/reflogCommitFiles/recording.json @@ -1 +1,125 @@ -{"KeyEvents":[{"Timestamp":608,"Mod":0,"Key":259,"Ch":0},{"Timestamp":768,"Mod":0,"Key":259,"Ch":0},{"Timestamp":1376,"Mod":0,"Key":256,"Ch":93},{"Timestamp":1817,"Mod":0,"Key":258,"Ch":0},{"Timestamp":2560,"Mod":0,"Key":13,"Ch":13},{"Timestamp":3271,"Mod":0,"Key":256,"Ch":32},{"Timestamp":3936,"Mod":2,"Key":16,"Ch":16},{"Timestamp":4680,"Mod":0,"Key":258,"Ch":0},{"Timestamp":4945,"Mod":0,"Key":258,"Ch":0},{"Timestamp":5216,"Mod":0,"Key":13,"Ch":13},{"Timestamp":5712,"Mod":0,"Key":260,"Ch":0},{"Timestamp":5952,"Mod":0,"Key":260,"Ch":0},{"Timestamp":6191,"Mod":0,"Key":256,"Ch":99},{"Timestamp":6456,"Mod":0,"Key":256,"Ch":97},{"Timestamp":6536,"Mod":0,"Key":256,"Ch":115},{"Timestamp":6647,"Mod":0,"Key":256,"Ch":100},{"Timestamp":6968,"Mod":0,"Key":13,"Ch":13},{"Timestamp":7376,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":272,"Height":74}]} \ No newline at end of file +{ + "KeyEvents": [ + { + "Timestamp": 608, + "Mod": 0, + "Key": 259, + "Ch": 0 + }, + { + "Timestamp": 768, + "Mod": 0, + "Key": 259, + "Ch": 0 + }, + { + "Timestamp": 1376, + "Mod": 0, + "Key": 256, + "Ch": 93 + }, + { + "Timestamp": 1817, + "Mod": 0, + "Key": 258, + "Ch": 0 + }, + { + "Timestamp": 2560, + "Mod": 0, + "Key": 13, + "Ch": 13 + }, + { + "Timestamp": 2860, + "Mod": 0, + "Key": 13, + "Ch": 13 + }, + { + "Timestamp": 3271, + "Mod": 0, + "Key": 256, + "Ch": 32 + }, + { + "Timestamp": 3936, + "Mod": 2, + "Key": 16, + "Ch": 16 + }, + { + "Timestamp": 4680, + "Mod": 0, + "Key": 258, + "Ch": 0 + }, + { + "Timestamp": 4945, + "Mod": 0, + "Key": 258, + "Ch": 0 + }, + { + "Timestamp": 5216, + "Mod": 0, + "Key": 13, + "Ch": 13 + }, + { + "Timestamp": 5712, + "Mod": 0, + "Key": 260, + "Ch": 0 + }, + { + "Timestamp": 5952, + "Mod": 0, + "Key": 260, + "Ch": 0 + }, + { + "Timestamp": 6191, + "Mod": 0, + "Key": 256, + "Ch": 99 + }, + { + "Timestamp": 6456, + "Mod": 0, + "Key": 256, + "Ch": 97 + }, + { + "Timestamp": 6536, + "Mod": 0, + "Key": 256, + "Ch": 115 + }, + { + "Timestamp": 6647, + "Mod": 0, + "Key": 256, + "Ch": 100 + }, + { + "Timestamp": 6968, + "Mod": 0, + "Key": 13, + "Ch": 13 + }, + { + "Timestamp": 7376, + "Mod": 0, + "Key": 256, + "Ch": 113 + } + ], + "ResizeEvents": [ + { + "Timestamp": 0, + "Width": 272, + "Height": 74 + } + ] +} From fe87114074ae72e3c548f5b05fb50a919eda0f94 Mon Sep 17 00:00:00 2001 From: Jesse Duffield
ctrl+o: copy commit SHA to clipboard space: checkout commit + y: copy commit attribute + o: open commit in browser + n: create new branch off of commit g: view reset options c: copy commit (cherry-pick) C: copy commit range (cherry-pick) @@ -254,8 +257,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directctrl+o: copy commit SHA to clipboard space: checkout commit + y: copy commit attribute + o: open commit in browser + n: create new branch off of commit g: view reset options - n: new branch c: copy commit (cherry-pick) C: copy commit range (cherry-pick) ctrl+r: reset cherry-picked (copied) commits selection diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index b6220463f..bb081e709 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -129,7 +129,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct y: copy commit attribute o: open commit in browser n: cre毛er nieuwe branch van commit - g: reset naar deze commit + g: bekijk reset opties c: kopieer commit (cherry-pick) C: kopieer commit reeks (cherry-pick) enter: bekijk gecommite bestanden @@ -177,6 +177,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directctrl+o: kopieer commit SHA naar klembord space: checkout commit + y: copy commit attribute + o: open commit in browser + n: cre毛er nieuwe branch van commit g: bekijk reset opties c: kopieer commit (cherry-pick) C: kopieer commit reeks (cherry-pick) @@ -254,8 +257,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directctrl+o: kopieer commit SHA naar klembord space: checkout commit + y: copy commit attribute + o: open commit in browser + n: cre毛er nieuwe branch van commit g: bekijk reset opties - n: nieuwe branch c: kopieer commit (cherry-pick) C: kopieer commit reeks (cherry-pick) ctrl+r: reset cherry-picked (gekopieerde) commits selectie diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index aa1b9295b..c4fe08d56 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -88,7 +88,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct y: copy commit attribute o: open commit in browser n: create new branch off of commit - g: zresetuj do tego commita + g: wy艣wietl opcje resetu c: kopiuj commit (przebieranie) C: kopiuj zakres commit贸w (przebieranie) enter: przegl膮daj pliki commita @@ -178,6 +178,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directctrl+o: copy commit SHA to clipboard space: checkout commit + y: copy commit attribute + o: open commit in browser + n: create new branch off of commit g: wy艣wietl opcje resetu c: kopiuj commit (przebieranie) C: kopiuj zakres commit贸w (przebieranie) @@ -247,8 +250,10 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directctrl+o: copy commit SHA to clipboard space: checkout commit + y: copy commit attribute + o: open commit in browser + n: create new branch off of commit g: wy艣wietl opcje resetu - n: nowa ga艂膮藕 c: kopiuj commit (przebieranie) C: kopiuj zakres commit贸w (przebieranie) ctrl+r: reset cherry-picked (copied) commits selection diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md index 3af2b795b..e4b23404a 100644 --- a/docs/keybindings/Keybindings_zh.md +++ b/docs/keybindings/Keybindings_zh.md @@ -46,6 +46,9 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n directctrl+o: 灏嗘彁浜ょ殑 SHA 澶嶅埗鍒板壀璐存澘 space: 妫鍑烘彁浜 + y: copy commit attribute + o: 鍦ㄦ祻瑙堝櫒涓墦寮鎻愪氦 + n: 浠庢彁浜ゅ垱寤烘柊鍒嗘敮 g: 鏌ョ湅閲嶇疆閫夐」 c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 @@ -82,7 +85,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct y: copy commit attribute o: 鍦ㄦ祻瑙堝櫒涓墦寮鎻愪氦 n: 浠庢彁浜ゅ垱寤烘柊鍒嗘敮 - g: 閲嶇疆涓烘鎻愪氦 + g: 鏌ョ湅閲嶇疆閫夐」 c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 ctrl+r: 閲嶇疆宸叉嫞閫夛紙澶嶅埗锛夌殑鎻愪氦 @@ -128,7 +131,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct y: copy commit attribute o: 鍦ㄦ祻瑙堝櫒涓墦寮鎻愪氦 n: 浠庢彁浜ゅ垱寤烘柊鍒嗘敮 - g: 閲嶇疆涓烘鎻愪氦 + g: 鏌ョ湅閲嶇疆閫夐」 c: 澶嶅埗鎻愪氦锛堟嫞閫夛級 C: 澶嶅埗鎻愪氦鑼冨洿锛堟嫞閫夛級 enter: 鏌ョ湅鎻愪氦鐨勬枃浠 diff --git a/pkg/gui/controllers/basic_commits_controller.go b/pkg/gui/controllers/basic_commits_controller.go index 2065b54c5..68c2698fd 100644 --- a/pkg/gui/controllers/basic_commits_controller.go +++ b/pkg/gui/controllers/basic_commits_controller.go @@ -1,7 +1,6 @@ package controllers import ( - "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -51,14 +50,14 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ }, { Key: opts.GetKey(opts.Config.Universal.New), - Modifier: gocui.ModNone, Handler: self.checkSelected(self.newBranch), Description: self.c.Tr.LcCreateNewBranchFromCommit, }, { Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), Handler: self.checkSelected(self.createResetMenu), - Description: self.c.Tr.LcResetToThisCommit, + Description: self.c.Tr.LcViewResetOptions, + OpensMenu: true, }, { Key: opts.GetKey(opts.Config.Commits.CherryPickCopy), diff --git a/pkg/i18n/chinese.go b/pkg/i18n/chinese.go index 3b33f3841..28d95443f 100644 --- a/pkg/i18n/chinese.go +++ b/pkg/i18n/chinese.go @@ -101,7 +101,6 @@ func chineseTranslationSet() TranslationSet { LcClose: "鍏抽棴", LcQuit: "閫鍑", LcSquashDown: "鍚戜笅鍘嬬缉", - LcResetToThisCommit: "閲嶇疆涓烘鎻愪氦", LcFixupCommit: "淇鎻愪氦锛坒ixup锛", NoCommitsThisBranch: "璇ュ垎鏀病鏈夋彁浜", OnlySquashTopmostCommit: "鍙兘鍘嬬缉鏈椤跺眰鐨勬彁浜", diff --git a/pkg/i18n/dutch.go b/pkg/i18n/dutch.go index 394b4abc4..6cbeddbb4 100644 --- a/pkg/i18n/dutch.go +++ b/pkg/i18n/dutch.go @@ -67,7 +67,6 @@ func dutchTranslationSet() TranslationSet { LcClose: "sluiten", LcQuit: "quit", LcSquashDown: "squash beneden", - LcResetToThisCommit: "reset naar deze commit", LcFixupCommit: "Fixup commit", OnlySquashTopmostCommit: "Kan alleen bovenste commit squashen", YouNoCommitsToSquash: "Je hebt geen commits om mee te squashen", diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 678b8cd18..02dce1416 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -82,7 +82,6 @@ type TranslationSet struct { LcClose string LcQuit string LcSquashDown string - LcResetToThisCommit string LcFixupCommit string OnlySquashTopmostCommit string YouNoCommitsToSquash string @@ -673,7 +672,6 @@ func EnglishTranslationSet() TranslationSet { LcClose: "close", LcQuit: "quit", LcSquashDown: "squash down", - LcResetToThisCommit: "reset to this commit", LcFixupCommit: "fixup commit", NoCommitsThisBranch: "No commits for this branch", OnlySquashTopmostCommit: "Can only squash topmost commit", diff --git a/pkg/i18n/polish.go b/pkg/i18n/polish.go index ae6942abe..3ed130e05 100644 --- a/pkg/i18n/polish.go +++ b/pkg/i18n/polish.go @@ -60,7 +60,6 @@ func polishTranslationSet() TranslationSet { CloseConfirm: "{{.keyBindClose}}: zamknij, {{.keyBindConfirm}}: potwierd藕", LcClose: "zamknij", LcSquashDown: "艣ci艣nij", - LcResetToThisCommit: "zresetuj do tego commita", LcFixupCommit: "napraw commit", NoCommitsThisBranch: "Brak commit贸w dla tej ga艂臋zi", OnlySquashTopmostCommit: "Mo偶na tylko sp艂aszczy膰 najwy偶szy commit", From 240483953f708f538b3396fa9e21069c1461137c Mon Sep 17 00:00:00 2001 From: Moritz HaaseDate: Sat, 26 Mar 2022 18:10:58 +0100 Subject: [PATCH 137/385] config: Add option 'git.autoRefresh' to en-/disable auto-refresh Adds a new 'autoRefresh' option to the 'git' config section that allows user to disable auto-refresh (defaults to on). If auto-refresh is enabled, the refreshInterval is now checked before starting the timer to prevent crashes when it is non-positive. Fixes #1417 --- docs/Config.md | 3 ++- pkg/config/user_config.go | 2 ++ pkg/gui/gui.go | 11 ++++++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/Config.md b/docs/Config.md index aac7f0349..951686073 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -73,6 +73,7 @@ git: showGraph: 'when-maximised' skipHookPrefix: WIP autoFetch: true + autoRefresh: true branchLogCmd: 'git log --graph --color=always --abbrev-commit --decorate --date=relative --pretty=medium {{branchName}} --' allBranchesLogCmd: 'git log --graph --all --color=always --abbrev-commit --decorate --date=relative --pretty=medium' overrideGpg: false # prevents lazygit from spawning a separate process when using GPG @@ -84,7 +85,7 @@ os: editCommandTemplate: '{{editor}} {{filename}}' openCommand: '' refresher: - refreshInterval: 10 # file/submodule refresh interval in seconds + refreshInterval: 10 # File/submodule refresh interval in seconds. Auto-refresh can be disabled via option 'git.autoRefresh'. fetchInterval: 60 # re-fetch interval in seconds update: method: prompt # can be: prompt | background | never diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 988673f1e..321a7fa5e 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -68,6 +68,7 @@ type GitConfig struct { Merging MergingConfig `yaml:"merging"` SkipHookPrefix string `yaml:"skipHookPrefix"` AutoFetch bool `yaml:"autoFetch"` + AutoRefresh bool `yaml:"autoRefresh"` BranchLogCmd string `yaml:"branchLogCmd"` AllBranchesLogCmd string `yaml:"allBranchesLogCmd"` OverrideGpg bool `yaml:"overrideGpg"` @@ -373,6 +374,7 @@ func GetDefaultConfig() *UserConfig { }, SkipHookPrefix: "WIP", AutoFetch: true, + AutoRefresh: true, BranchLogCmd: "git log --graph --color=always --abbrev-commit --decorate --date=relative --pretty=medium {{branchName}} --", AllBranchesLogCmd: "git log --graph --all --color=always --abbrev-commit --decorate --date=relative --pretty=medium", DisableForcePushing: false, diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index b4e0f8de4..3848f2bd9 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -587,7 +587,16 @@ func (gui *Gui) Run(filterPath string) error { go utils.Safe(gui.startBackgroundFetch) } - gui.goEvery(time.Second*time.Duration(userConfig.Refresher.RefreshInterval), gui.stopChan, gui.refreshFilesAndSubmodules) + if userConfig.Git.AutoRefresh { + refreshInterval := userConfig.Refresher.RefreshInterval + if refreshInterval > 0 { + gui.goEvery(time.Second*time.Duration(refreshInterval), gui.stopChan, gui.refreshFilesAndSubmodules) + } else { + gui.c.Log.Errorf( + "Value of config option 'refresher.refreshInterval' (%d) is invalid, disabling auto-refresh", + refreshInterval) + } + } gui.c.Log.Info("starting main loop") From 4abd80e2c455cf7d92fa2b3a4389b5baa1ae5aa3 Mon Sep 17 00:00:00 2001 From: Moritz Haase Date: Sat, 26 Mar 2022 18:24:36 +0100 Subject: [PATCH 138/385] pkg/gui: Fix crash if auto-fetch interval is non-positive Check whether the auto-fetch interval configured is actually positive before starting the background fetcher. If it is not, an error is logged. Also improve the config option documentation a bit to make it easier to understand how to disable auto-fetch. --- docs/Config.md | 2 +- pkg/gui/gui.go | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/Config.md b/docs/Config.md index 951686073..77685a378 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -86,7 +86,7 @@ os: openCommand: '' refresher: refreshInterval: 10 # File/submodule refresh interval in seconds. Auto-refresh can be disabled via option 'git.autoRefresh'. - fetchInterval: 60 # re-fetch interval in seconds + fetchInterval: 60 # Re-fetch interval in seconds. Auto-fetch can be disabled via option 'git.autoFetch'. update: method: prompt # can be: prompt | background | never days: 14 # how often an update is checked for diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 3848f2bd9..ba2d85a27 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -583,8 +583,16 @@ func (gui *Gui) Run(filterPath string) error { } gui.waitForIntro.Add(1) - if gui.c.UserConfig.Git.AutoFetch { - go utils.Safe(gui.startBackgroundFetch) + + if userConfig.Git.AutoFetch { + fetchInterval := userConfig.Refresher.FetchInterval + if fetchInterval > 0 { + go utils.Safe(gui.startBackgroundFetch) + } else { + gui.c.Log.Errorf( + "Value of config option 'refresher.fetchInterval' (%d) is invalid, disabling auto-fetch", + fetchInterval) + } } if userConfig.Git.AutoRefresh { From ae10a5ea8865e04b6369f6a0f9cd8a554ca6cac1 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 26 Mar 2022 21:18:10 +1100 Subject: [PATCH 139/385] add git fetch prune integration test --- pkg/integration/integration.go | 11 +++--- test/integration/fetchPrune/config/config.yml | 10 ++++++ .../expected/.git_keep/COMMIT_EDITMSG | 1 + .../fetchPrune/expected/.git_keep/FETCH_HEAD | 1 + .../fetchPrune/expected/.git_keep/HEAD | 1 + .../fetchPrune/expected/.git_keep/config | 21 +++++++++++ .../fetchPrune/expected/.git_keep/description | 1 + .../fetchPrune/expected/.git_keep/index | Bin 0 -> 137 bytes .../expected/.git_keep/info/exclude | 7 ++++ .../fetchPrune/expected/.git_keep/logs/HEAD | 3 ++ .../expected/.git_keep/logs/refs/heads/master | 1 + .../.git_keep/logs/refs/heads/other_branch | 1 + .../.git_keep/logs/refs/remotes/origin/master | 1 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin 0 -> 52 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin 0 -> 21 bytes .../f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 | Bin 0 -> 121 bytes .../fetchPrune/expected/.git_keep/packed-refs | 1 + .../expected/.git_keep/refs/heads/master | 1 + .../.git_keep/refs/heads/other_branch | 1 + .../.git_keep/refs/remotes/origin/master | 1 + test/integration/fetchPrune/expected/myfile1 | 1 + .../fetchPrune/expected_remote/HEAD | 1 + .../fetchPrune/expected_remote/config | 8 +++++ .../fetchPrune/expected_remote/description | 1 + .../fetchPrune/expected_remote/info/exclude | 7 ++++ .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin 0 -> 52 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin 0 -> 21 bytes .../f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 | Bin 0 -> 121 bytes .../fetchPrune/expected_remote/packed-refs | 2 ++ test/integration/fetchPrune/recording.json | 1 + test/integration/fetchPrune/setup.sh | 34 ++++++++++++++++++ test/integration/fetchPrune/test.json | 4 +++ 32 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 test/integration/fetchPrune/config/config.yml create mode 100644 test/integration/fetchPrune/expected/.git_keep/COMMIT_EDITMSG create mode 100644 test/integration/fetchPrune/expected/.git_keep/FETCH_HEAD create mode 100644 test/integration/fetchPrune/expected/.git_keep/HEAD create mode 100644 test/integration/fetchPrune/expected/.git_keep/config create mode 100644 test/integration/fetchPrune/expected/.git_keep/description create mode 100644 test/integration/fetchPrune/expected/.git_keep/index create mode 100644 test/integration/fetchPrune/expected/.git_keep/info/exclude create mode 100644 test/integration/fetchPrune/expected/.git_keep/logs/HEAD create mode 100644 test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/master create mode 100644 test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/other_branch create mode 100644 test/integration/fetchPrune/expected/.git_keep/logs/refs/remotes/origin/master create mode 100644 test/integration/fetchPrune/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 create mode 100644 test/integration/fetchPrune/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 create mode 100644 test/integration/fetchPrune/expected/.git_keep/objects/f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 create mode 100644 test/integration/fetchPrune/expected/.git_keep/packed-refs create mode 100644 test/integration/fetchPrune/expected/.git_keep/refs/heads/master create mode 100644 test/integration/fetchPrune/expected/.git_keep/refs/heads/other_branch create mode 100644 test/integration/fetchPrune/expected/.git_keep/refs/remotes/origin/master create mode 100644 test/integration/fetchPrune/expected/myfile1 create mode 100644 test/integration/fetchPrune/expected_remote/HEAD create mode 100644 test/integration/fetchPrune/expected_remote/config create mode 100644 test/integration/fetchPrune/expected_remote/description create mode 100644 test/integration/fetchPrune/expected_remote/info/exclude create mode 100644 test/integration/fetchPrune/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 create mode 100644 test/integration/fetchPrune/expected_remote/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 create mode 100644 test/integration/fetchPrune/expected_remote/objects/f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 create mode 100644 test/integration/fetchPrune/expected_remote/packed-refs create mode 100644 test/integration/fetchPrune/recording.json create mode 100644 test/integration/fetchPrune/setup.sh create mode 100644 test/integration/fetchPrune/test.json diff --git a/pkg/integration/integration.go b/pkg/integration/integration.go index bb2d7a0b0..ed1c0fe42 100644 --- a/pkg/integration/integration.go +++ b/pkg/integration/integration.go @@ -89,12 +89,12 @@ func RunTests( for _, test := range tests { test := test - if test.Skip && !includeSkipped { - logf("skipping test: %s", test.Name) - continue - } - fnWrapper(test, func(t *testing.T) error { //nolint: thelper + if test.Skip && !includeSkipped { + logf("skipping test: %s", test.Name) + return nil + } + speeds := getTestSpeeds(test.Speed, mode, speedEnv) testPath := filepath.Join(testDir, test.Name) actualRepoDir := filepath.Join(testPath, "actual") @@ -357,6 +357,7 @@ func generateSnapshot(dir string) (string, error) { snapshot := "" cmdStrs := []string{ + `remote show -n origin`, // remote branches `status`, // file tree `log --pretty=%B -p -1`, // log `tag -n`, // tags diff --git a/test/integration/fetchPrune/config/config.yml b/test/integration/fetchPrune/config/config.yml new file mode 100644 index 000000000..a77fb48ed --- /dev/null +++ b/test/integration/fetchPrune/config/config.yml @@ -0,0 +1,10 @@ +disableStartupPopups: true +git: + autoFetch: false +gui: + theme: + activeBorderColor: + - green + - bold + SelectedRangeBgcolor: + - reverse diff --git a/test/integration/fetchPrune/expected/.git_keep/COMMIT_EDITMSG b/test/integration/fetchPrune/expected/.git_keep/COMMIT_EDITMSG new file mode 100644 index 000000000..3829ab872 --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/COMMIT_EDITMSG @@ -0,0 +1 @@ +myfile1 diff --git a/test/integration/fetchPrune/expected/.git_keep/FETCH_HEAD b/test/integration/fetchPrune/expected/.git_keep/FETCH_HEAD new file mode 100644 index 000000000..8ef89fd5e --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/FETCH_HEAD @@ -0,0 +1 @@ +f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 branch 'master' of ../actual_remote diff --git a/test/integration/fetchPrune/expected/.git_keep/HEAD b/test/integration/fetchPrune/expected/.git_keep/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/test/integration/fetchPrune/expected/.git_keep/config b/test/integration/fetchPrune/expected/.git_keep/config new file mode 100644 index 000000000..6dfad7326 --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/config @@ -0,0 +1,21 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true +[user] + email = CI@example.com + name = CI +[fetch] + prune = true +[remote "origin"] + url = ../actual_remote + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "master"] + remote = origin + merge = refs/heads/master +[branch "other_branch"] + remote = origin + merge = refs/heads/other_branch diff --git a/test/integration/fetchPrune/expected/.git_keep/description b/test/integration/fetchPrune/expected/.git_keep/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/test/integration/fetchPrune/expected/.git_keep/index b/test/integration/fetchPrune/expected/.git_keep/index new file mode 100644 index 0000000000000000000000000000000000000000..35b2e51a41fb2f2f9e218cffb40a031b02f6096b GIT binary patch literal 137 zcmZ?q402{*U|<4b#w5EpmF64um|-*{0|P75oPAFj7#f!VrN08zhyXF$(mjv=s;1uf z5)m53lkapPz^kSEDg%3NWm;xVsv%H8NRX>5kdkCDR50M;%lWWu`@CM4hix~67Jm13 ezUIFs=mej|q}#XDe!ICeo|kQ?QVuWiPXhoKkuLK9 literal 0 HcmV?d00001 diff --git a/test/integration/fetchPrune/expected/.git_keep/info/exclude b/test/integration/fetchPrune/expected/.git_keep/info/exclude new file mode 100644 index 000000000..8e9f2071f --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/info/exclude @@ -0,0 +1,7 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ +.DS_Store diff --git a/test/integration/fetchPrune/expected/.git_keep/logs/HEAD b/test/integration/fetchPrune/expected/.git_keep/logs/HEAD new file mode 100644 index 000000000..eac6e78df --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/logs/HEAD @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 CI 1648290937 +1100 commit (initial): myfile1 +f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 CI 1648290937 +1100 checkout: moving from master to other_branch +f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 CI 1648290937 +1100 checkout: moving from other_branch to master diff --git a/test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/master b/test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/master new file mode 100644 index 000000000..94180e0b5 --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 CI 1648290937 +1100 commit (initial): myfile1 diff --git a/test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/other_branch b/test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/other_branch new file mode 100644 index 000000000..7cd5bcbce --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/other_branch @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 CI 1648290937 +1100 branch: Created from HEAD diff --git a/test/integration/fetchPrune/expected/.git_keep/logs/refs/remotes/origin/master b/test/integration/fetchPrune/expected/.git_keep/logs/refs/remotes/origin/master new file mode 100644 index 000000000..225a60ab5 --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/logs/refs/remotes/origin/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 CI 1648290938 +1100 fetch origin: storing head diff --git a/test/integration/fetchPrune/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/fetchPrune/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 new file mode 100644 index 0000000000000000000000000000000000000000..7f2ebf4eeb6ad6875bcc2a2b91ca3345ee06b45e GIT binary patch literal 52 zcmb `~^A08nuUMF0Q* literal 0 HcmV?d00001 diff --git a/test/integration/fetchPrune/expected/.git_keep/objects/f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 b/test/integration/fetchPrune/expected/.git_keep/objects/f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 new file mode 100644 index 0000000000000000000000000000000000000000..3d352742a54fef71e79f7712cdc1716f1d7fa401 GIT binary patch literal 121 zcmV-<0EYi~0gcT;3d0}}K+&!}#q0}Z#!N?rQVLn+7)D1Lh**M! r}>NB&Fm+Z+#DvoC!vT%v%ZcY65ciUi`;4w}w-DCZ%dP}W7frPyc b7zPJdB1Ci6bJF!sZt78%RmuDSG=MDIu$DTV literal 0 HcmV?d00001 diff --git a/test/integration/fetchPrune/expected/.git_keep/packed-refs b/test/integration/fetchPrune/expected/.git_keep/packed-refs new file mode 100644 index 000000000..250f18738 --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/packed-refs @@ -0,0 +1 @@ +# pack-refs with: peeled fully-peeled sorted diff --git a/test/integration/fetchPrune/expected/.git_keep/refs/heads/master b/test/integration/fetchPrune/expected/.git_keep/refs/heads/master new file mode 100644 index 000000000..0725115bd --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/refs/heads/master @@ -0,0 +1 @@ +f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 diff --git a/test/integration/fetchPrune/expected/.git_keep/refs/heads/other_branch b/test/integration/fetchPrune/expected/.git_keep/refs/heads/other_branch new file mode 100644 index 000000000..0725115bd --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/refs/heads/other_branch @@ -0,0 +1 @@ +f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 diff --git a/test/integration/fetchPrune/expected/.git_keep/refs/remotes/origin/master b/test/integration/fetchPrune/expected/.git_keep/refs/remotes/origin/master new file mode 100644 index 000000000..0725115bd --- /dev/null +++ b/test/integration/fetchPrune/expected/.git_keep/refs/remotes/origin/master @@ -0,0 +1 @@ +f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 diff --git a/test/integration/fetchPrune/expected/myfile1 b/test/integration/fetchPrune/expected/myfile1 new file mode 100644 index 000000000..a5bce3fd2 --- /dev/null +++ b/test/integration/fetchPrune/expected/myfile1 @@ -0,0 +1 @@ +test1 diff --git a/test/integration/fetchPrune/expected_remote/HEAD b/test/integration/fetchPrune/expected_remote/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/test/integration/fetchPrune/expected_remote/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/test/integration/fetchPrune/expected_remote/config b/test/integration/fetchPrune/expected_remote/config new file mode 100644 index 000000000..0c3c56578 --- /dev/null +++ b/test/integration/fetchPrune/expected_remote/config @@ -0,0 +1,8 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true + ignorecase = true + precomposeunicode = true +[remote "origin"] + url = /Users/jesseduffieldduffield/go/src/github.com/jesseduffield/lazygit/test/integration/fetchPrune/./actual diff --git a/test/integration/fetchPrune/expected_remote/description b/test/integration/fetchPrune/expected_remote/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/test/integration/fetchPrune/expected_remote/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/test/integration/fetchPrune/expected_remote/info/exclude b/test/integration/fetchPrune/expected_remote/info/exclude new file mode 100644 index 000000000..8e9f2071f --- /dev/null +++ b/test/integration/fetchPrune/expected_remote/info/exclude @@ -0,0 +1,7 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ +.DS_Store diff --git a/test/integration/fetchPrune/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/fetchPrune/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 new file mode 100644 index 0000000000000000000000000000000000000000..7f2ebf4eeb6ad6875bcc2a2b91ca3345ee06b45e GIT binary patch literal 52 zcmb `~^A08nuUMF0Q* literal 0 HcmV?d00001 diff --git a/test/integration/fetchPrune/expected_remote/objects/f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 b/test/integration/fetchPrune/expected_remote/objects/f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 new file mode 100644 index 0000000000000000000000000000000000000000..3d352742a54fef71e79f7712cdc1716f1d7fa401 GIT binary patch literal 121 zcmV-<0EYi~0gcT;3d0}}K+&!}#q0}Z#!N?rQVLn+7)D1Lh**M! r}>NB&Fm+Z+#DvoC!vT%v%ZcY65ciUi`;4w}w-DCZ%dP}W7frPyc b7zPJdB1Ci6bJF!sZt78%RmuDSG=MDIu$DTV literal 0 HcmV?d00001 diff --git a/test/integration/fetchPrune/expected_remote/packed-refs b/test/integration/fetchPrune/expected_remote/packed-refs new file mode 100644 index 000000000..0488de20d --- /dev/null +++ b/test/integration/fetchPrune/expected_remote/packed-refs @@ -0,0 +1,2 @@ +# pack-refs with: peeled fully-peeled sorted +f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 refs/heads/master diff --git a/test/integration/fetchPrune/recording.json b/test/integration/fetchPrune/recording.json new file mode 100644 index 000000000..b24cbf0cb --- /dev/null +++ b/test/integration/fetchPrune/recording.json @@ -0,0 +1 @@ +{"KeyEvents":[{"Timestamp":608,"Mod":0,"Key":256,"Ch":102},{"Timestamp":1568,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":272,"Height":74}]} \ No newline at end of file diff --git a/test/integration/fetchPrune/setup.sh b/test/integration/fetchPrune/setup.sh new file mode 100644 index 000000000..19d0beec7 --- /dev/null +++ b/test/integration/fetchPrune/setup.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +set -e + +cd $1 + +git init + +git config user.email "CI@example.com" +git config user.name "CI" + +# we're setting this to ensure that it's honoured by the fetch command +git config fetch.prune true + +echo test1 > myfile1 +git add . +git commit -am "myfile1" + +git checkout -b other_branch +git checkout master + +cd .. +git clone --bare ./actual actual_remote + +cd actual + +git remote add origin ../actual_remote +git fetch origin +git branch --set-upstream-to=origin/master master +git branch --set-upstream-to=origin/other_branch other_branch + +# unbenownst to our test repo we're removing the branch on the remote, so upon +# fetching with prune: true we expect git to realise the remote branch is gone +git -C ../actual_remote branch -d other_branch diff --git a/test/integration/fetchPrune/test.json b/test/integration/fetchPrune/test.json new file mode 100644 index 000000000..e358a8c9a --- /dev/null +++ b/test/integration/fetchPrune/test.json @@ -0,0 +1,4 @@ +{ + "description": "fetch from the remote with the 'prune' option set in the git config", + "speed": 10 +} From 2b3d457aa44821a7d0c1705a510a5567e44a07da Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 27 Mar 2022 11:22:16 +1100 Subject: [PATCH 140/385] honour push.default matching config value --- pkg/gui/controllers/sync_controller.go | 74 ++++++++++-------- .../expected/.git_keep/COMMIT_EDITMSG | 1 + .../expected/.git_keep/FETCH_HEAD | 2 + .../forcePushMultiple/expected/.git_keep/HEAD | 1 + .../expected/.git_keep/ORIG_HEAD | 1 + .../expected/.git_keep/config | 21 +++++ .../expected/.git_keep/description | 1 + .../expected/.git_keep/index | Bin 0 -> 209 bytes .../expected/.git_keep/info/exclude | 7 ++ .../expected/.git_keep/logs/HEAD | 10 +++ .../expected/.git_keep/logs/refs/heads/master | 4 + .../.git_keep/logs/refs/heads/other_branch | 3 + .../.git_keep/logs/refs/remotes/origin/master | 3 + .../logs/refs/remotes/origin/other_branch | 3 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin 0 -> 52 bytes .../16/d8875e19987b16f1991a41fd3f4536d16f7cb4 | 2 + .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin 0 -> 21 bytes .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin 0 -> 103 bytes .../42/d408cffcc087da21115f9ebc29e9765a2beb83 | 3 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin 0 -> 21 bytes .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin 0 -> 77 bytes .../b8/2ed4a67bef9ef50807adf409f103ef7b0832ab | Bin 0 -> 149 bytes .../ce/0848710343a75263ea72cb5bdfa666b9ecda68 | Bin 0 -> 103 bytes .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin 0 -> 21 bytes .../d3/708eeec2b9d69acbe87862330e844e85f77de1 | Bin 0 -> 149 bytes .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin 0 -> 21 bytes .../expected/.git_keep/refs/heads/master | 1 + .../.git_keep/refs/heads/other_branch | 1 + .../.git_keep/refs/remotes/origin/master | 1 + .../refs/remotes/origin/other_branch | 1 + .../forcePushMultiple/expected/myfile1 | 1 + .../forcePushMultiple/expected/myfile2 | 1 + .../forcePushMultiple/expected_remote/HEAD | 1 + .../forcePushMultiple/expected_remote/config | 8 ++ .../expected_remote/description | 1 + .../expected_remote/info/exclude | 7 ++ .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin 0 -> 52 bytes .../16/d8875e19987b16f1991a41fd3f4536d16f7cb4 | 2 + .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin 0 -> 21 bytes .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin 0 -> 103 bytes .../42/d408cffcc087da21115f9ebc29e9765a2beb83 | 3 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin 0 -> 21 bytes .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin 0 -> 77 bytes .../b8/2ed4a67bef9ef50807adf409f103ef7b0832ab | Bin 0 -> 149 bytes .../ce/0848710343a75263ea72cb5bdfa666b9ecda68 | Bin 0 -> 103 bytes .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin 0 -> 21 bytes .../d3/708eeec2b9d69acbe87862330e844e85f77de1 | Bin 0 -> 149 bytes .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin 0 -> 21 bytes .../expected_remote/packed-refs | 3 + .../expected_remote/refs/heads/master | 1 + .../expected_remote/refs/heads/other_branch | 1 + .../forcePushMultiple/recording.json | 1 + test/integration/forcePushMultiple/setup.sh | 54 +++++++++++++ test/integration/forcePushMultiple/test.json | 4 + 54 files changed, 196 insertions(+), 32 deletions(-) create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/COMMIT_EDITMSG create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/FETCH_HEAD create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/HEAD create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/ORIG_HEAD create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/config create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/description create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/index create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/info/exclude create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/logs/HEAD create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/master create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/other_branch create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/master create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/other_branch create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/16/d8875e19987b16f1991a41fd3f4536d16f7cb4 create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/b8/2ed4a67bef9ef50807adf409f103ef7b0832ab create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/d3/708eeec2b9d69acbe87862330e844e85f77de1 create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/refs/heads/master create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/refs/heads/other_branch create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/master create mode 100644 test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/other_branch create mode 100644 test/integration/forcePushMultiple/expected/myfile1 create mode 100644 test/integration/forcePushMultiple/expected/myfile2 create mode 100644 test/integration/forcePushMultiple/expected_remote/HEAD create mode 100644 test/integration/forcePushMultiple/expected_remote/config create mode 100644 test/integration/forcePushMultiple/expected_remote/description create mode 100644 test/integration/forcePushMultiple/expected_remote/info/exclude create mode 100644 test/integration/forcePushMultiple/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 create mode 100644 test/integration/forcePushMultiple/expected_remote/objects/16/d8875e19987b16f1991a41fd3f4536d16f7cb4 create mode 100644 test/integration/forcePushMultiple/expected_remote/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 create mode 100644 test/integration/forcePushMultiple/expected_remote/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce create mode 100644 test/integration/forcePushMultiple/expected_remote/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 create mode 100644 test/integration/forcePushMultiple/expected_remote/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 create mode 100644 test/integration/forcePushMultiple/expected_remote/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 create mode 100644 test/integration/forcePushMultiple/expected_remote/objects/b8/2ed4a67bef9ef50807adf409f103ef7b0832ab create mode 100644 test/integration/forcePushMultiple/expected_remote/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 create mode 100644 test/integration/forcePushMultiple/expected_remote/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 create mode 100644 test/integration/forcePushMultiple/expected_remote/objects/d3/708eeec2b9d69acbe87862330e844e85f77de1 create mode 100644 test/integration/forcePushMultiple/expected_remote/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b create mode 100644 test/integration/forcePushMultiple/expected_remote/packed-refs create mode 100644 test/integration/forcePushMultiple/expected_remote/refs/heads/master create mode 100644 test/integration/forcePushMultiple/expected_remote/refs/heads/other_branch create mode 100644 test/integration/forcePushMultiple/recording.json create mode 100644 test/integration/forcePushMultiple/setup.sh create mode 100644 test/integration/forcePushMultiple/test.json diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go index 8501c5484..38f8db733 100644 --- a/pkg/gui/controllers/sync_controller.go +++ b/pkg/gui/controllers/sync_controller.go @@ -1,6 +1,7 @@ package controllers import ( + "errors" "fmt" "strings" @@ -74,13 +75,8 @@ func (self *SyncController) branchCheckedOut(f func(*models.Branch) error) func( func (self *SyncController) push(currentBranch *models.Branch) error { // if we have pullables we'll ask if the user wants to force push if currentBranch.IsTrackingRemote() { - opts := pushOpts{ - force: false, - upstreamRemote: currentBranch.UpstreamRemote, - upstreamBranch: currentBranch.UpstreamBranch, - } + opts := pushOpts{} if currentBranch.HasCommitsToPull() { - opts.force = true return self.requestToForcePush(opts) } else { return self.pushAux(opts) @@ -90,21 +86,15 @@ func (self *SyncController) push(currentBranch *models.Branch) error { return self.pushAux(pushOpts{setUpstream: true}) } else { return self.promptForUpstream(currentBranch, func(upstream string) error { - var upstreamBranch, upstreamRemote string - split := strings.Split(upstream, " ") - if len(split) == 2 { - upstreamRemote = split[0] - upstreamBranch = split[1] - } else { - upstreamRemote = upstream - upstreamBranch = "" + upstreamRemote, upstreamBranch, err := self.parseUpstream(upstream) + if err != nil { + return self.c.Error(err) } return self.pushAux(pushOpts{ - force: false, + setUpstream: true, upstreamRemote: upstreamRemote, upstreamBranch: upstreamBranch, - setUpstream: true, }) }) } @@ -117,27 +107,46 @@ func (self *SyncController) pull(currentBranch *models.Branch) error { // if we have no upstream branch we need to set that first if !currentBranch.IsTrackingRemote() { return self.promptForUpstream(currentBranch, func(upstream string) error { - var upstreamBranch, upstreamRemote string - split := strings.Split(upstream, " ") - if len(split) != 2 { - return self.c.ErrorMsg(self.c.Tr.InvalidUpstream) + if err := self.setCurrentBranchUpstream(upstream); err != nil { + return self.c.Error(err) } - upstreamRemote = split[0] - upstreamBranch = split[1] - - if err := self.git.Branch.SetCurrentBranchUpstream(upstreamRemote, upstreamBranch); err != nil { - errorMessage := err.Error() - if strings.Contains(errorMessage, "does not exist") { - errorMessage = fmt.Sprintf("upstream branch %s not found.\nIf you expect it to exist, you should fetch (with 'f').\nOtherwise, you should push (with 'shift+P')", upstream) - } - return self.c.ErrorMsg(errorMessage) - } - return self.PullAux(PullFilesOptions{UpstreamRemote: upstreamRemote, UpstreamBranch: upstreamBranch, Action: action}) + return self.PullAux(PullFilesOptions{Action: action}) }) } - return self.PullAux(PullFilesOptions{UpstreamRemote: currentBranch.UpstreamRemote, UpstreamBranch: currentBranch.UpstreamBranch, Action: action}) + return self.PullAux(PullFilesOptions{Action: action}) +} + +func (self *SyncController) setCurrentBranchUpstream(upstream string) error { + upstreamRemote, upstreamBranch, err := self.parseUpstream(upstream) + if err != nil { + return err + } + + if err := self.git.Branch.SetCurrentBranchUpstream(upstreamRemote, upstreamBranch); err != nil { + if strings.Contains(err.Error(), "does not exist") { + return fmt.Errorf( + "upstream branch %s/%s not found.\nIf you expect it to exist, you should fetch (with 'f').\nOtherwise, you should push (with 'shift+P')", + upstreamRemote, upstreamBranch, + ) + } + return err + } + return nil +} + +func (self *SyncController) parseUpstream(upstream string) (string, string, error) { + var upstreamBranch, upstreamRemote string + split := strings.Split(upstream, " ") + if len(split) != 2 { + return "", "", errors.New(self.c.Tr.InvalidUpstream) + } + + upstreamRemote = split[0] + upstreamBranch = split[1] + + return upstreamRemote, upstreamBranch, nil } func (self *SyncController) promptForUpstream(currentBranch *models.Branch, onConfirm func(string) error) error { @@ -229,6 +238,7 @@ func (self *SyncController) requestToForcePush(opts pushOpts) error { Title: self.c.Tr.ForcePush, Prompt: self.c.Tr.ForcePushPrompt, HandleConfirm: func() error { + opts.force = true return self.pushAux(opts) }, }) diff --git a/test/integration/forcePushMultiple/expected/.git_keep/COMMIT_EDITMSG b/test/integration/forcePushMultiple/expected/.git_keep/COMMIT_EDITMSG new file mode 100644 index 000000000..51be8ec3d --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/COMMIT_EDITMSG @@ -0,0 +1 @@ +myfile4 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/FETCH_HEAD b/test/integration/forcePushMultiple/expected/.git_keep/FETCH_HEAD new file mode 100644 index 000000000..d56304e09 --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/FETCH_HEAD @@ -0,0 +1,2 @@ +b82ed4a67bef9ef50807adf409f103ef7b0832ab branch 'master' of ../actual_remote +d3708eeec2b9d69acbe87862330e844e85f77de1 not-for-merge branch 'other_branch' of ../actual_remote diff --git a/test/integration/forcePushMultiple/expected/.git_keep/HEAD b/test/integration/forcePushMultiple/expected/.git_keep/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/test/integration/forcePushMultiple/expected/.git_keep/ORIG_HEAD b/test/integration/forcePushMultiple/expected/.git_keep/ORIG_HEAD new file mode 100644 index 000000000..3774ff3d1 --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/ORIG_HEAD @@ -0,0 +1 @@ +d3708eeec2b9d69acbe87862330e844e85f77de1 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/config b/test/integration/forcePushMultiple/expected/.git_keep/config new file mode 100644 index 000000000..740ff301f --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/config @@ -0,0 +1,21 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true +[user] + email = CI@example.com + name = CI +[push] + default = matching +[remote "origin"] + url = ../actual_remote + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "master"] + remote = origin + merge = refs/heads/master +[branch "other_branch"] + remote = origin + merge = refs/heads/other_branch diff --git a/test/integration/forcePushMultiple/expected/.git_keep/description b/test/integration/forcePushMultiple/expected/.git_keep/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/test/integration/forcePushMultiple/expected/.git_keep/index b/test/integration/forcePushMultiple/expected/.git_keep/index new file mode 100644 index 0000000000000000000000000000000000000000..375819d60017e3e32da674025180ba89508246c7 GIT binary patch literal 209 zcmZ?q402{*U|<5_B>Q#j8jJQmhtZ4-46ICZb>$cs8kaCIFn$H95dmVhrF$O#RZYF| zB_cG6C*SEpfLBZRRR;Fl%CyX!R70QwkbcdpmqK7P)ErZEb0m0v7&R#EJNI(cqVTHz zmRH*IE!1J=7y-=*337D>Qj!ct3I<%uO{5|}+ 1648340487 +1100 commit (initial): myfile1 +16d8875e19987b16f1991a41fd3f4536d16f7cb4 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 commit: myfile2 +42d408cffcc087da21115f9ebc29e9765a2beb83 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 checkout: moving from master to other_branch +42d408cffcc087da21115f9ebc29e9765a2beb83 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 checkout: moving from other_branch to master +42d408cffcc087da21115f9ebc29e9765a2beb83 b82ed4a67bef9ef50807adf409f103ef7b0832ab CI 1648340487 +1100 commit: myfile3 +b82ed4a67bef9ef50807adf409f103ef7b0832ab 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 reset: moving to HEAD^ +42d408cffcc087da21115f9ebc29e9765a2beb83 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 checkout: moving from master to other_branch +42d408cffcc087da21115f9ebc29e9765a2beb83 d3708eeec2b9d69acbe87862330e844e85f77de1 CI 1648340487 +1100 commit: myfile4 +d3708eeec2b9d69acbe87862330e844e85f77de1 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 reset: moving to HEAD^ +42d408cffcc087da21115f9ebc29e9765a2beb83 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 checkout: moving from other_branch to master diff --git a/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/master b/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/master new file mode 100644 index 000000000..15de170c8 --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/master @@ -0,0 +1,4 @@ +0000000000000000000000000000000000000000 16d8875e19987b16f1991a41fd3f4536d16f7cb4 CI 1648340487 +1100 commit (initial): myfile1 +16d8875e19987b16f1991a41fd3f4536d16f7cb4 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 commit: myfile2 +42d408cffcc087da21115f9ebc29e9765a2beb83 b82ed4a67bef9ef50807adf409f103ef7b0832ab CI 1648340487 +1100 commit: myfile3 +b82ed4a67bef9ef50807adf409f103ef7b0832ab 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 reset: moving to HEAD^ diff --git a/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/other_branch b/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/other_branch new file mode 100644 index 000000000..78ea80b06 --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/other_branch @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 branch: Created from HEAD +42d408cffcc087da21115f9ebc29e9765a2beb83 d3708eeec2b9d69acbe87862330e844e85f77de1 CI 1648340487 +1100 commit: myfile4 +d3708eeec2b9d69acbe87862330e844e85f77de1 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 reset: moving to HEAD^ diff --git a/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/master b/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/master new file mode 100644 index 000000000..dd0a1b736 --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/master @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 fetch origin: storing head +42d408cffcc087da21115f9ebc29e9765a2beb83 b82ed4a67bef9ef50807adf409f103ef7b0832ab CI 1648340487 +1100 update by push +b82ed4a67bef9ef50807adf409f103ef7b0832ab 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340489 +1100 update by push diff --git a/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/other_branch b/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/other_branch new file mode 100644 index 000000000..ca4e1389e --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/other_branch @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 fetch origin: storing head +42d408cffcc087da21115f9ebc29e9765a2beb83 d3708eeec2b9d69acbe87862330e844e85f77de1 CI 1648340487 +1100 update by push +d3708eeec2b9d69acbe87862330e844e85f77de1 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340489 +1100 update by push diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/forcePushMultiple/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 new file mode 100644 index 0000000000000000000000000000000000000000..7f2ebf4eeb6ad6875bcc2a2b91ca3345ee06b45e GIT binary patch literal 52 zcmb ~ZE#08nZNMgRZ+ literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/forcePushMultiple/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce new file mode 100644 index 0000000000000000000000000000000000000000..0a734f98100d24e67455a3cfa8497adaccc7a422 GIT binary patch literal 103 zcmV-t0GR)H0V^p=O;s>7Fl8__FfcPQQOK=K%gjkNWLUcA@n6-{8($(qqj>V2E(CbB zbYDeLV#FZ9^TVh?Y2Ue*s}_Y<^|!pzo^PR!qQsctem1Z6nX+eZ_)jSuQWx;@*VuJL J8UTCqE3ZN5G4lWb literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 b/test/integration/forcePushMultiple/expected/.git_keep/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 new file mode 100644 index 000000000..31d3fad7a --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 @@ -0,0 +1,3 @@ +x崕A + E祸叛扫J!C &眄蝴<黣痷m"^谏瑩wi坆Ja朒)J&Gk婡闔'亢H%?0| !Hq們R慱2n淆杂i~'誧阚沧{呃嘈`瘊 +`岅礋j黦]寨[屷9 \ No newline at end of file diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/forcePushMultiple/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 new file mode 100644 index 0000000000000000000000000000000000000000..285df3e5fbab12262e28d85e78af8a31cd0024c1 GIT binary patch literal 21 ccmb `~^A08nuUMF0Q* literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 b/test/integration/forcePushMultiple/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 new file mode 100644 index 0000000000000000000000000000000000000000..96d2e71a6af75cdd27ac5d9628a27faecc40fb66 GIT binary patch literal 77 zcmV-T0J8sh0V^p=O;s>AU@$Z=Ff%bx$gNDv%t B=N-?^8o7KK;!x4hDxZ=ntVWIZ01*pecg literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/b8/2ed4a67bef9ef50807adf409f103ef7b0832ab b/test/integration/forcePushMultiple/expected/.git_keep/objects/b8/2ed4a67bef9ef50807adf409f103ef7b0832ab new file mode 100644 index 0000000000000000000000000000000000000000..55c8270daa81e5e4cdcaa1b2eeeabcb4f7b732e1 GIT binary patch literal 149 zcmV;G0BZku0gaA93c@fD06pgwxeJobrp*RKgr540WV4F}V@rvkzqe2DG%(Czcx`Rz z7E(C%UBvnV5t&A)8W1%HRLvDo$uSiK&%;3$v*lf0-3DKSBUWX06l?YXFlds(K1qt> zkbRLtX!5&1*4<9Cy-xF8KDljAx$xR<7REprT%c&r0M41i9#dWZ%uW01@)R^bRRB9O DRux1N literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 b/test/integration/forcePushMultiple/expected/.git_keep/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 new file mode 100644 index 0000000000000000000000000000000000000000..5e9361d3548aa14bca5d35e0871b31e326387c70 GIT binary patch literal 103 zcmV-t0GR)H0V^p=O;s>7Fl8__FfcPQQOK=K%gjkNWLUcA@n6-{8($(qqj>V2E(CbB zbYDeLV#FZ9^TVh?Y2Ue*s}_Y<^|!pzo^PR!qQr#ZlF88r;s1<|mAy)TaoXZbQtYkQ JApo0YFGO2mGTHzD literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/forcePushMultiple/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 new file mode 100644 index 0000000000000000000000000000000000000000..d39fa7d2fecf1c45a132dfe3a8758952f3c8d968 GIT binary patch literal 21 ccmb }lpN08nuUO8@`> literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/d3/708eeec2b9d69acbe87862330e844e85f77de1 b/test/integration/forcePushMultiple/expected/.git_keep/objects/d3/708eeec2b9d69acbe87862330e844e85f77de1 new file mode 100644 index 0000000000000000000000000000000000000000..e36f500bdd0daf555f8c0a188d92b5d2cc80531d GIT binary patch literal 149 zcmV;G0BZku0gaAJ3c@fDKwak)*$a|MCO;4ny6Q0|lL;1#EhU29-X6j2 b`B2}Ua^bb#Gz3fz&5_k-0AtiakEtPl>Z*U+@)T4*8fiM= D)tx}L literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/forcePushMultiple/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b new file mode 100644 index 0000000000000000000000000000000000000000..9b771fc2f6f41f91b00976b4ff3f8f9935f7931e GIT binary patch literal 21 ccmb >`CU&08otwO#lD@ literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/refs/heads/master b/test/integration/forcePushMultiple/expected/.git_keep/refs/heads/master new file mode 100644 index 000000000..f9339e7e2 --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/refs/heads/master @@ -0,0 +1 @@ +42d408cffcc087da21115f9ebc29e9765a2beb83 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/refs/heads/other_branch b/test/integration/forcePushMultiple/expected/.git_keep/refs/heads/other_branch new file mode 100644 index 000000000..f9339e7e2 --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/refs/heads/other_branch @@ -0,0 +1 @@ +42d408cffcc087da21115f9ebc29e9765a2beb83 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/master b/test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/master new file mode 100644 index 000000000..f9339e7e2 --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/master @@ -0,0 +1 @@ +42d408cffcc087da21115f9ebc29e9765a2beb83 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/other_branch b/test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/other_branch new file mode 100644 index 000000000..f9339e7e2 --- /dev/null +++ b/test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/other_branch @@ -0,0 +1 @@ +42d408cffcc087da21115f9ebc29e9765a2beb83 diff --git a/test/integration/forcePushMultiple/expected/myfile1 b/test/integration/forcePushMultiple/expected/myfile1 new file mode 100644 index 000000000..a5bce3fd2 --- /dev/null +++ b/test/integration/forcePushMultiple/expected/myfile1 @@ -0,0 +1 @@ +test1 diff --git a/test/integration/forcePushMultiple/expected/myfile2 b/test/integration/forcePushMultiple/expected/myfile2 new file mode 100644 index 000000000..180cf8328 --- /dev/null +++ b/test/integration/forcePushMultiple/expected/myfile2 @@ -0,0 +1 @@ +test2 diff --git a/test/integration/forcePushMultiple/expected_remote/HEAD b/test/integration/forcePushMultiple/expected_remote/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/test/integration/forcePushMultiple/expected_remote/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/test/integration/forcePushMultiple/expected_remote/config b/test/integration/forcePushMultiple/expected_remote/config new file mode 100644 index 000000000..c51ded5d7 --- /dev/null +++ b/test/integration/forcePushMultiple/expected_remote/config @@ -0,0 +1,8 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true + ignorecase = true + precomposeunicode = true +[remote "origin"] + url = /Users/jesseduffieldduffield/go/src/github.com/jesseduffield/lazygit/test/integration/forcePushMultiple/./actual diff --git a/test/integration/forcePushMultiple/expected_remote/description b/test/integration/forcePushMultiple/expected_remote/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/test/integration/forcePushMultiple/expected_remote/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/test/integration/forcePushMultiple/expected_remote/info/exclude b/test/integration/forcePushMultiple/expected_remote/info/exclude new file mode 100644 index 000000000..8e9f2071f --- /dev/null +++ b/test/integration/forcePushMultiple/expected_remote/info/exclude @@ -0,0 +1,7 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ +.DS_Store diff --git a/test/integration/forcePushMultiple/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/forcePushMultiple/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 new file mode 100644 index 0000000000000000000000000000000000000000..7f2ebf4eeb6ad6875bcc2a2b91ca3345ee06b45e GIT binary patch literal 52 zcmb ~ZE#08nZNMgRZ+ literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/forcePushMultiple/expected_remote/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce new file mode 100644 index 0000000000000000000000000000000000000000..0a734f98100d24e67455a3cfa8497adaccc7a422 GIT binary patch literal 103 zcmV-t0GR)H0V^p=O;s>7Fl8__FfcPQQOK=K%gjkNWLUcA@n6-{8($(qqj>V2E(CbB zbYDeLV#FZ9^TVh?Y2Ue*s}_Y<^|!pzo^PR!qQsctem1Z6nX+eZ_)jSuQWx;@*VuJL J8UTCqE3ZN5G4lWb literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 b/test/integration/forcePushMultiple/expected_remote/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 new file mode 100644 index 000000000..31d3fad7a --- /dev/null +++ b/test/integration/forcePushMultiple/expected_remote/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 @@ -0,0 +1,3 @@ +x崕A + E祸叛扫J!C &眄蝴<黣痷m"^谏瑩wi坆Ja朒)J&Gk婡闔'亢H%?0| !Hq們R慱2n淆杂i~'誧阚沧{呃嘈`瘊 +`岅礋j黦]寨[屷9 \ No newline at end of file diff --git a/test/integration/forcePushMultiple/expected_remote/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/forcePushMultiple/expected_remote/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 new file mode 100644 index 0000000000000000000000000000000000000000..285df3e5fbab12262e28d85e78af8a31cd0024c1 GIT binary patch literal 21 ccmb `~^A08nuUMF0Q* literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 b/test/integration/forcePushMultiple/expected_remote/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 new file mode 100644 index 0000000000000000000000000000000000000000..96d2e71a6af75cdd27ac5d9628a27faecc40fb66 GIT binary patch literal 77 zcmV-T0J8sh0V^p=O;s>AU@$Z=Ff%bx$gNDv%t B=N-?^8o7KK;!x4hDxZ=ntVWIZ01*pecg literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/b8/2ed4a67bef9ef50807adf409f103ef7b0832ab b/test/integration/forcePushMultiple/expected_remote/objects/b8/2ed4a67bef9ef50807adf409f103ef7b0832ab new file mode 100644 index 0000000000000000000000000000000000000000..55c8270daa81e5e4cdcaa1b2eeeabcb4f7b732e1 GIT binary patch literal 149 zcmV;G0BZku0gaA93c@fD06pgwxeJobrp*RKgr540WV4F}V@rvkzqe2DG%(Czcx`Rz z7E(C%UBvnV5t&A)8W1%HRLvDo$uSiK&%;3$v*lf0-3DKSBUWX06l?YXFlds(K1qt> zkbRLtX!5&1*4<9Cy-xF8KDljAx$xR<7REprT%c&r0M41i9#dWZ%uW01@)R^bRRB9O DRux1N literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 b/test/integration/forcePushMultiple/expected_remote/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 new file mode 100644 index 0000000000000000000000000000000000000000..5e9361d3548aa14bca5d35e0871b31e326387c70 GIT binary patch literal 103 zcmV-t0GR)H0V^p=O;s>7Fl8__FfcPQQOK=K%gjkNWLUcA@n6-{8($(qqj>V2E(CbB zbYDeLV#FZ9^TVh?Y2Ue*s}_Y<^|!pzo^PR!qQr#ZlF88r;s1<|mAy)TaoXZbQtYkQ JApo0YFGO2mGTHzD literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/forcePushMultiple/expected_remote/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 new file mode 100644 index 0000000000000000000000000000000000000000..d39fa7d2fecf1c45a132dfe3a8758952f3c8d968 GIT binary patch literal 21 ccmb }lpN08nuUO8@`> literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/d3/708eeec2b9d69acbe87862330e844e85f77de1 b/test/integration/forcePushMultiple/expected_remote/objects/d3/708eeec2b9d69acbe87862330e844e85f77de1 new file mode 100644 index 0000000000000000000000000000000000000000..e36f500bdd0daf555f8c0a188d92b5d2cc80531d GIT binary patch literal 149 zcmV;G0BZku0gaAJ3c@fDKwak)*$a|MCO;4ny6Q0|lL;1#EhU29-X6j2 b`B2}Ua^bb#Gz3fz&5_k-0AtiakEtPl>Z*U+@)T4*8fiM= D)tx}L literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/forcePushMultiple/expected_remote/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b new file mode 100644 index 0000000000000000000000000000000000000000..9b771fc2f6f41f91b00976b4ff3f8f9935f7931e GIT binary patch literal 21 ccmb >`CU&08otwO#lD@ literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected_remote/packed-refs b/test/integration/forcePushMultiple/expected_remote/packed-refs new file mode 100644 index 000000000..07ff7e761 --- /dev/null +++ b/test/integration/forcePushMultiple/expected_remote/packed-refs @@ -0,0 +1,3 @@ +# pack-refs with: peeled fully-peeled sorted +42d408cffcc087da21115f9ebc29e9765a2beb83 refs/heads/master +42d408cffcc087da21115f9ebc29e9765a2beb83 refs/heads/other_branch diff --git a/test/integration/forcePushMultiple/expected_remote/refs/heads/master b/test/integration/forcePushMultiple/expected_remote/refs/heads/master new file mode 100644 index 000000000..f9339e7e2 --- /dev/null +++ b/test/integration/forcePushMultiple/expected_remote/refs/heads/master @@ -0,0 +1 @@ +42d408cffcc087da21115f9ebc29e9765a2beb83 diff --git a/test/integration/forcePushMultiple/expected_remote/refs/heads/other_branch b/test/integration/forcePushMultiple/expected_remote/refs/heads/other_branch new file mode 100644 index 000000000..f9339e7e2 --- /dev/null +++ b/test/integration/forcePushMultiple/expected_remote/refs/heads/other_branch @@ -0,0 +1 @@ +42d408cffcc087da21115f9ebc29e9765a2beb83 diff --git a/test/integration/forcePushMultiple/recording.json b/test/integration/forcePushMultiple/recording.json new file mode 100644 index 000000000..dd0070f15 --- /dev/null +++ b/test/integration/forcePushMultiple/recording.json @@ -0,0 +1 @@ +{"KeyEvents":[{"Timestamp":591,"Mod":0,"Key":256,"Ch":80},{"Timestamp":1207,"Mod":0,"Key":13,"Ch":13},{"Timestamp":1990,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":272,"Height":74}]} \ No newline at end of file diff --git a/test/integration/forcePushMultiple/setup.sh b/test/integration/forcePushMultiple/setup.sh new file mode 100644 index 000000000..3c599991f --- /dev/null +++ b/test/integration/forcePushMultiple/setup.sh @@ -0,0 +1,54 @@ +#!/bin/sh + +set -e + +set -e + +cd $1 + +git init + +git config user.email "CI@example.com" +git config user.name "CI" +git config push.default matching + +echo test1 > myfile1 +git add . +git commit -am "myfile1" +echo test2 > myfile2 +git add . +git commit -am "myfile2" + +git checkout -b other_branch +git checkout master + +cd .. +git clone --bare ./actual actual_remote + +cd actual + +git remote add origin ../actual_remote +git fetch origin +git branch --set-upstream-to=origin/master master +git branch --set-upstream-to=origin/other_branch other_branch + +echo test3 > myfile3 +git add . +git commit -am "myfile3" + +git push origin master +git reset --hard HEAD^ + +git checkout other_branch + +echo test4 > myfile4 +git add . +git commit -am "myfile4" + +git push origin other_branch +git reset --hard HEAD^ + +git checkout master + +# at this point, both branches have diverged from their remote counterparts, meaning if you +# attempt to push either, it'll ask if you want to force push. diff --git a/test/integration/forcePushMultiple/test.json b/test/integration/forcePushMultiple/test.json new file mode 100644 index 000000000..f939494e9 --- /dev/null +++ b/test/integration/forcePushMultiple/test.json @@ -0,0 +1,4 @@ +{ + "description": "Force push to multiple branches because the user hasn't configured git to do otherwise", + "speed": 10 +} From 20ec6d98ad7581e985d066a37346f3193a44fc93 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sun, 27 Mar 2022 11:47:07 +1100 Subject: [PATCH 141/385] refactor integration tests --- .gitignore | 1 - pkg/integration/integration.go | 147 +++++++++--------- test/hooks/pre-push | 2 + .../{ => repo}/.git_keep/BISECT_ANCESTORS_OK | 0 .../{ => repo}/.git_keep/BISECT_EXPECTED_REV | 0 .../expected/{ => repo}/.git_keep/BISECT_LOG | 0 .../{ => repo}/.git_keep/BISECT_NAMES | 0 .../{ => repo}/.git_keep/BISECT_START | 0 .../{ => repo}/.git_keep/BISECT_TERMS | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../bisect/expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../{ => repo}/.git_keep/logs/refs/heads/test | 0 .../00/5ca78c7fb8157683fa61158235b250d2316004 | Bin .../00/750edc07d6415dcc07ae0351e9397b0222b7ba | Bin .../05/4bdf969fdcf1f90f1998666f628d40f72fde4f | 0 .../07/552205114379b7c1abd7cb39575cb7a30a2e8c | Bin .../0c/fbf08886fca9a91cb753ec8734c84fcbe52c9f | Bin .../11/0046b8d92b877def6cda61639cf8f37bc2829c | Bin .../12/e46e3c37d1a43a26b909a346ecd2d97677c641 | Bin .../1b/01733c2b372c7b5544c7f2293c3b7341824112 | Bin .../1e/8b314962144c26d5e0e50fd29d2ca327864913 | Bin .../20/9e3ef4b6247ce746048d5711befda46206d235 | Bin .../26/7465454f74736bbe5b493c7f69dd3d024e26e5 | Bin .../32/e7b0308424a817ed5aa5bba94b06b72a1b8ce5 | Bin .../39/983ea412adebe6c5a3d4451a7673cf0962c472 | 0 .../3c/032078a4a21c5c51d3c93d91717c1dabbb8cd0 | Bin .../3e/02ce90348f3386128ebb2972515fb1a3788818 | Bin .../3f/f8b0f3820fd2eb3da53a5b803f94caf30dc2ab | Bin .../43/78c740dfa0de7a973216b54b99c45a3c03f83c | Bin .../45/a4fb75db864000d01701c0f7a51864bd4daabf | Bin .../47/8a007451b33c7a234c60f0d13b164561b29094 | Bin .../48/082f72f087ce7e6fa75b9c41d7387daecd447b | Bin .../4b/65d66c089cd4f6bfa69dff2d7ba4c27337cd23 | Bin .../54/3c0ef66d928051f16f8b9d7d33d6c4ea1f4e4f | Bin .../5f/9397e5bcee1ac2a3fe6d834d42e36b74ef4ca8 | Bin .../60/d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 | Bin .../66/19c0a1a3eb6449eb15ce6cd0916fec0e410c10 | 0 .../67/fbfb3b74c2381ad1e058949231f2b4f0c8921f | Bin .../78/d41b2abbd2f52c1ebf2f496268a915d59eb27b | 0 .../7e/d6ff82de6bcc2a78243fc9c54d3ef5ac14da69 | Bin .../7f/8f011eb73d6043d2e6db9d2c101195ae2801f2 | Bin .../80/eeef1a7c49b376f3373ea26c6ba44d69d90d9c | Bin .../82/d721eb037f7045056023d0904989781ce1f526 | Bin .../83/51c19397f4fcd5238d10034fa7fa384f14d580 | Bin .../91/36f315e5952043f1e7ecdc0d28c208eaeaed71 | Bin .../96/202a92c1d3bde1b20d6f3dec8e742d09732b4d | Bin .../98/d9bcb75a685dfbfd60f611c309410152935b3d | Bin .../ae/95e9aa3b8881aedb7a526c86ec5d60f371ca6c | Bin .../af/f6316148f1524977997c486bcfe624c9094c4e | Bin .../b1/bd38b62a0800a4f6a80c34e21c5acffae52c7e | Bin .../b4/de3947675361a7770d29b8982c407b0ec6b2a0 | Bin .../b5/31696093a6482eca9ad4bcab63407172225b93 | 0 .../b6/a7d89c68e0ca66e96a9a51892cc33db66fb8a3 | Bin .../b8/626c4cff2849624fb67f87cd0ad72b163671ad | Bin .../b9/7844c9437a4ab69c8165cadd97bc597b43135b | Bin .../ba/8e7277a0ee7cdf84cd5c6138057adb85947a90 | Bin .../bc/21c8fabc28201fab6c60503168ecda25ad8626 | Bin .../d0/0491fd7e5bb6fa28c517a0bb32b8b506539d4d | Bin .../d1/f7a85555fe6f10dd44754d35459ae741cb107c | Bin .../d5/42aa84743f8ba1380358d4009408f03dbfb247 | Bin .../d6/b24041cf04154f8f902651969675021f4d93a5 | Bin .../d9/328d9b2c9536fdf01641dd03f4a254d2c86601 | Bin .../d9/cc608eedd5d2cc63c262272b7a0f6ab6aed5dd | Bin .../db/b21289ee21b2ff0f3de2bc7d00038b30c4e353 | Bin .../e5/9bbaffe94b06acaadab4245f30ff3e11c66e5b | Bin .../e9/27f0f9467e772eea36f24053c9b534303b106a | Bin .../e9/d2f825e793bc9ac2be698348dbe669bad34cad | 0 .../ea/684d3f868c358400465f2ec16a640c319ea6a3 | Bin .../eb/e59a71e9750e75fb983f241687cdf7f0c8ce94 | Bin .../ec/635144f60048986bc560c5576355344005e6e7 | Bin .../f2/7c6ae26adb8396d3861976ba268f87ad8afa0b | Bin .../f5/99e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 | Bin .../expected/{ => repo}/.git_keep/packed-refs | 0 .../{ => repo}/.git_keep/refs/bisect/bad | 0 ...d-39983ea412adebe6c5a3d4451a7673cf0962c472 | 0 ...d-67fbfb3b74c2381ad1e058949231f2b4f0c8921f | 0 ...d-e927f0f9467e772eea36f24053c9b534303b106a | 0 ...d-e9d2f825e793bc9ac2be698348dbe669bad34cad | 0 ...p-bc21c8fabc28201fab6c60503168ecda25ad8626 | 0 ...p-d1f7a85555fe6f10dd44754d35459ae741cb107c | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../{ => repo}/.git_keep/refs/heads/test | 0 .../bisect/expected/{ => repo}/file | 0 .../{ => repo}/.git_keep/BISECT_ANCESTORS_OK | 0 .../{ => repo}/.git_keep/BISECT_EXPECTED_REV | 0 .../expected/{ => repo}/.git_keep/BISECT_LOG | 0 .../{ => repo}/.git_keep/BISECT_NAMES | 0 .../{ => repo}/.git_keep/BISECT_START | 0 .../{ => repo}/.git_keep/BISECT_TERMS | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../.git_keep/logs/refs/heads/other | 0 .../{ => repo}/.git_keep/logs/refs/heads/test | 0 .../00/750edc07d6415dcc07ae0351e9397b0222b7ba | Bin .../03/ecdaa424af1fdaeab1bd1852319652b9518f11 | Bin .../04/a577be2858b8024716876aefe6b665a98e1e4f | Bin .../05/57fc43da38567eae00831e9b385fd2cad22643 | Bin .../0c/fbf08886fca9a91cb753ec8734c84fcbe52c9f | Bin .../0d/1bbe8d012c8c070167a006a4898b525cfbd930 | Bin .../0f/373801691c466240bd131d28b2168712b045ba | 0 .../10/e171beacb963e4f8a4dc1d80fd291c135902bb | Bin .../11/e4fd4011c9ed3800bb33b85580dd1d09f6aefd | Bin .../15/d4c5b8608fe472fd224333e60d44ea826cc80e | Bin .../1a/35564b85e24c96e647b477aaf8d35dcf0de84d | Bin .../1a/b342c03b4226cca1c751dba71fa2df0e7d82ee | Bin .../1e/8b314962144c26d5e0e50fd29d2ca327864913 | Bin .../20/9e3ef4b6247ce746048d5711befda46206d235 | Bin .../26/661287266e53bda69d8daa3aac1f714650f13c | Bin .../30/68d0d730547aaa5b86dbfe638db83133ae1421 | Bin .../31/df6c951dc82b75b11bc48836e780134a16e6ad | Bin .../33/3ff293caf2d3216edf22e3f1df64d43a7e1311 | Bin .../36/903784186b1b8b4a150dc656eccd49f94e114e | Bin .../38/242e5215bc35b3e418c1d6d63fd0291001e10b | 0 .../3a/05ed1ca9671bc362c7197eb09bddff040c9110 | Bin .../3b/e94d6b1b1b3b63db9e412b2e788d08979bc176 | Bin .../3c/032078a4a21c5c51d3c93d91717c1dabbb8cd0 | Bin .../3f/bb9e626d4b7d30e58346b3eefaa342b15ab776 | Bin .../3f/d9ad29c185eac6106cfa005a3aa594e21b9e06 | Bin .../43/99b07bd31d1f58a0ff10b5434d5ff4f36e38fb | Bin .../45/a4fb75db864000d01701c0f7a51864bd4daabf | Bin .../48/082f72f087ce7e6fa75b9c41d7387daecd447b | Bin .../4a/9e01012c736e5e0998b7184d9a54e8c610ed02 | Bin .../54/93d27d38b9902cf28b1035c644bf470df76060 | Bin .../60/d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 | Bin .../6f/a769bf11bd9dc4ff4e85f4951950b0bc34326f | 0 .../74/cd0e856d938eb6b665284c5485c00f87e20dc5 | Bin .../7c/fd51ebd06287effcfdab241235305cb6439d40 | Bin .../7e/d6ff82de6bcc2a78243fc9c54d3ef5ac14da69 | Bin .../7f/8f011eb73d6043d2e6db9d2c101195ae2801f2 | Bin .../83/51c19397f4fcd5238d10034fa7fa384f14d580 | Bin .../88/8633a131a49f1b8981d70c13d666defed6ba15 | Bin .../8b/0156bd25a1ecd82ef7c4c53e9d6d312bb6d403 | Bin .../90/dfebd90b0a89766c39928f22901b8c02b51fda | 0 .../98/d9bcb75a685dfbfd60f611c309410152935b3d | Bin .../9c/836a5c3f513818d300b410f8cb3a2e3bbd42a1 | Bin .../9d/33ec0915534bf6401be9412203697791e40a04 | 0 .../b1/bd38b62a0800a4f6a80c34e21c5acffae52c7e | Bin .../b2/970eba9fd8dba8655094dc38fb4ee50b9bf23e | Bin .../b4/de3947675361a7770d29b8982c407b0ec6b2a0 | Bin .../b6/14152a335aabd8b5daa2c6abccc9425eb14177 | 0 .../b6/a7d89c68e0ca66e96a9a51892cc33db66fb8a3 | Bin .../b8/626c4cff2849624fb67f87cd0ad72b163671ad | Bin .../cd/c58c0f95a2313ded9185e102bc35253f6a1bed | Bin .../d0/0491fd7e5bb6fa28c517a0bb32b8b506539d4d | Bin .../d2/7a997859219951ecc95c351174c70ea0cf9d37 | 0 .../d3/6e09d97bf2c1527118bde353ad64b157f8b269 | 0 .../d4/e982570808a24722649e852a92bda5cf54c9dd | Bin .../d6/b24041cf04154f8f902651969675021f4d93a5 | Bin .../d8/4e0684b1038552d5c8d86e67398d634f77ad3b | Bin .../da/8dacb2a073ebc2adeddceb3cc2b39b6c95c858 | Bin .../db/76c03074879025735b647b825786a7b3fcfe7c | Bin .../e5/59f83c6e8dd11680de70b487725e37ff2e283f | 0 .../e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 | Bin .../ec/635144f60048986bc560c5576355344005e6e7 | Bin .../f5/99e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 | Bin .../ff/231021500c7beb87de0d6d5edc29b6f9c000b1 | Bin .../expected/{ => repo}/.git_keep/packed-refs | 0 .../{ => repo}/.git_keep/refs/bisect/bad | 0 ...d-38242e5215bc35b3e418c1d6d63fd0291001e10b | 0 ...d-3fbb9e626d4b7d30e58346b3eefaa342b15ab776 | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../{ => repo}/.git_keep/refs/heads/other | 0 .../{ => repo}/.git_keep/refs/heads/test | 0 .../expected/{ => repo}/myfile | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../{ => repo}/.git_keep/logs/refs/heads/four | 0 .../.git_keep/logs/refs/heads/master | 0 .../{ => repo}/.git_keep/logs/refs/heads/one | 0 .../.git_keep/logs/refs/heads/three | 0 .../{ => repo}/.git_keep/logs/refs/heads/two | 0 .../b4/9fda1c7a9af6a4f0b6b07a2cb31aecb8c01a6c | Bin .../e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 | Bin .../f7/53f4dfc98d148a7e685c46c8d148bcac56707d | Bin .../{ => repo}/.git_keep/refs/heads/four | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../{ => repo}/.git_keep/refs/heads/one | 0 .../{ => repo}/.git_keep/refs/heads/three | 0 .../{ => repo}/.git_keep/refs/heads/two | 0 .../expected/{ => repo}/myfile.txt | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../.git_keep/logs/refs/heads/new-branch | 0 .../.git_keep/logs/refs/heads/new-branch-2 | 0 .../.git_keep/logs/refs/heads/new-branch-3 | 0 .../.git_keep/logs/refs/heads/old-branch | 0 .../.git_keep/logs/refs/heads/old-branch-3 | 0 .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../21/b436d66d2c515ad17285e53d9e6380d599b044 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../.git_keep/refs/heads/new-branch | 0 .../.git_keep/refs/heads/new-branch-2 | 0 .../.git_keep/refs/heads/new-branch-3 | 0 .../.git_keep/refs/heads/old-branch | 0 .../.git_keep/refs/heads/old-branch-3 | 0 .../branchDelete/expected/{ => repo}/file0 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/develop | 0 .../.git_keep/logs/refs/heads/master | 0 .../09/cbe8c6717c06a61876b7b641a46a62bf3c585d | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1b/9ae5f5dff631baaa180a30afd9983f83dc27ca | Bin .../21/78af7503938665881174069be4d48fa483e4af | Bin .../2e/83133d8d6b88c588de66c3ff8405501b5215b4 | Bin .../34/c74161eef968fc951cf170a011fa8abfeddbcd | Bin .../36/27f93f3cc779dc2f99484fb8ffa49953e43b2f | Bin .../3e/1706cdf670f5641be0715178471abfc9ed1748 | 0 .../42/1b29bba240f23ea39e216bb0873cd4012624b5 | Bin .../42/597904331c82f6d5c8c902755c8dfa5767ea95 | Bin .../4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 | 0 .../5d/874a902548f753e50944827e572a7470aa9731 | Bin .../5f/3e4598b46a912f0f95a4898743e979343c82f3 | Bin .../60/91d709b275e712111d016d9b3a4fb44e63f1f6 | Bin .../69/f11ae88c8712fe38ffd0fe9ff9df05371500a6 | Bin .../70/95508e3cd0fd40572f8e711170db38ef2342d7 | Bin .../7a/45b8933308e43f2597ee5d290862a62a9b46b3 | Bin .../88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 | Bin .../8c/7a45270a95d66c8e3b843df3f466be5dc19960 | Bin .../8d/3bd1cbd5560c759c78a948bc0d24acb9cfae73 | 0 .../9a/6521a3788b4d9e679b1709130ff8dc3f73ab18 | 0 .../9d/e8260b738a34a74533df54f2e404276aa96242 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a8/381c9130b03aef530b60b5a4546b93dc59ae12 | 0 .../cb/289e645aed5251ce74fa2eaf0cd1145b9cb014 | Bin .../cc/52f7d833c761b3b11a5fa1ae76ba9aba2edd6f | 0 .../dc/d348507ba1da8f6479b9d964daa302b2fb9d9c | 0 .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e3/ae5c6d8407e8307b9bc77923be78c901408f6e | Bin .../e4/666ba294866d5c16f9afebcacf8f4adfee7439 | Bin .../e9/57aaf2eef0c03a9052b472d4862d9ee684c3e5 | Bin .../f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 | Bin .../f5/067da83b48f8588edce682fd2715a575f34373 | 0 .../fe/427b52bbbe9dac81b463a162f37ab979ca772b | Bin .../{ => repo}/.git_keep/refs/heads/develop | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/directory/file | 0 .../expected/{ => repo}/directory/file2 | 0 .../branchRebase/expected/{ => repo}/file1 | 0 .../branchRebase/expected/{ => repo}/file3 | 0 .../branchRebase/expected/{ => repo}/file4 | 0 .../branchRebase/expected/{ => repo}/file5 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/develop | 0 .../.git_keep/logs/refs/heads/master | 0 .../09/cbe8c6717c06a61876b7b641a46a62bf3c585d | Bin .../10/6606554f129e8b6e4b942908734deef5628dcd | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1b/9ae5f5dff631baaa180a30afd9983f83dc27ca | Bin .../21/78af7503938665881174069be4d48fa483e4af | Bin .../27/ba706fa463253f9189b2f258430877d2b5ed4f | 0 .../34/c74161eef968fc951cf170a011fa8abfeddbcd | Bin .../37/14b55ba17f3d8b0233c6e5924a5e497eb09bb7 | Bin .../4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 | 0 .../5f/3e4598b46a912f0f95a4898743e979343c82f3 | Bin .../60/91d709b275e712111d016d9b3a4fb44e63f1f6 | Bin .../7a/45b8933308e43f2597ee5d290862a62a9b46b3 | Bin .../7c/d86f0c3e1894b4270d0bf9fa246c33568f9bf1 | 0 .../88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 | Bin .../8b/24e74245461f6ad529c77c040fe17e415cf3da | Bin .../8c/7a45270a95d66c8e3b843df3f466be5dc19960 | Bin .../9d/e8260b738a34a74533df54f2e404276aa96242 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/3e01f9d181ff16b3d821dd962e98accbd62936 | Bin .../bd/8db1919bbbbd4509ad4d9fa3baf546460e17a2 | Bin .../c2/3c3e0496a9b3decc42344bfd94514f0834b93c | Bin .../cb/289e645aed5251ce74fa2eaf0cd1145b9cb014 | Bin .../dc/d348507ba1da8f6479b9d964daa302b2fb9d9c | 0 .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e3/ae5c6d8407e8307b9bc77923be78c901408f6e | Bin .../e4/666ba294866d5c16f9afebcacf8f4adfee7439 | Bin .../ee/a0cf47f42fe8d027b4cecaf534ecc0673f7981 | 0 .../f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 | Bin .../fe/427b52bbbe9dac81b463a162f37ab979ca772b | Bin .../{ => repo}/.git_keep/refs/heads/develop | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/directory/file | 0 .../expected/{ => repo}/directory/file2 | 0 .../branchReset/expected/{ => repo}/file1 | 0 .../branchReset/expected/{ => repo}/file3 | 0 .../branchReset/expected/{ => repo}/file4 | 0 .../branchReset/expected/{ => repo}/file5 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../.git_keep/logs/refs/heads/new-branch | 0 .../.git_keep/logs/refs/heads/new-branch-2 | 0 .../.git_keep/logs/refs/heads/new-branch-3 | 0 .../.git_keep/logs/refs/heads/old-branch | 0 .../.git_keep/logs/refs/heads/old-branch-2 | 0 .../.git_keep/logs/refs/heads/old-branch-3 | 0 .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../75/e9e90a1d58c37d97d46a543dfbfd0f33fc52d8 | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../.git_keep/refs/heads/new-branch | 0 .../.git_keep/refs/heads/new-branch-2 | 0 .../.git_keep/refs/heads/new-branch-3 | 0 .../.git_keep/refs/heads/old-branch | 0 .../.git_keep/refs/heads/old-branch-2 | 0 .../.git_keep/refs/heads/old-branch-3 | 0 .../expected/{ => repo}/file0 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/REBASE_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/base_branch | 0 .../.git_keep/logs/refs/heads/develop | 0 .../logs/refs/heads/feature/cherry-picking | 0 .../.git_keep/logs/refs/heads/master | 0 .../.git_keep/logs/refs/heads/other_branch | 0 .../05/56e5da1cda4e150d6cc1182be6efdb061f59fe | Bin .../09/cbe8c6717c06a61876b7b641a46a62bf3c585d | Bin .../16/f2bcca6ce7bcc17277103a5555072a6c3322a2 | 0 .../17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 | Bin .../17/4a8c9444cfa700682d74059d9fa9be5749242c | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 | Bin .../19/079c78db18112c5a2720896a040014a2d05f6d | Bin .../1b/9ae5f5dff631baaa180a30afd9983f83dc27ca | Bin .../20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 | Bin .../21/28c3c3def18d6e2a389957252fdb69ba85fce0 | Bin .../21/78af7503938665881174069be4d48fa483e4af | Bin .../22/b0fd807dd5e428c2d818aef6a2311d7c11e885 | Bin .../23/4e2fa9a01b8d7e849b0c2a1bbd550e788ea18d | 0 .../24/6f7487e08e6330ccbec4053e701145d53f64d4 | Bin .../24/93c87610e0a9b8edfca592cb01a027f60ce587 | 0 .../2c/f63d6da8c52131dd79622f8572b44a1267e420 | Bin .../2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 | Bin .../33/9e2d062760be9ecdb4bb90f97bdb0e634e7831 | 0 .../34/c74161eef968fc951cf170a011fa8abfeddbcd | Bin .../36/e0ef3e52c6e29e64980c71defbab6064d2da8c | Bin .../3e/0d4389ab458a8643281e494e3ebae7ce307eec | 0 .../45/20f99d650662a3f597a200fea5f2599f528180 | 0 .../4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 | 0 .../5d/2484f3cb6ce658e296526c48e1a376b2790dfc | Bin .../5d/a4d9200457542d875fe4def54ac98c16332db0 | Bin .../5f/3e4598b46a912f0f95a4898743e979343c82f3 | Bin .../60/91d709b275e712111d016d9b3a4fb44e63f1f6 | Bin .../61/01e935461d4cd862ae4a720846e87880d198b9 | Bin .../65/c0438e428cd1aa94588eaa52eb7ebad7ec62fd | Bin .../68/728b56ed31d03ca94496b9e2a45c62ba0f4e8f | 0 .../69/6a8fd43c580b3bed203977faab4566b052a4e4 | Bin .../6b/6092c6840d05583489cc32a1260db0d5390a98 | Bin .../73/17cf7580efd92f974c8dfb3cde84eded8dafec | 0 .../78/3666de4acbb22a9efc205197667f5136118c54 | Bin .../78/a5ec82970200538b70f5ac61c18acb45ccb8ee | 0 .../79/23e4a952f4b169373b0389be6a9db3cd929547 | 0 .../88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d | Bin .../88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 | Bin .../90/a84fd62f8033027fab3e567a81d5ed2a6a71cd | Bin .../95/9d7a10da71acf97b17300b40a3b4f30903e09c | Bin .../9b/b8cd97914c8e8a7b8a6ec6f94bca0b09fa0048 | Bin .../9d/e8260b738a34a74533df54f2e404276aa96242 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../af/a76754c933269d7cd45630a7184a20849dbe9c | Bin .../b4/121e2d6aa156227b6541431ddfb8594904b520 | Bin .../b8/ab98a9ab0599193a3f41a9cc5cb988283e6722 | Bin .../bd/6f34089ba29cbae102003bd973e9f37a235c2e | Bin .../bf/cc5725cd2ef871ff804996f4e02beef3e4dec2 | 0 .../c1/dd146476a4a37fff75b88612a718281ea83b58 | Bin .../ce/ecbe69460104e09eb2cd7c865df520c5679a68 | Bin .../d0/60f7226715ca55b04e91fad2b8aca01badd993 | Bin .../d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 | Bin .../d8/e5ca46d2bbd7c115e5849e637efe2361203368 | 0 .../da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 | Bin .../dc/d348507ba1da8f6479b9d964daa302b2fb9d9c | 0 .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e3/ae5c6d8407e8307b9bc77923be78c901408f6e | Bin .../e4/48ae5bf6371d80ebee24a22b6df341797a6511 | Bin .../e4/666ba294866d5c16f9afebcacf8f4adfee7439 | Bin .../e4/aa98b835d0a871d9ea02e6d286f0fbb2204cdc | 0 .../ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d | Bin .../eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 | Bin .../ef/029771f117b5f31c972dfa546037662e243ca7 | Bin .../f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 | Bin .../f3/7d8713ef1390c277b45a084a08c0c142ff7ed9 | 0 .../f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 | Bin .../f4/ffac820a371104fe611d81bc13a45b70a3ebb3 | Bin .../fa/cb56c48e4718f71c08116153c93d87bc699671 | 0 .../fd/31cea7e0b6e8d334280be34db8dd86cdda3007 | Bin .../.git_keep/refs/heads/base_branch | 0 .../{ => repo}/.git_keep/refs/heads/develop | 0 .../refs/heads/feature/cherry-picking | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../.git_keep/refs/heads/other_branch | 0 .../expected/{ => repo}/cherrypicking3 | 0 .../expected/{ => repo}/cherrypicking4 | 0 .../expected/{ => repo}/cherrypicking5 | 0 .../expected/{ => repo}/directory/file | 0 .../expected/{ => repo}/directory/file2 | 0 .../cherryPicking/expected/{ => repo}/file | 0 .../cherryPicking/expected/{ => repo}/file1 | 0 .../cherryPicking/expected/{ => repo}/file3 | 0 .../cherryPicking/expected/{ => repo}/file4 | 0 .../cherryPicking/expected/{ => repo}/file5 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../commit/expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../14/40bc6cc888a09dca2329d1060eec6de78d9d21 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../30/a1ca3481fdec3245b02aeacfb72ddfe2a433be | Bin .../3d/f3d8761bc0f0828596b11845aeac175b7b7393 | 0 .../4b/a4f1ed711a9081fab21bc222469aa5176a01f8 | Bin .../4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../a7/d53cc21fd53100f955377be379423b0e386274 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e7/560e2cd4783a261ad32496cefed2d9f69a46e7 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../commit/expected/{ => repo}/myfile1 | 0 .../commit/expected/{ => repo}/myfile2 | 0 .../commit/expected/{ => repo}/myfile3 | 0 .../commit/expected/{ => repo}/myfile4 | 0 .../commit/expected/{ => repo}/myfile5 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../17/6069f0ded1db43eecb3b629a6077dba6c68295 | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../30/a1ca3481fdec3245b02aeacfb72ddfe2a433be | Bin .../37/128a3020849daa0847462d14c384cc74c42ae0 | Bin .../39/33a268c502712421b7bfa04888319d6f108574 | Bin .../4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f | Bin .../57/4013716a7f007a27b647b90cdbc78d006d792b | 0 .../9f/1b5440546da24daad7014ccf3e1f4d81f9414b | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/myfile1 | 0 .../expected/{ => repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../expected/{ => repo}/myfile4 | 0 .../expected/{ => repo}/myfile5 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../{ => repo}/.git_keep/logs/refs/heads/lol | 0 .../.git_keep/logs/refs/heads/master | 0 .../00/29f9bf66e346d47ede6a501abb5b82bee60096 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../99/01fd9b7766be600bed07f55f1794a759527a98 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../e1/cb250774fb8606d33062518d0ae03831130249 | Bin .../{ => repo}/.git_keep/refs/heads/lol | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/file0 | 0 .../expected/{ => repo}/file1 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../17/27eeb6864e52a8967a1a494099359dbdfcc235 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3a/1ee58e5736049ad5b9266715d3642614816c1f | 0 .../7e/03c9a9538a907c936de5c9a2154707b9ee541c | 0 .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../9e/aae8f342ca71c060b760870a715a6303905935 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../ab/15072795e72a2061bc40060494c3ca2138b297 | Bin .../b7/81ffd3aa940dde39f73c9149b67e2b128de085 | 0 .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../commitsRevert/expected/{ => repo}/file0 | 0 .../commitsRevert/expected/{ => repo}/file2 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../54/4efed4e669ec3bd64b44799175bffac95035f5 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../confirmQuit/expected/{ => repo}/myfile1 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../15/bdb2c31c825116ad5af06ee25517d90b24f13b | Bin .../20/f11a5545b04a86ca81f7a9967d5207349052d7 | Bin .../8a/2e45643093ea7cf7b06382e38470034c24e812 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../customCommands/expected/{ => repo}/blah | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../05/3cf208ac3728c36c6ed86f2a03a1fb72a8e6bc | Bin .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../4f/dfedfd9d406506be8b02f5b863dbc08d43cc9f | Bin .../54/28838691c97ac192c8b8e1c3f573d8541a94b6 | Bin .../7d/b446a082f8c10183f1f27178698f07f3750b6b | Bin .../7d/d93a4be3d27d40fbe791d6d77e0d2fedc4d785 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../ab/38b1ca116f77648925d952e731f419db360cdb | 0 .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../f7/08d3e3819470a69f6c8562ff1e68eef02f8cac | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/myfile1 | 0 .../expected/{ => repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../expected/{ => repo}/myfile4 | 0 .../expected/{ => repo}/output.txt | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/branch2 | 0 .../.git_keep/logs/refs/heads/master | 0 .../05/19814b4923f4639f1a47348b1539e3c5c54904 | Bin .../0c/2aa38e0600e0d2df09c2f84664d8a14f899879 | Bin .../14/4da8a531224129210249f43dded86056891506 | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../2d/00bd505971a8bc7318d98e003aee708a367c85 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a | Bin .../3d/b2086f780b1cf632eec29111ef395913a8ab2b | Bin .../57/51731b38a36f8eb54a4bb304522ca539e04522 | Bin .../59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 | Bin .../75/b31f81dd4387724638dbd3aff7380155c672cd | Bin .../8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 | Bin .../96/a6d041bbb131df0e74d179c3adcd2ace0e7f9c | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a1/00b407f33fd2e97a3cb6f62b68ed6b7cc6c676 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../d1/5e253139400c94b42fc266641d1698720d4ecf | 0 .../e5/c5c5583f49a34e86ce622b59363df99e09d4c6 | Bin .../e7/76522ac28860d2eba6fe98fa4fad67e798419a | Bin .../f6/77ef8a14ca2770e48129cc13acfa1c369908cc | 0 .../{ => repo}/.git_keep/refs/heads/branch2 | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../diffing/expected/{ => repo}/file0 | 0 .../diffing/expected/{ => repo}/file1 | 0 .../diffing/expected/{ => repo}/file2 | 0 .../diffing/expected/{ => repo}/file4 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/branch2 | 0 .../.git_keep/logs/refs/heads/master | 0 .../06/da465196938ea235323950ee451ffb36a431cf | Bin .../08/04f2069f5af172770da3d231be982ca320bf8b | Bin .../0c/2aa38e0600e0d2df09c2f84664d8a14f899879 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1b/74d64fe4055d4502ac600072586068b27d4aa7 | 0 .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../2d/00bd505971a8bc7318d98e003aee708a367c85 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a | Bin .../3d/b2086f780b1cf632eec29111ef395913a8ab2b | Bin .../59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 | Bin .../6d/04f5ed53b383c0a4c63cac168df557b6df1e44 | Bin .../7b/f3d13079ced18f5b00e29c48c777e23f687d0a | Bin .../8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a1/1d868e88adb55a48fc55ee1377b3255c0cd329 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../c6/756882cc166f52b096a5e4fb9e4f5d507870c8 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../e5/c5c5583f49a34e86ce622b59363df99e09d4c6 | Bin .../e7/76522ac28860d2eba6fe98fa4fad67e798419a | Bin .../e8/76c3dfe2826621bea1bd3c87c2b9e2be88e69e | Bin .../{ => repo}/.git_keep/refs/heads/branch2 | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../diffing2/expected/{ => repo}/file0 | 0 .../diffing2/expected/{ => repo}/file1 | 0 .../diffing2/expected/{ => repo}/file2 | 0 .../diffing2/expected/{ => repo}/file4 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/branch2 | 0 .../.git_keep/logs/refs/heads/master | 0 .../0c/2aa38e0600e0d2df09c2f84664d8a14f899879 | Bin .../13/d8ce6d541ffd4b323376e2530ccdd3bcc7b8d5 | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../1e/dd26fd03ee6243bd1513788874c6c57ef1d41a | 0 .../27/5e6a821120c07a9068a9701ed14a82eeed3117 | 0 .../2d/00bd505971a8bc7318d98e003aee708a367c85 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a | Bin .../3d/b2086f780b1cf632eec29111ef395913a8ab2b | Bin .../4e/2d07409901af28a47f5d3b126953a5fb8b36ee | 0 .../57/695899c35539821690c4c132bd0e872a01c192 | Bin .../59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 | Bin .../8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 | Bin .../93/b73046d6820607f1da09399b55a145d5389ab8 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../b2/5b8446022fb5fcded2bab1ed2b02828a5c4d0b | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../e5/c5c5583f49a34e86ce622b59363df99e09d4c6 | Bin .../e7/76522ac28860d2eba6fe98fa4fad67e798419a | Bin .../ff/b13702e6bc59e2806bc3a5f93500e46925b131 | Bin .../{ => repo}/.git_keep/refs/heads/branch2 | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../diffing3/expected/{ => repo}/file0 | 0 .../diffing3/expected/{ => repo}/file1 | 0 .../diffing3/expected/{ => repo}/file2 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/conflict | 0 .../.git_keep/logs/refs/heads/conflict_second | 0 .../11/bdfc142c42c6ffaa904890ab61ec76262ec9ca | 0 .../15/fe7f43604da957ffb663b4db95b60d0af66469 | Bin .../1c/9488b0e1b8abd1ec8645b3345bdac91290b464 | Bin .../26/80cfddbd9fa03c059ac60d2bec5e59a1c34281 | Bin .../2c/e75e2a24f7d6841a504cf3616ef5a59edb3a2d | Bin .../30/07c9c07bf80aaa72b1f1f704e7fea622446678 | Bin .../3f/7bd8f68987d4e16b8f6fa7f6b0738b42180d1f | Bin .../47/966dcaa8ee736e89279b895faf8707de898e04 | Bin .../48/f9387742d3cc3017c1a7e292c9187e35321753 | Bin .../4d/8452fc76beed0c7b15e40e45d06922bf746c5f | Bin .../59/cf7b78af9aab84813bcb0bc8be27fdd9216b2b | Bin .../5a/d28e22767f979da2c198dc6c1003b25964e3da | Bin .../5b/e4a414b32cf4204f889469942986d3d783da84 | Bin .../7a/22af9d1908d85e3c4b6d916a9b6c733c55c990 | Bin .../85/4f08fa802293e0679d07771547fe9fe5d159e8 | Bin .../89/44a13fdfc597e4cf1d23797df51977680f8e77 | Bin .../8c/82faa1358ce6cddba19d59b2924cbcc5ef1c8e | Bin .../90/7b308167f0880fb2a5c0e1614bb0c7620f9dc3 | Bin .../90/be1f3056c4f471f977a28497b8d4b392c55a02 | Bin .../98/e834e9cdae1191de7fafb2b6f334bddd0793e8 | Bin .../99/76d7948def8b082e9d20135d6a04624d711752 | 0 .../9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 | Bin .../9f/5118ee216a6e44728305f90633b0c0e2ad235c | Bin .../a1/be04124078e38a592c153942bf75edf210f1ed | Bin .../a1/e09c2fda67b9f8d4440073c0c33f6e45689b7c | Bin .../ab/addc0b9edd523c69166a2c9f3a9e31a4c873e3 | Bin .../c9/1b3b139ea108475c19839fcda3a4e33db4ccc9 | 0 .../ce/e08babc6b109f011f42eaba5f79e6e693c09e7 | Bin .../d4/d1b67951582a751c12ff7ea29ede7d37fd9ee8 | Bin .../d7/98b86744c3997c186e0f0dc666f02943c797a7 | Bin .../e9/55de60e73263440d4651e79e947ec8b2902373 | Bin .../fa/938d99f6ee5cc562cd0f33fa64fd68d78ce2e9 | Bin .../{ => repo}/.git_keep/refs/heads/conflict | 0 .../.git_keep/refs/heads/conflict_second | 0 .../expected/{ => repo}/both-added.txt | 0 .../expected/{ => repo}/both-modded.txt | 0 .../expected/{ => repo}/change-delete.txt | 0 .../{ => repo}/changed-them-added-us.txt | 0 .../expected/{ => repo}/delete-change.txt | 0 .../expected/{ => repo}/deleted-staged.txt | 0 .../expected/{ => repo}/deleted-them.txt | 0 .../expected/{ => repo}/deleted.txt | 0 .../expected/{ => repo}/double-modded.txt | 0 .../expected/{ => repo}/modded-staged.txt | 0 .../expected/{ => repo}/modded.txt | 0 .../expected/{ => repo}/renamed.txt | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../00/cbccfd35a05ef9373bba9d5633cf6e67f83dd5 | Bin .../0a/91dcf3772f7fd7409b3df04eb6ef177219303a | 0 .../0c/db6daba7e25b6d6d10da326e0ab74401021370 | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../18/e987d34afb121659724591cd709e2a789184fc | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../22/5ad83faa797c1831a2bc956a21e2d472f21443 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../42/786aead9ca20a3427c38e5e5262fa787ce9868 | Bin .../78/80a9728615a4d196df39600a0c8c71b40d96d6 | Bin .../7b/8a8396be4352039598acb43acaadc1c380551f | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../af/6725ba23f43a286deff0747476d7874113df1e | 0 .../b7/a702b642978f2a9b1af9c1c67b22127af78c92 | 0 .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../d1/4505f281a54cda96fc5fb8cd4b4ee14bae6264 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/file0 | 0 .../expected/{ => repo}/file1 | 0 .../expected/{ => repo}/file2 | 0 .../expected/{ => repo}/file3 | 0 .../fetchPrune/expected/.git_keep/FETCH_HEAD | 1 - .../fetchPrune/expected/.git_keep/index | Bin 137 -> 0 bytes .../fetchPrune/expected/.git_keep/logs/HEAD | 3 - .../expected/.git_keep/logs/refs/heads/master | 1 - .../.git_keep/logs/refs/heads/other_branch | 1 - .../.git_keep/logs/refs/remotes/origin/master | 1 - .../f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 | Bin 121 -> 0 bytes .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/heads/other_branch | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/{.git_keep => origin}/HEAD | 0 .../fetchPrune/expected/origin/config | 8 + .../{.git_keep => origin}/description | 0 .../{.git_keep => origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../75/f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 | 3 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../fetchPrune/expected/origin/packed-refs | 2 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../repo/.git_keep}/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 2 +- .../repo/.git_keep}/description | 0 .../fetchPrune/expected/repo/.git_keep/index | Bin 0 -> 137 bytes .../repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 3 + .../repo/.git_keep/logs/refs/heads/master | 1 + .../.git_keep/logs/refs/heads/other_branch | 1 + .../.git_keep/logs/refs/remotes/origin/master | 1 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../75/f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 | 3 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../expected/{ => repo}/.git_keep/packed-refs | 0 .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/heads/other_branch | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../fetchPrune/expected/{ => repo}/myfile1 | 0 .../f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 | Bin 121 -> 0 bytes .../fetchPrune/expected_remote/packed-refs | 2 - test/integration/fetchPrune/setup.sh | 8 +- test/integration/fetchPrune/test.json | 2 +- .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../22/adc4567aba3d1a0acf28b4cef312922d516aeb | Bin .../2e/a97a56215f6adbe991eaf0dcf61c7086880ea5 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../4b/9d1f9f9fc76b123a5c90cd8396390cac41a3e3 | Bin .../77/9de836a10ac879fa919f48d5dc4f4ce11528e2 | Bin .../84/b823dc5fc92fcf08eb8c8545716232ce49bd45 | Bin .../8b/476a1094290d7251c56305e199eb2a203d8682 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../af/3ef564e968dbe92fb4e08a67dd5f835f43d4e8 | Bin .../b7/c728d5b4e9dfc210ec19f0549f25c94b766e4e | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../d7/236d5f85ad303f5f23141661e4c8959610b70b | 0 .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../f2/4812da035a21812bc4c73018349ac2f0a6ec39 | 0 .../f3/d94fa1d4be39b8daae35b82525bf357aa712de | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../filterPath/expected/{ => repo}/file | 0 .../filterPath/expected/{ => repo}/file0 | 0 .../filterPath/expected/{ => repo}/file2 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../6c/dce80c062ba2c8f8758879834a936b84ead78c | Bin .../70/3f7069185227287623aaba7cdb0e56ae7a6c60 | Bin .../77/9de836a10ac879fa919f48d5dc4f4ce11528e2 | Bin .../84/b823dc5fc92fcf08eb8c8545716232ce49bd45 | Bin .../92/ec47058a2894afbbbd69c5f79bff20c503e686 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a5/c053a7a46bce2775edb371a9aa97424b542ab7 | Bin .../c5/f9a8793f15aa0db816944424adb4303eb036a8 | 0 .../c8/68546458601b9c71b76b893f9020ecf7405528 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e7/c2bd00356720683d5bc4362ef5b92655fa8914 | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../filterPath2/expected/{ => repo}/file | 0 .../filterPath2/expected/{ => repo}/file0 | 0 .../filterPath2/expected/{ => repo}/file1 | 0 .../filterPath2/expected/{ => repo}/file2 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/{ => repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../23/1410172e8f51138f06d8dff963898fb1e97b30 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../72/226d27a85fff688d32c134a22ebe650d6c2e41 | Bin .../77/9de836a10ac879fa919f48d5dc4f4ce11528e2 | Bin .../84/b823dc5fc92fcf08eb8c8545716232ce49bd45 | Bin .../8e/d4f7b4eae8cc97d9add459348cc95e936b8f25 | 0 .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../b3/5d7fa77c939890020952987eeb461f410297d8 | 0 .../c1/a1ba9d2873d7163606bb5fdf46e50975db042b | 0 .../c8/68546458601b9c71b76b893f9020ecf7405528 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../db/6681a3e9fb9fb6ef524771cdc763904dd2b54d | 0 .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../filterPath3/expected/{ => repo}/file | 0 .../filterPath3/expected/{ => repo}/file0 | 0 .../filterPath3/expected/{ => repo}/file1 | 0 .../filterPath3/expected/{ => repo}/file2 | 0 .../forcePush/expected/.git_keep/FETCH_HEAD | 1 - .../forcePush/expected/.git_keep/ORIG_HEAD | 1 - .../forcePush/expected/.git_keep/index | Bin 281 -> 0 bytes .../forcePush/expected/.git_keep/logs/HEAD | 5 - .../expected/.git_keep/logs/refs/heads/master | 5 - .../.git_keep/logs/refs/remotes/origin/master | 3 - .../1f/e60e6b7023a1b9751850f83ac5bda49ddd9278 | 5 - .../66/bd8d357f6226ec264478db3606bc1c4be87e63 | Bin 149 -> 0 bytes .../a9/848fd98935937cd7d3909023ed1b588ccd4bfb | Bin 149 -> 0 bytes .../ae/d1af42535c9c6a27b9f660119452328fddd7cd | 3 - .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/{.git_keep => origin}/HEAD | 0 .../expected/origin}/config | 2 +- .../{.git_keep => origin}/description | 0 .../{.git_keep => origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../55/58e3589b913d8280499a5f9bf698971a83c5bd | Bin 0 -> 121 bytes .../77/ead8cf99f5fa1084e9ffa40eb18f37157b22c8 | 2 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../b8/568c2ecaef7e2f47647057ad47b040e8c5df53 | 2 + .../ce/0848710343a75263ea72cb5bdfa666b9ecda68 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e3/8b0dbe9634034957d8ebe0088587abd9ae938d | Bin 0 -> 149 bytes .../forcePush/expected/origin/packed-refs | 2 + .../expected/origin/refs/heads/master | 1 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../repo/.git_keep}/HEAD | 0 .../expected/repo/.git_keep/ORIG_HEAD | 1 + .../expected/repo}/.git_keep/config | 2 +- .../repo/.git_keep}/description | 0 .../forcePush/expected/repo/.git_keep/index | Bin 0 -> 281 bytes .../repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 5 + .../repo/.git_keep/logs/refs/heads/master | 5 + .../.git_keep/logs/refs/remotes/origin/master | 3 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../55/58e3589b913d8280499a5f9bf698971a83c5bd | Bin 0 -> 121 bytes .../77/ead8cf99f5fa1084e9ffa40eb18f37157b22c8 | 2 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../b8/568c2ecaef7e2f47647057ad47b040e8c5df53 | 2 + .../ce/0848710343a75263ea72cb5bdfa666b9ecda68 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e3/8b0dbe9634034957d8ebe0088587abd9ae938d | Bin 0 -> 149 bytes .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../forcePush/expected/{ => repo}/myfile1 | 0 .../forcePush/expected/{ => repo}/myfile2 | 0 .../forcePush/expected/{ => repo}/myfile4 | 0 .../1f/e60e6b7023a1b9751850f83ac5bda49ddd9278 | 5 - .../66/bd8d357f6226ec264478db3606bc1c4be87e63 | Bin 149 -> 0 bytes .../a9/848fd98935937cd7d3909023ed1b588ccd4bfb | Bin 149 -> 0 bytes .../ae/d1af42535c9c6a27b9f660119452328fddd7cd | 3 - .../forcePush/expected_remote/packed-refs | 2 - .../expected_remote/refs/heads/master | 1 - test/integration/forcePush/setup.sh | 6 +- .../expected/.git_keep/FETCH_HEAD | 2 - .../expected/.git_keep/ORIG_HEAD | 1 - .../expected/.git_keep/index | Bin 209 -> 0 bytes .../expected/.git_keep/logs/HEAD | 10 -- .../expected/.git_keep/logs/refs/heads/master | 4 - .../.git_keep/logs/refs/heads/other_branch | 3 - .../.git_keep/logs/refs/remotes/origin/master | 3 - .../logs/refs/remotes/origin/other_branch | 3 - .../16/d8875e19987b16f1991a41fd3f4536d16f7cb4 | 2 - .../42/d408cffcc087da21115f9ebc29e9765a2beb83 | 3 - .../b8/2ed4a67bef9ef50807adf409f103ef7b0832ab | Bin 149 -> 0 bytes .../d3/708eeec2b9d69acbe87862330e844e85f77de1 | Bin 149 -> 0 bytes .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/heads/other_branch | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../refs/remotes/origin/other_branch | 1 - .../16/d8875e19987b16f1991a41fd3f4536d16f7cb4 | 2 - .../42/d408cffcc087da21115f9ebc29e9765a2beb83 | 3 - .../b8/2ed4a67bef9ef50807adf409f103ef7b0832ab | Bin 149 -> 0 bytes .../d3/708eeec2b9d69acbe87862330e844e85f77de1 | Bin 149 -> 0 bytes .../expected_remote/packed-refs | 3 - .../expected_remote/refs/heads/master | 1 - .../expected_remote/refs/heads/other_branch | 1 - .../forcePushMultiple/recording.json | 1 - .../expected/origin}/HEAD | 0 .../expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../7a/35f0bb6bd8dc18ae462465e51f02362ba6babe | 2 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../bd/739fb752ed02ccd49422196e31599c87ff90ad | Bin 0 -> 149 bytes .../ce/0848710343a75263ea72cb5bdfa666b9ecda68 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e6/7f344f42afdb79c87a590f22537160241d8d61 | Bin 0 -> 150 bytes .../fe/67c3eaf819025990d3688d5f147a064e669ca5 | Bin 0 -> 150 bytes .../expected/origin/packed-refs | 3 + .../expected/origin/refs/heads/master | 1 + .../expected/origin/refs/heads/other_branch | 1 + .../expected/repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 2 + .../expected/repo/.git_keep}/HEAD | 0 .../expected/repo/.git_keep/ORIG_HEAD | 1 + .../expected/repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 209 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 10 ++ .../repo/.git_keep/logs/refs/heads/master | 4 + .../.git_keep/logs/refs/heads/other_branch | 3 + .../.git_keep/logs/refs/remotes/origin/master | 3 + .../logs/refs/remotes/origin/other_branch | 3 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../7a/35f0bb6bd8dc18ae462465e51f02362ba6babe | 2 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../bd/739fb752ed02ccd49422196e31599c87ff90ad | Bin 0 -> 149 bytes .../ce/0848710343a75263ea72cb5bdfa666b9ecda68 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e6/7f344f42afdb79c87a590f22537160241d8d61 | Bin 0 -> 150 bytes .../fe/67c3eaf819025990d3688d5f147a064e669ca5 | Bin 0 -> 150 bytes .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/heads/other_branch | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../refs/remotes/origin/other_branch | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../forcePushMultipleMatching/recording.json | 1 + .../setup.sh | 6 +- .../test.json | 2 +- .../expected/origin}/HEAD | 0 .../expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../48/6301f318c84045827013a3c3246b8c6a319eb8 | Bin 0 -> 148 bytes .../49/ea44f3ec1792142714930c8e4c3073f137936c | Bin 0 -> 150 bytes .../81/bdc116083cd4b4655333f4eb94dc0320197082 | 3 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../c8/4375dda9d81c1f2103defe4384e31f859dac86 | 5 + .../ce/0848710343a75263ea72cb5bdfa666b9ecda68 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../expected/origin/packed-refs | 3 + .../expected/origin/refs/heads/master | 1 + .../expected/origin/refs/heads/other_branch | 1 + .../expected/repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 2 + .../expected/repo}/.git_keep/HEAD | 0 .../expected/repo/.git_keep/ORIG_HEAD | 1 + .../expected/repo/.git_keep/config | 21 +++ .../expected/repo}/.git_keep/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 209 bytes .../expected/repo}/.git_keep/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 10 ++ .../repo/.git_keep/logs/refs/heads/master | 4 + .../.git_keep/logs/refs/heads/other_branch | 3 + .../.git_keep/logs/refs/remotes/origin/master | 3 + .../logs/refs/remotes/origin/other_branch | 2 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../48/6301f318c84045827013a3c3246b8c6a319eb8 | Bin 0 -> 148 bytes .../49/ea44f3ec1792142714930c8e4c3073f137936c | Bin 0 -> 150 bytes .../81/bdc116083cd4b4655333f4eb94dc0320197082 | 3 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../c8/4375dda9d81c1f2103defe4384e31f859dac86 | 5 + .../ce/0848710343a75263ea72cb5bdfa666b9ecda68 | Bin 0 -> 103 bytes .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/heads/other_branch | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../refs/remotes/origin/other_branch | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../forcePushMultipleUpstream/recording.json | 1 + .../forcePushMultipleUpstream/setup.sh | 54 +++++++ .../forcePushMultipleUpstream/test.json | 4 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../46/f86259c48ec60496e43d9c962e32f40e7cdefb | Bin .../62/b35f5751dd871e0908247223d276b5efeb4cb4 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../e4/776798a2a73374b45e6321b60b5578b9fb590c | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/repo}/myfile1 | 0 .../initialOpen/expected/{ => repo}/myfile2 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/another | 0 .../.git_keep/logs/refs/heads/master | 0 .../.git_keep/logs/refs/heads/other | 0 .../1e/7d643e0db24ebee10f92aa2f8099d50dbe0f0f | Bin .../3c/3594b2fd655fb7ffe36077ee8a9c3f79fb5fc6 | Bin .../41/bed9f222cc54e68d7846dc010bea6d23bea33e | Bin .../61/3e54e7fd6e080d53ef44c18ecd33c545ac0e08 | Bin .../89/8618af3fef6edf472d0f4a483ed8010d7bcfbb | Bin .../98/f656b294e5f3b447e3fd66814a80d0d4080627 | Bin .../9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 | Bin .../a4/942a576eec3a1a15fb790c942b6860331bee32 | 0 .../a7/fd052c52f174943cdea637f2d11f5ab7d090cd | Bin .../ba/4581dc53b5b2ff56803651dfd79245203d546b | Bin .../be/5b46b808c9c808be26710daeb2ce9ed2c7a070 | Bin .../c5/af43f6cc1d51ebb3ab4800347595541f81799c | Bin .../d3/b35176a575d48743900b1f0863cefbc198f84c | Bin .../dd/ad764e9e78b555cd41e5e81f8ce969cfa3972c | 0 .../e5/265503c8aea2860fc4754c1025e4597530ce0e | 0 .../fa/0b6bf64815f57729716334319596c926b6564a | Bin .../{ => repo}/.git_keep/refs/heads/another | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../{ => repo}/.git_keep/refs/heads/other | 0 .../expected/{ => repo}/file1 | 0 .../expected/{ => repo}/file2 | 0 .../expected/{ => repo}/file4 | 0 .../expected/{ => repo}/file5 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/MERGE_HEAD | 0 .../expected/{ => repo}/.git_keep/MERGE_MODE | 0 .../expected/{ => repo}/.git_keep/MERGE_MSG | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/base_branch | 0 .../.git_keep/logs/refs/heads/develop | 0 .../logs/refs/heads/feature/cherry-picking | 0 .../.git_keep/logs/refs/heads/master | 0 .../.git_keep/logs/refs/heads/other_branch | 0 .../08/e2576bb7cd0dd9be54f9a523c4bedea0643557 | Bin .../09/cbe8c6717c06a61876b7b641a46a62bf3c585d | Bin .../17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 | Bin .../17/4a8c9444cfa700682d74059d9fa9be5749242c | Bin .../17/dc45dd142947e06cf7e635d62f2c0acbb86da7 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../18/c07ac9568c564ececb199f78f64babc92214cb | Bin .../18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 | Bin .../1b/9ae5f5dff631baaa180a30afd9983f83dc27ca | Bin .../20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 | Bin .../21/78af7503938665881174069be4d48fa483e4af | Bin .../22/b0fd807dd5e428c2d818aef6a2311d7c11e885 | Bin .../24/10ee12b940bade9d9e99413732faa6dc60adb1 | Bin .../24/6f7487e08e6330ccbec4053e701145d53f64d4 | Bin .../27/94411aa7b73b44f533fb862cdb9dbfd13c5d92 | Bin .../27/9f068805e089660f7ddd17ff32f66100e0dca5 | 0 .../2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 | Bin .../31/f2a971f823279ba1ef877be7599da288f6e24b | Bin .../32/d15fd4451b6693a93d6420c8af6cfc99348e71 | Bin .../34/c74161eef968fc951cf170a011fa8abfeddbcd | Bin .../36/e0ef3e52c6e29e64980c71defbab6064d2da8c | Bin .../38/08a710b52a152bb73805fe274e0d877cf61800 | 0 .../3d/1213374cd86b841f034768571d0b5f2c870a16 | Bin .../44/2a53c1b023b4816085fdc4eaa85d0c5fd897e2 | 0 .../4e/5d3ae0b6e865073bcbd79531a75c55bf7bfcb4 | 0 .../4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 | 0 .../5d/874a902548f753e50944827e572a7470aa9731 | Bin .../5d/a4d9200457542d875fe4def54ac98c16332db0 | Bin .../5d/c2e019349371e9b3e4f1be99754ba70094cad6 | 0 .../5f/3e4598b46a912f0f95a4898743e979343c82f3 | Bin .../60/91d709b275e712111d016d9b3a4fb44e63f1f6 | Bin .../61/01e935461d4cd862ae4a720846e87880d198b9 | Bin .../68/7ff9526e0d56fafe1445ee4c182a83afc3cc35 | Bin .../6d/fbfa4bd19cb38608681df40ebb3a78bd13a824 | 0 .../78/3666de4acbb22a9efc205197667f5136118c54 | Bin .../7b/c178be031c4645110e9accb4accf16902d2d7f | Bin .../82/db6d0e4502f489719ea0f3dbe7e14413c6d28a | 0 .../88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d | Bin .../88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 | Bin .../8c/d762c119834784fdbf97e9bb3b4c15e804ebaa | Bin .../90/a84fd62f8033027fab3e567a81d5ed2a6a71cd | Bin .../91/65a12a95d3b2b9b8a0374de787af169b2c339e | Bin .../95/9d7a10da71acf97b17300b40a3b4f30903e09c | Bin .../9d/e8260b738a34a74533df54f2e404276aa96242 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../af/a76754c933269d7cd45630a7184a20849dbe9c | Bin .../b4/121e2d6aa156227b6541431ddfb8594904b520 | Bin .../c1/dd146476a4a37fff75b88612a718281ea83b58 | Bin .../c2/7ef6b4964209a875191eca7e56605c8efa5eee | Bin .../c5/0f7e1375a30118c2886d4b31318579f3419231 | Bin .../c9/b473bec307b18fd94a913658f4d759be63ca47 | Bin .../ce/d01df5f1a270490c1b9d4efe5ceb0c53626279 | 0 .../d0/60f7226715ca55b04e91fad2b8aca01badd993 | Bin .../d2/5721fffa7dc911ff2a9102bef201db225e2f16 | Bin .../d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 | Bin .../da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 | Bin .../db/f5ab9a4fa3f976d266f3be50670aa83121b420 | 0 .../dc/d348507ba1da8f6479b9d964daa302b2fb9d9c | 0 .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e3/ae5c6d8407e8307b9bc77923be78c901408f6e | Bin .../e4/48ae5bf6371d80ebee24a22b6df341797a6511 | Bin .../e4/666ba294866d5c16f9afebcacf8f4adfee7439 | Bin .../ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d | Bin .../eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 | Bin .../f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 | Bin .../f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 | Bin .../fd/31cea7e0b6e8d334280be34db8dd86cdda3007 | Bin .../.git_keep/refs/heads/base_branch | 0 .../{ => repo}/.git_keep/refs/heads/develop | 0 .../refs/heads/feature/cherry-picking | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../.git_keep/refs/heads/other_branch | 0 .../expected/{ => repo}/cherrypicking1 | 0 .../expected/{ => repo}/cherrypicking2 | 0 .../expected/{ => repo}/cherrypicking3 | 0 .../expected/{ => repo}/cherrypicking4 | 0 .../expected/{ => repo}/cherrypicking5 | 0 .../expected/{ => repo}/cherrypicking6 | 0 .../expected/{ => repo}/cherrypicking7 | 0 .../expected/{ => repo}/cherrypicking8 | 0 .../expected/{ => repo}/cherrypicking9 | 0 .../expected/{ => repo}/directory/file | 0 .../expected/{ => repo}/directory/file2 | 0 .../expected/{ => repo}/file | 0 .../expected/{ => repo}/file1 | 0 .../expected/{ => repo}/file3 | 0 .../expected/{ => repo}/file4 | 0 .../expected/{ => repo}/file5 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/base_branch | 0 .../.git_keep/logs/refs/heads/develop | 0 .../logs/refs/heads/feature/cherry-picking | 0 .../.git_keep/logs/refs/heads/master | 0 .../.git_keep/logs/refs/heads/other_branch | 0 .../09/cbe8c6717c06a61876b7b641a46a62bf3c585d | Bin .../0b/2387a3f67ec050f6d4e08f379e3cbb0a9913f1 | Bin .../16/18ce1085acb41fd710e279ac38911aadfb0a09 | Bin .../17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 | Bin .../17/4a8c9444cfa700682d74059d9fa9be5749242c | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 | Bin .../1b/9ae5f5dff631baaa180a30afd9983f83dc27ca | Bin .../1f/bc3eb4b11cb89b204a593572c2e01462ca5a89 | 0 .../20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 | Bin .../21/78af7503938665881174069be4d48fa483e4af | Bin .../22/b0fd807dd5e428c2d818aef6a2311d7c11e885 | Bin .../24/10ee12b940bade9d9e99413732faa6dc60adb1 | Bin .../24/6f7487e08e6330ccbec4053e701145d53f64d4 | Bin .../27/94411aa7b73b44f533fb862cdb9dbfd13c5d92 | Bin .../2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 | Bin .../32/d15fd4451b6693a93d6420c8af6cfc99348e71 | Bin .../34/1cf8213827614a274c750cd7dec4307eb41de7 | Bin .../34/c74161eef968fc951cf170a011fa8abfeddbcd | Bin .../36/e0ef3e52c6e29e64980c71defbab6064d2da8c | Bin .../38/08a710b52a152bb73805fe274e0d877cf61800 | 0 .../49/7b1e236588f0e2674c9a5787abeb226abf3680 | Bin .../4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 | 0 .../55/9043765dc6c32c943b6278b4abbff1e6f52839 | 0 .../55/f688e6b47b7a5ca8ffc4e25b77c1af6222b503 | 0 .../56/2af0640203fb5a6e92c090d8d1ded26806d2c4 | Bin .../5d/874a902548f753e50944827e572a7470aa9731 | Bin .../5d/a4d9200457542d875fe4def54ac98c16332db0 | Bin .../5f/3e4598b46a912f0f95a4898743e979343c82f3 | Bin .../60/91d709b275e712111d016d9b3a4fb44e63f1f6 | Bin .../61/01e935461d4cd862ae4a720846e87880d198b9 | Bin .../61/db24350a92fa37b2fe35f13eb3dd3f7655f6cf | 0 .../78/3666de4acbb22a9efc205197667f5136118c54 | Bin .../88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d | Bin .../88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 | Bin .../90/a84fd62f8033027fab3e567a81d5ed2a6a71cd | Bin .../91/65a12a95d3b2b9b8a0374de787af169b2c339e | Bin .../95/9d7a10da71acf97b17300b40a3b4f30903e09c | Bin .../9d/e8260b738a34a74533df54f2e404276aa96242 | Bin .../a1/9ec0b99e516795f349033f09383f87be0b74e9 | 0 .../a1/e00cd67130c6f7e2b9bb7f23f0cda2b37eb30b | 0 .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../af/a76754c933269d7cd45630a7184a20849dbe9c | Bin .../b0/753bdba91b84e3f406e21dbc7deba8e98f1fc8 | Bin .../b2/d5312a06a9c56e9ada21c48a12f57ce8dd4c4a | 0 .../b4/121e2d6aa156227b6541431ddfb8594904b520 | Bin .../c1/dd146476a4a37fff75b88612a718281ea83b58 | Bin .../cc/19bee93215b6c20ab129fb2c006762d4ae1497 | Bin .../d0/60f7226715ca55b04e91fad2b8aca01badd993 | Bin .../d3/e2708327280097b5e1f8ab69309934b24f8b64 | 0 .../d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 | Bin .../da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 | Bin .../dc/d348507ba1da8f6479b9d964daa302b2fb9d9c | 0 .../dd/259e90c3748e269bdf1ee3ce537a006d2394aa | 0 .../df/2c0daa40dcba0dded361a25ff7806b13db59a6 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e3/ae5c6d8407e8307b9bc77923be78c901408f6e | Bin .../e4/48ae5bf6371d80ebee24a22b6df341797a6511 | Bin .../e4/666ba294866d5c16f9afebcacf8f4adfee7439 | Bin .../e5/63585cb87cc39b553ca421902d631ea8890118 | 0 .../ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d | Bin .../eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 | Bin .../ed/d4e2e50eb82125428b045c540a9194d934e180 | Bin .../f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 | Bin .../f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 | Bin .../f7/f30ea7f84d4521d3ce9cc08b780c7a1bf7cc5e | Bin .../f8/9097f0bd23eda6d8977c0edfae7f913ffc5db3 | Bin .../f8/dd12b796f400be7f59d9471670c3080f9c90a1 | 0 .../fd/31cea7e0b6e8d334280be34db8dd86cdda3007 | Bin .../.git_keep/refs/heads/base_branch | 0 .../{ => repo}/.git_keep/refs/heads/develop | 0 .../refs/heads/feature/cherry-picking | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../.git_keep/refs/heads/other_branch | 0 .../expected/{ => repo}/cherrypicking1 | 0 .../expected/{ => repo}/cherrypicking2 | 0 .../expected/{ => repo}/cherrypicking3 | 0 .../expected/{ => repo}/cherrypicking4 | 0 .../expected/{ => repo}/cherrypicking5 | 0 .../expected/{ => repo}/cherrypicking6 | 0 .../expected/{ => repo}/cherrypicking7 | 0 .../expected/{ => repo}/cherrypicking8 | 0 .../expected/{ => repo}/cherrypicking9 | 0 .../expected/{ => repo}/directory/file | 0 .../expected/{ => repo}/directory/file2 | 0 .../mergeConflicts/expected/{ => repo}/file | 0 .../mergeConflicts/expected/{ => repo}/file1 | 0 .../mergeConflicts/expected/{ => repo}/file3 | 0 .../mergeConflicts/expected/{ => repo}/file4 | 0 .../mergeConflicts/expected/{ => repo}/file5 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/base_branch | 0 .../.git_keep/logs/refs/heads/develop | 0 .../logs/refs/heads/feature/cherry-picking | 0 .../.git_keep/logs/refs/heads/master | 0 .../.git_keep/logs/refs/heads/other_branch | 0 .../09/cbe8c6717c06a61876b7b641a46a62bf3c585d | Bin .../0f/8c9b8f1cac20c63e92e8df34f6d8b3fa74accd | Bin .../17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 | Bin .../17/4a8c9444cfa700682d74059d9fa9be5749242c | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 | Bin .../1b/9ae5f5dff631baaa180a30afd9983f83dc27ca | Bin .../20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 | Bin .../21/730e75ee0eec374cc54eb1140d24e03db834fc | 0 .../21/78af7503938665881174069be4d48fa483e4af | Bin .../22/b0fd807dd5e428c2d818aef6a2311d7c11e885 | Bin .../24/6f7487e08e6330ccbec4053e701145d53f64d4 | Bin .../2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 | Bin .../32/d15fd4451b6693a93d6420c8af6cfc99348e71 | Bin .../34/c74161eef968fc951cf170a011fa8abfeddbcd | Bin .../34/d20faa891d1857610dce8f790a35b702ebd7ee | 0 .../36/e0ef3e52c6e29e64980c71defbab6064d2da8c | Bin .../38/08a710b52a152bb73805fe274e0d877cf61800 | 0 .../41/893d444283aa0c46aa7b5ee01811522cca473d | 0 .../4b/6f90d670c40e5ac78d9c405a5bc40932a0980b | 0 .../4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 | 0 .../5d/a4d9200457542d875fe4def54ac98c16332db0 | Bin .../5e/66799d4a5a3fed89757f3df445a962c9ce2d4f | Bin .../5f/3e4598b46a912f0f95a4898743e979343c82f3 | Bin .../60/91d709b275e712111d016d9b3a4fb44e63f1f6 | Bin .../61/01e935461d4cd862ae4a720846e87880d198b9 | Bin .../67/b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 | Bin .../6c/590c6a21f4e6d335528b5ecf6c52993b914996 | Bin .../72/c9bf1e687e81778850d517953c64f03adbaa1b | 0 .../72/df4fceb0be99deb091ece3f501ef80b39a876a | Bin .../78/3666de4acbb22a9efc205197667f5136118c54 | Bin .../79/6a5a2670ccb2d08db89b9cfcaa07e9be5358e6 | 0 .../88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d | Bin .../88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 | Bin .../90/a84fd62f8033027fab3e567a81d5ed2a6a71cd | Bin .../91/65a12a95d3b2b9b8a0374de787af169b2c339e | Bin .../95/9d7a10da71acf97b17300b40a3b4f30903e09c | Bin .../9a/92a03fdc6eb492ea1ac7acf4fdb04962092f81 | Bin .../9d/e8260b738a34a74533df54f2e404276aa96242 | Bin .../a5/1a44d96e13555215619b32065d0a22d95b8476 | 0 .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../ab/daa06b758aa198cc4afb9c406c87c5690d0ca0 | Bin .../af/a76754c933269d7cd45630a7184a20849dbe9c | Bin .../b2/afb2548f2d143fdd691058f2283b03933a1749 | 0 .../b4/121e2d6aa156227b6541431ddfb8594904b520 | Bin .../c1/dd146476a4a37fff75b88612a718281ea83b58 | Bin .../c6/2b5bc94e327ddb9b545213ff77b207ade48aba | Bin .../d0/60f7226715ca55b04e91fad2b8aca01badd993 | Bin .../d4/f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 | 0 .../d7/d52ecd690fe82c7d820ddb437e82d78b0fa7b2 | Bin .../d8/8617710499a59992caf98d6df1b5f981c58ab1 | 0 .../d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 | Bin .../da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 | Bin .../dc/d348507ba1da8f6479b9d964daa302b2fb9d9c | 0 .../dd/401e3ee3d58b648207cee7f737364a37139bea | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e3/ae5c6d8407e8307b9bc77923be78c901408f6e | Bin .../e4/48ae5bf6371d80ebee24a22b6df341797a6511 | Bin .../e4/666ba294866d5c16f9afebcacf8f4adfee7439 | Bin .../ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d | Bin .../eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 | Bin .../f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 | Bin .../f3/7ec566036d715d6995f55dbc82a4fb3cf56f2f | Bin .../f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 | Bin .../fa/5c5dac095b577173e47b4a0c139525eced009f | 0 .../fd/31cea7e0b6e8d334280be34db8dd86cdda3007 | Bin .../.git_keep/refs/heads/base_branch | 0 .../{ => repo}/.git_keep/refs/heads/develop | 0 .../refs/heads/feature/cherry-picking | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../.git_keep/refs/heads/other_branch | 0 .../expected/{ => repo}/cherrypicking1 | 0 .../expected/{ => repo}/cherrypicking2 | 0 .../expected/{ => repo}/cherrypicking3 | 0 .../expected/{ => repo}/cherrypicking4 | 0 .../expected/{ => repo}/cherrypicking5 | 0 .../expected/{ => repo}/cherrypicking6 | 0 .../expected/{ => repo}/cherrypicking7 | 0 .../expected/{ => repo}/cherrypicking8 | 0 .../expected/{ => repo}/cherrypicking9 | 0 .../expected/{ => repo}/directory/file | 0 .../expected/{ => repo}/directory/file2 | 0 .../expected/{ => repo}/file | 0 .../expected/{ => repo}/file1 | 0 .../expected/{ => repo}/file3 | 0 .../expected/{ => repo}/file4 | 0 .../expected/{ => repo}/file5 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../.git_keep/logs/refs/heads/other | 0 .../03/959db9f70fcb4a8f0931e4ad64e1c9ec1016a4 | 0 .../08/84a47e04257f4c85435a8b10ff4f15fffa63fc | Bin .../0b/e6e80a67f6276c5ede28dd6b8fa8873f1b23c5 | Bin .../2d/8021ed8803ed6142d31b331850ef46246391a7 | Bin .../53/502c7023f80c046a1b00b45614d5ffef8977d9 | Bin .../69/1ee9e9d9c654c81214f56c514ff725f46cb9e4 | Bin .../6b/03bc7537ecf00b48a0ea57ce1edf388ed3f1ad | Bin .../76/9c8b8d89700f6f196b8331159150746a839662 | 0 .../bd/2b32f02abf86a2bb79a12ab09758e44b204b34 | Bin .../c0/565d7cfcf1039c969105f2e1c86ca5eff64381 | Bin .../f2/df244fb87b6ba1d2ab484d76c66baba168a867 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../{ => repo}/.git_keep/refs/heads/other | 0 .../expected/{ => repo}/file | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../01/5689313279311c9356ea3fd3628f73ca4ea797 | Bin .../01/ed22faef05591076721466e07fb10962642887 | Bin .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../24/4cec6fa9704d5dc61fc5e60faba4125dfe3baa | Bin .../24/79abfe7bd6b64a753d3c3797f614bbb422f627 | Bin .../47/5a06b7978eef6509efdd2a86e341992d9f2908 | Bin .../52/863675692b53d9e34dd72da8c35a72bf0a5b51 | Bin .../7a/40dadc0814bf7f1418d005eae184848a9f1c94 | Bin .../92/2fc2ed1965fe8436ce7837c634379f14faf3c3 | Bin .../92/571130f37c70766612048271f1d4dca63ef0b5 | Bin .../93/96d8d0c471661257f6c16c1957452912c0c6f5 | Bin .../a3/2f90adf7ee0f14ae300e49cdf8779507746c27 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../ad/e030587c8ae5d240ad7669bff9030b24bd6385 | Bin .../c6/9e35e8cae5688bbfcf8278c20ab43c1b8dbae3 | Bin .../ce/024fc694fd464cfb5b43cb7702f0bd7345d882 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e3/31050363ceb0b12d9d042e37879d892d867ea0 | Bin .../f3/c8a074e65b02d1bc364caf0b4c1516abf9eb5a | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/repo}/myfile1 | 0 .../patchBuilding/expected/{ => repo}/myfile2 | 0 .../patchBuilding/expected/{ => repo}/myfile3 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../{ => repo}/.git_keep/logs/refs/stash | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../1a/b6a62ed874b19c1191ba2b0106741ca4ca4b50 | Bin .../2c/60d208ba3ec966b77ca756237843af7584cf93 | 0 .../47/5a06b7978eef6509efdd2a86e341992d9f2908 | Bin .../50/63202049f1980e035c390732a7e6da8783357f | Bin .../52/863675692b53d9e34dd72da8c35a72bf0a5b51 | Bin .../9a/939087472cfaf305396d4b177ee888ced193d9 | 0 .../a3/2f90adf7ee0f14ae300e49cdf8779507746c27 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../ad/27dd25048bff07da92d2d9d829e4dd75472da4 | Bin .../ad/e030587c8ae5d240ad7669bff9030b24bd6385 | Bin .../ce/024fc694fd464cfb5b43cb7702f0bd7345d882 | Bin .../d0/ec73019f9c5e426c9b37fa58757855367580a5 | Bin .../d3/4fc4a9c0c675a5cb11d848e5afef4c89160dc0 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e3/31050363ceb0b12d9d042e37879d892d867ea0 | Bin .../e4/74bc2d1712ed5fdf14fb7223392f1b0dcc8d37 | Bin .../f3/c8a074e65b02d1bc364caf0b4c1516abf9eb5a | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/.git_keep/refs/stash | 0 .../expected/repo}/myfile1 | 0 .../expected/{ => repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../41/05b6da4ccc191a4abd24b1ffac6a2031534c0b | Bin .../44/eb4bd0e7419049a8e4176945786c20dae60d7c | Bin .../4b/825dc642cb6eb9a060e54bf8d69288fbee4904 | Bin .../4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f | Bin .../68/bbd52379d849022495dcfd11b13f2fb3103d37 | Bin .../70/28eaec19b2723b62690974057c92ba7d8c1b11 | Bin .../83/90c32b5e687b97e242da46498b574ace0e1eb5 | Bin .../98/1651deb012f8e684dd306c1f5bf8edd5c3db67 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../cf/149a94a18c990b2c5cdd0cf15ec4880f51c8b0 | 0 .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/one/two/three/file3 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo/.git_keep}/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo/.git_keep}/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo/.git_keep}/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../41/05b6da4ccc191a4abd24b1ffac6a2031534c0b | Bin .../43/9a6f2a3c627cd37ba1c5eda6a49c26a85ad610 | Bin .../44/eb4bd0e7419049a8e4176945786c20dae60d7c | Bin .../4b/825dc642cb6eb9a060e54bf8d69288fbee4904 | Bin .../4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f | Bin .../54/57a1e78421c0c1bf9eb3bcc89f6c0996b9f89e | Bin .../5a/abb4aaf3d6cc113fec7f7a3c0a880988085c23 | Bin .../68/bbd52379d849022495dcfd11b13f2fb3103d37 | Bin .../83/90c32b5e687b97e242da46498b574ace0e1eb5 | Bin .../88/981dbb0664057b766113679127284f69f4fb69 | Bin .../98/1651deb012f8e684dd306c1f5bf8edd5c3db67 | Bin .../9f/aac09750995930a5d55eccf91ad6f802e8c66b | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../b5/e8fb99b011265d28065d0d545ff6b0245b1fa1 | 0 .../c1/7dc7400fbb649385064c27544ba1e6c4751566 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/one/two/file2 | 0 .../expected/{ => repo}/one/two/three/file3 | 0 .../pull/expected/.git_keep/FETCH_HEAD | 1 - .../pull/expected/.git_keep/ORIG_HEAD | 1 - .../integration/pull/expected/.git_keep/index | Bin 353 -> 0 bytes .../pull/expected/.git_keep/logs/HEAD | 6 - .../expected/.git_keep/logs/refs/heads/master | 6 - .../.git_keep/logs/refs/remotes/origin/master | 1 - .../00/3527daa0801470151d8f93140a02fc306fea00 | 2 - .../0c/0f210a4e5ff3b58e4190501c2b755695f439fa | Bin 148 -> 0 bytes .../33/6826e035e431ac94eca7f3cb6dd3fb072f7a5a | Bin 150 -> 0 bytes .../6a/d6c42187d356f4eab4f004cca17863746adec1 | 2 - .../pull/expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../.git_keep => pull/expected/origin}/HEAD | 0 .../expected/origin}/config | 2 +- .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../3e/a0c134bed03d0a2cb7eeaff586af277d137129 | 2 + .../7b/9a91f4ecba02fd55dbf3f372bc3faee3897939 | Bin 0 -> 150 bytes .../97/bf06c598032ab5ad0faf744c91545071f3cb38 | Bin 0 -> 148 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../f0/eb4a85b26f51dc8c23e31bb7f541f0e2d1d2d0 | 3 + .../pull/expected/origin/packed-refs | 2 + .../expected/repo}/.git_keep/COMMIT_EDITMSG | 0 .../pull/expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo/.git_keep}/HEAD | 0 .../pull/expected/repo/.git_keep/ORIG_HEAD | 1 + .../expected/repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../pull/expected/repo/.git_keep/index | Bin 0 -> 353 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../pull/expected/repo/.git_keep/logs/HEAD | 7 + .../repo/.git_keep/logs/refs/heads/master | 6 + .../.git_keep/logs/refs/remotes/origin/master | 1 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../3e/a0c134bed03d0a2cb7eeaff586af277d137129 | 2 + .../7b/9a91f4ecba02fd55dbf3f372bc3faee3897939 | Bin 0 -> 150 bytes .../97/bf06c598032ab5ad0faf744c91545071f3cb38 | Bin 0 -> 148 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../f0/eb4a85b26f51dc8c23e31bb7f541f0e2d1d2d0 | 3 + .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected => pull/expected/repo}/myfile1 | 0 .../expected => pull/expected/repo}/myfile2 | 0 .../pull/expected/{ => repo}/myfile3 | 0 .../pull/expected/{ => repo}/myfile4 | 0 .../00/3527daa0801470151d8f93140a02fc306fea00 | 2 - .../0c/0f210a4e5ff3b58e4190501c2b755695f439fa | Bin 148 -> 0 bytes .../33/6826e035e431ac94eca7f3cb6dd3fb072f7a5a | Bin 150 -> 0 bytes .../6a/d6c42187d356f4eab4f004cca17863746adec1 | 2 - .../pull/expected_remote/packed-refs | 2 - test/integration/pull/setup.sh | 6 +- .../expected/.git_keep/FETCH_HEAD | 1 - .../expected/.git_keep/ORIG_HEAD | 1 - .../expected/.git_keep/index | Bin 353 -> 0 bytes .../expected/.git_keep/logs/HEAD | 7 - .../expected/.git_keep/logs/refs/heads/master | 6 - .../.git_keep/logs/refs/remotes/origin/master | 1 - .../06/d3929607b7519beb45ca67165a1f2b5c0e578b | Bin 149 -> 0 bytes .../76/6e681a51daa75233c1c4ae8845be2c893577d5 | Bin 149 -> 0 bytes .../97/2fb9caab8b8536ae38687fec98304b76748b9d | Bin 120 -> 0 bytes .../c9/fd61f40de25556977e063683d1de612f931ccb | Bin 150 -> 0 bytes .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/origin}/HEAD | 0 .../pullAndSetUpstream/expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1f/027c0e280612f8e5e2cf0a5361f6ab0c4baed6 | 2 + .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../64/d950eb46bf13d35cd27dd7a3ad621422dee6ac | Bin 0 -> 149 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../df/fd8a2962e840dfcbce39a0315e0cded7873b29 | Bin 0 -> 149 bytes .../f1/1c72f0484c803d954446036bf464c3b8523330 | Bin 0 -> 149 bytes .../expected/origin/packed-refs | 2 + .../expected/repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo/.git_keep}/HEAD | 0 .../expected/repo/.git_keep/ORIG_HEAD | 1 + .../expected/repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 353 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 7 + .../repo/.git_keep/logs/refs/heads/master | 6 + .../.git_keep/logs/refs/remotes/origin/master | 1 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1f/027c0e280612f8e5e2cf0a5361f6ab0c4baed6 | 2 + .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../64/d950eb46bf13d35cd27dd7a3ad621422dee6ac | Bin 0 -> 149 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../df/fd8a2962e840dfcbce39a0315e0cded7873b29 | Bin 0 -> 149 bytes .../f1/1c72f0484c803d954446036bf464c3b8523330 | Bin 0 -> 149 bytes .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../expected/{ => repo}/myfile4 | 0 .../pullAndSetUpstream/expected_remote/config | 8 - .../06/d3929607b7519beb45ca67165a1f2b5c0e578b | Bin 149 -> 0 bytes .../76/6e681a51daa75233c1c4ae8845be2c893577d5 | Bin 149 -> 0 bytes .../97/2fb9caab8b8536ae38687fec98304b76748b9d | Bin 120 -> 0 bytes .../c9/fd61f40de25556977e063683d1de612f931ccb | Bin 150 -> 0 bytes .../expected_remote/packed-refs | 2 - test/integration/pullAndSetUpstream/setup.sh | 6 +- .../pullMerge/expected/.git_keep/FETCH_HEAD | 1 - .../pullMerge/expected/.git_keep/ORIG_HEAD | 1 - .../pullMerge/expected/.git_keep/index | Bin 353 -> 0 bytes .../pullMerge/expected/.git_keep/logs/HEAD | 7 - .../expected/.git_keep/logs/refs/heads/master | 7 - .../.git_keep/logs/refs/remotes/origin/master | 1 - .../2a/0805355a8040f9eebfa2dbf70b8bc313d6f456 | Bin 150 -> 0 bytes .../55/29eadf398ce89032744d5f4151000f07d70124 | 2 - .../70/3e85166069a42b4254af06b68dffc159ea3f24 | Bin 150 -> 0 bytes .../7c/0bda1656e7695870ed15839643564b0a9283a8 | 3 - .../7f/157a65ec0c8d6cffce08d6768e6733939e75a1 | Bin 149 -> 0 bytes .../b1/0baba2f9d877322f94f8770e2e0c8ab1db6bcc | Bin 204 -> 0 bytes .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/origin}/HEAD | 0 .../expected/origin}/config | 2 +- .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0d/5dd7784063912fe3efeaf7d2b6782019ee9e6e | Bin 0 -> 149 bytes .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../22/4786fb3e4a16b22b4e2b43fe01d7797491adad | 2 + .../29/1b985e75f255f9947f064aee9e1f37af1a930d | 2 + .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../82/422401226cbf89b60b7ba3c6d4fa74781250c9 | Bin 0 -> 150 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../pullMerge/expected/origin/packed-refs | 2 + .../expected/repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo/.git_keep}/HEAD | 0 .../expected/repo/.git_keep/ORIG_HEAD | 1 + .../expected/repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../pullMerge/expected/repo/.git_keep/index | Bin 0 -> 353 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 7 + .../repo/.git_keep/logs/refs/heads/master | 7 + .../.git_keep/logs/refs/remotes/origin/master | 1 + .../0d/5dd7784063912fe3efeaf7d2b6782019ee9e6e | Bin 0 -> 149 bytes .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../22/4786fb3e4a16b22b4e2b43fe01d7797491adad | 2 + .../29/1b985e75f255f9947f064aee9e1f37af1a930d | 2 + .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../67/3a4237450c6ea2a27b18f1d7a3c9293c5606ea | Bin 0 -> 149 bytes .../82/422401226cbf89b60b7ba3c6d4fa74781250c9 | Bin 0 -> 150 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a6/1316509295a5644a82e38e8bd455422fe477c5 | Bin 0 -> 200 bytes .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../ce/0848710343a75263ea72cb5bdfa666b9ecda68 | Bin 0 -> 103 bytes .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../pullMerge/expected/{ => repo}/myfile3 | 0 .../pullMerge/expected/{ => repo}/myfile4 | 0 .../55/29eadf398ce89032744d5f4151000f07d70124 | 2 - .../70/3e85166069a42b4254af06b68dffc159ea3f24 | Bin 150 -> 0 bytes .../7c/0bda1656e7695870ed15839643564b0a9283a8 | 3 - .../7f/157a65ec0c8d6cffce08d6768e6733939e75a1 | Bin 149 -> 0 bytes .../pullMerge/expected_remote/packed-refs | 2 - test/integration/pullMerge/setup.sh | 6 +- .../expected/.git_keep/FETCH_HEAD | 1 - .../expected/.git_keep/ORIG_HEAD | 1 - .../expected/.git_keep/index | Bin 425 -> 0 bytes .../expected/.git_keep/logs/HEAD | 7 - .../expected/.git_keep/logs/refs/heads/master | 7 - .../.git_keep/logs/refs/remotes/origin/master | 1 - .../1f/e5d8152187295b171f171c0d55d809500ae80f | Bin 85 -> 0 bytes .../38/699899bb94dfae74e3e55cf5bd6d92e6f3292a | 3 - .../72/0c7e2dd34822d33cb24a0a3f0f4bdabf433500 | Bin 204 -> 0 bytes .../7d/ba68a0030313e27b8dd5da2076952629485f2d | Bin 156 -> 0 bytes .../80/f8aed01cdb61f9e94c6a53c39f400dfbcf05c9 | Bin 149 -> 0 bytes .../dd/f4b7fe8f45d07a181c2b57cc3434c982d3f4aa | Bin 149 -> 0 bytes .../f0/e8e7922de77a5ab20b924640c8b8435bae0b0b | 2 - .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/origin}/HEAD | 0 .../pullMergeConflict/expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../29/c0636a86cc64292b7a6b1083c2df10de9cde6c | 2 + .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../77/a75278eb08101403d727a8ecaad724f5d9dc78 | Bin 0 -> 150 bytes .../7c/201cb45dc62900f5f42281c1235219df5d0388 | 2 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../c7/180f424ee6b59241eecffedcfa4472a86d927d | Bin 0 -> 150 bytes .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../expected/origin/packed-refs | 2 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 4 +- .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo/.git_keep}/HEAD | 0 .../expected/repo/.git_keep/ORIG_HEAD | 1 + .../expected/repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 425 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 7 + .../repo/.git_keep/logs/refs/heads/master | 7 + .../.git_keep/logs/refs/remotes/origin/master | 1 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../29/c0636a86cc64292b7a6b1083c2df10de9cde6c | 2 + .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../4d/b288af7bc797a3819441c734a4c4e7e3635296 | 2 + .../77/a75278eb08101403d727a8ecaad724f5d9dc78 | Bin 0 -> 150 bytes .../7c/201cb45dc62900f5f42281c1235219df5d0388 | 2 + .../7d/a51df5143674eeec01d1bafa23ab8b9e69e8c2 | Bin 0 -> 86 bytes .../9b/1719f5cf069568785080a0bbabbe7c377e22ae | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../ae/d6c0a012c68a8b615ab0185b64f59c414d4746 | Bin .../c2/5833e74799f64c317fe3f112f934fcc57b71f9 | Bin 0 -> 199 bytes .../c7/180f424ee6b59241eecffedcfa4472a86d927d | Bin 0 -> 150 bytes .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../expected/{ => repo}/myfile4 | 0 .../pullMergeConflict/expected_remote/config | 8 - .../38/699899bb94dfae74e3e55cf5bd6d92e6f3292a | 3 - .../80/f8aed01cdb61f9e94c6a53c39f400dfbcf05c9 | Bin 149 -> 0 bytes .../dd/f4b7fe8f45d07a181c2b57cc3434c982d3f4aa | Bin 149 -> 0 bytes .../f0/e8e7922de77a5ab20b924640c8b8435bae0b0b | 2 - .../expected_remote/packed-refs | 2 - test/integration/pullMergeConflict/setup.sh | 6 +- .../pullRebase/expected/.git_keep/FETCH_HEAD | 1 - .../pullRebase/expected/.git_keep/ORIG_HEAD | 1 - .../pullRebase/expected/.git_keep/index | Bin 425 -> 0 bytes .../pullRebase/expected/.git_keep/logs/HEAD | 9 -- .../expected/.git_keep/logs/refs/heads/master | 7 - .../.git_keep/logs/refs/remotes/origin/master | 1 - .../0b/bb382cb5729bfd2e6fd3e1d60237e03cb375a4 | Bin 148 -> 0 bytes .../74/755f34462bd712c676b84247831233da97a272 | Bin 154 -> 0 bytes .../7b/21277988b03a5fd9e933126e8d1f31d2498d08 | 2 - .../c0/ae07711df69fb0a21efaca9d63da42a67eaedf | 2 - .../d0/e04b2bced3bc76f0abf50698a7ab774cd54568 | 3 - .../fe/1d53ca86366f64f689586cb0fe243fed1d1482 | Bin 149 -> 0 bytes .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/origin}/HEAD | 0 .../pullRebase/expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../7b/a4176e37b24d5c97f17214ca6d658dbc58ef9d | 2 + .../84/b9e43914aa7ae61a869a6b17cf0ec9f1bf04a9 | Bin 0 -> 150 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../f2/744f41facc4c70c41f07c93c2a5fc010b4ccf6 | Bin 0 -> 149 bytes .../f2/b972db67c4667ac1896df3556a2cb2422bef8a | Bin 0 -> 148 bytes .../pullRebase/expected/origin/packed-refs | 2 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo/.git_keep}/HEAD | 0 .../expected/repo/.git_keep/ORIG_HEAD | 1 + .../expected/repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../pullRebase/expected/repo/.git_keep/index | Bin 0 -> 425 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 9 ++ .../repo/.git_keep/logs/refs/heads/master | 7 + .../.git_keep/logs/refs/remotes/origin/master | 1 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../25/b115c8ff09bf59b023af22277ea140b2833110 | Bin 0 -> 148 bytes .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../7b/a4176e37b24d5c97f17214ca6d658dbc58ef9d | 2 + .../84/b9e43914aa7ae61a869a6b17cf0ec9f1bf04a9 | Bin 0 -> 150 bytes .../92/c2dd111eeb7daf4a0e30faff73b9441103805d | Bin .../98/fea3de076a474cabfac7130669625879051d43 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../ef/833c09ff39663448dd9582e3d6ac1fa777fb4f | Bin 0 -> 153 bytes .../f2/744f41facc4c70c41f07c93c2a5fc010b4ccf6 | Bin 0 -> 149 bytes .../f2/b972db67c4667ac1896df3556a2cb2422bef8a | Bin 0 -> 148 bytes .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../pullRebase/expected/{ => repo}/myfile3 | 0 .../pullRebase/expected/{ => repo}/myfile4 | 0 .../pullRebase/expected/{ => repo}/myfile5 | 0 .../pullRebase/expected_remote/config | 8 - .../0b/bb382cb5729bfd2e6fd3e1d60237e03cb375a4 | Bin 148 -> 0 bytes .../c0/ae07711df69fb0a21efaca9d63da42a67eaedf | 2 - .../d0/e04b2bced3bc76f0abf50698a7ab774cd54568 | 3 - .../fe/1d53ca86366f64f689586cb0fe243fed1d1482 | Bin 149 -> 0 bytes .../pullRebase/expected_remote/packed-refs | 2 - test/integration/pullRebase/setup.sh | 6 +- .../expected/.git_keep/FETCH_HEAD | 1 - .../expected/.git_keep/ORIG_HEAD | 1 - .../expected/.git_keep/index | Bin 425 -> 0 bytes .../expected/.git_keep/logs/HEAD | 9 -- .../expected/.git_keep/logs/refs/heads/master | 7 - .../.git_keep/logs/refs/remotes/origin/master | 1 - .../10/3c3eb899d173b83fc1b40261c8880fef359cc3 | Bin 149 -> 0 bytes .../11/6cef0e366265c3d002cdb3dce4e285e32b5d12 | Bin 157 -> 0 bytes .../34/574474ac6f7dd2d3142bc28ee39db88d8a16af | 2 - .../3b/9389ff50095ad2d66d33bb6d67b5700f0bf6da | Bin 149 -> 0 bytes .../aa/6ae0785290ee09875f6bd5a5d50c0e7002de13 | Bin 150 -> 0 bytes .../db/7122c7f62714dfa854d8d22b2081d308912af8 | Bin 159 -> 0 bytes .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/origin}/HEAD | 0 .../pullRebaseConflict/expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../00/36ac0e5f5536f55bfdfcb4e09927f1eed3b37b | 2 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../30/8a85a7f740d42925175560337196f952ac6cf6 | Bin 0 -> 150 bytes .../70/2648e6efd5f8c60f5fe57e152850a5de756978 | Bin 0 -> 148 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../ae/0aa5a0d1c65005bd50012612b1c56c1ea06155 | Bin 0 -> 149 bytes .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../expected/origin/packed-refs | 2 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo/.git_keep}/HEAD | 0 .../expected/repo/.git_keep/ORIG_HEAD | 1 + .../expected/repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 425 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 9 ++ .../repo/.git_keep/logs/refs/heads/master | 7 + .../.git_keep/logs/refs/remotes/origin/master | 1 + .../00/36ac0e5f5536f55bfdfcb4e09927f1eed3b37b | 2 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../30/8a85a7f740d42925175560337196f952ac6cf6 | Bin 0 -> 150 bytes .../4b/825dc642cb6eb9a060e54bf8d69288fbee4904 | Bin .../70/2648e6efd5f8c60f5fe57e152850a5de756978 | Bin 0 -> 148 bytes .../9b/1719f5cf069568785080a0bbabbe7c377e22ae | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../ae/0aa5a0d1c65005bd50012612b1c56c1ea06155 | Bin 0 -> 149 bytes .../ae/d6c0a012c68a8b615ab0185b64f59c414d4746 | Bin .../b2/da3d615a1805f094849247add77d09aee06451 | Bin .../bd/d975a23140e915dd46a1a16575c71bcad754ca | 3 + .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../d4/50cc8f4e691e3043aac25ae71f0f1a3217368f | 2 + .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e6/1e2c991de853082420fd27fd983098afd4c0c8 | Bin .../e6/9912eb1649ce8dbb33678796cec3e89da3675d | Bin .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../expected/{ => repo}/myfile4 | 0 .../pullRebaseConflict/expected_remote/config | 8 - .../10/3c3eb899d173b83fc1b40261c8880fef359cc3 | Bin 149 -> 0 bytes .../34/574474ac6f7dd2d3142bc28ee39db88d8a16af | 2 - .../3b/9389ff50095ad2d66d33bb6d67b5700f0bf6da | Bin 149 -> 0 bytes .../aa/6ae0785290ee09875f6bd5a5d50c0e7002de13 | Bin 150 -> 0 bytes .../expected_remote/packed-refs | 2 - test/integration/pullRebaseConflict/setup.sh | 6 +- .../expected/.git_keep/FETCH_HEAD | 1 - .../expected/.git_keep/ORIG_HEAD | 1 - .../expected/.git_keep/index | Bin 550 -> 0 bytes .../expected/.git_keep/logs/HEAD | 15 -- .../expected/.git_keep/logs/refs/heads/master | 10 -- .../.git_keep/logs/refs/remotes/origin/master | 1 - .../29/daf999882c9e60c6b6a2868913a6cfd856d620 | Bin 159 -> 0 bytes .../3f/b33027aedae13ab0796292c821a0258f6c2f7b | Bin 150 -> 0 bytes .../42/3f7757eb2eea3de217b54447a94820af933d3a | 5 - .../5c/32741b468f0ab8ddd243e9871dcc8dec5c35f9 | Bin 148 -> 0 bytes .../74/ca3dec707dde7c92727d9490517e498360fea8 | 2 - .../89/ee54b2ed7aff7c3aae24f64be85568f9a9d329 | Bin 144 -> 0 bytes .../91/47ce4817b84339d884cee1683f361fd3aa4696 | Bin 144 -> 0 bytes .../b8/9e837219d9a8aceb8b0f13381be0afb0dac427 | Bin 67 -> 0 bytes .../bf/4fb489636d4bde42e478b04cbdcc079dcd0183 | Bin 147 -> 0 bytes .../ca/58e8d47d619ffb625dc021f0ab2bb0f0bcf623 | Bin 150 -> 0 bytes .../e2/251a5b6d32bf5fc57f234946e3fabeba3b5cca | Bin 143 -> 0 bytes .../ea/4a99ea801f54f1ec09a88a28c65eb4db5865aa | 2 - .../ef/bb36c97316886b089b1b27233cd8bfdc37ed4a | 2 - .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/origin}/HEAD | 0 .../expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../52/137603da2dccb618dfa0953d1b7df8c0255959 | Bin 0 -> 150 bytes .../7c/0506ec2cd7852818e3e597619ff64af83770c6 | 3 + .../91/d2303b08e6765e0ec38c401ecbab0cbb126dca | Bin 0 -> 150 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../d4/3a810e4d47f2c632ea62ae581a8aade6f23b21 | 3 + .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../expected/origin/packed-refs | 2 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 10 +- .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo/.git_keep}/HEAD | 0 .../expected/repo/.git_keep/ORIG_HEAD | 1 + .../expected/{ => repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 550 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 15 ++ .../repo/.git_keep/logs/refs/heads/master | 10 ++ .../.git_keep/logs/refs/remotes/origin/master | 1 + .../00/a0b67048be84a6aeaa50b27ad90ab567d65837 | Bin .../03/5fa6a8b921a1d593845c5ce81434b92cc0eccb | Bin 0 -> 67 bytes .../09/f87d11c514ba0a54e43193aaf9067174e2315e | Bin 0 -> 146 bytes .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../24/21815f8570a34d9f8c8991df1005150ed3ae99 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2e/0409bb60df3c4587245fd01fdeb270bb5a24f3 | Bin 0 -> 144 bytes .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../41/6178fd7462af72f4357dda1241fc66063e467b | Bin 0 -> 148 bytes .../52/137603da2dccb618dfa0953d1b7df8c0255959 | Bin 0 -> 150 bytes .../5c/4dd6c94fae2afe48f413f48dc998ae48fcf463 | 2 + .../5d/0d8eb2623180ca95f2634f7e25f40521d5aea2 | Bin .../66/d3639353f039f2b87ea3e0dd3db13a5415c6df | Bin 0 -> 157 bytes .../7c/0506ec2cd7852818e3e597619ff64af83770c6 | 3 + .../8c/fc761d2799512553e491f7ceb3564a5e994999 | Bin .../91/d2303b08e6765e0ec38c401ecbab0cbb126dca | Bin 0 -> 150 bytes .../9b/1719f5cf069568785080a0bbabbe7c377e22ae | Bin .../9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../ae/d6c0a012c68a8b615ab0185b64f59c414d4746 | Bin .../b2/da3d615a1805f094849247add77d09aee06451 | Bin .../d2/17625c37713436bb6c92ff9d0b3991a8a7dba5 | Bin 0 -> 145 bytes .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../d4/3a810e4d47f2c632ea62ae581a8aade6f23b21 | 3 + .../d4/8cf11b7fbbda4199b736bb9e8fadabf773eb9e | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e9/74f4acf07db6fcaa438df552a8fd44e2d58dcd | Bin 0 -> 156 bytes .../f0/bbe52a52883609acdb825c8af32b4b3ccb0607 | Bin .../ff/0d57cafe9d745264b23450e9268cdb5ddc4edc | 2 + .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../expected/{ => repo}/myfile4 | 0 .../expected/{ => repo}/myfile5 | 0 .../expected/{ => repo}/myfile6 | 0 .../expected/{ => repo}/myfile7 | 0 .../expected_remote/config | 8 - .../3f/b33027aedae13ab0796292c821a0258f6c2f7b | Bin 150 -> 0 bytes .../74/ca3dec707dde7c92727d9490517e498360fea8 | 2 - .../ca/58e8d47d619ffb625dc021f0ab2bb0f0bcf623 | Bin 150 -> 0 bytes .../ea/4a99ea801f54f1ec09a88a28c65eb4db5865aa | 2 - .../expected_remote/packed-refs | 2 - .../pullRebaseInteractive/setup.sh | 6 +- .../expected/.git_keep/FETCH_HEAD | 1 - .../expected/.git_keep/ORIG_HEAD | 1 - .../expected/.git_keep/index | Bin 550 -> 0 bytes .../expected/.git_keep/logs/HEAD | 14 -- .../expected/.git_keep/logs/refs/heads/master | 10 -- .../.git_keep/logs/refs/remotes/origin/master | 1 - .../0f/a53867500c0f3a5cca9b2112982795fae51c51 | Bin 144 -> 0 bytes .../45/89efcaf3024e841825bb289bb88eb0e4f8530a | 2 - .../47/6a1939075b60aa47da50a8c40c5b4412a2f18b | Bin 149 -> 0 bytes .../57/59b6258419271e67a172e51cd90048dd21f9c0 | 3 - .../5d/08d9b6315ddb8fb8372d83b54862ba7d7fdc88 | 2 - .../65/401620c5230dfa2ad6e0e2dcb6b447fe21262b | Bin 67 -> 0 bytes .../69/a5c9fb912112305bfe15272855afb50f6acf4b | Bin 143 -> 0 bytes .../7c/717449332e4a81f7e5643eef9c95f459444e3f | 3 - .../90/13b5f12ca8a0fdd44fbe72028500bbac5c89ee | Bin 156 -> 0 bytes .../ae/4e33d43751b83fbd0b6f0a1796d58462492e47 | 2 - .../af/4c4b2b977f8909e590ea5bc3bab59d991e4c28 | Bin 144 -> 0 bytes .../e0/47462bda495acbe565c85b205d614f38c0a692 | Bin 150 -> 0 bytes .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/origin}/HEAD | 0 .../expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../6e/44f128bc1b25454eeb074e40dd15d02eff5c87 | 3 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../a8/88f490faa49a665557b35171f4ce0896414ea2 | 2 + .../ce/137eabb7b8df81d4818ac8a16892b1f7327219 | 3 + .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../fe/fea9e2c324080a61d03142554b81e410e9c87f | 2 + .../expected/origin/packed-refs | 2 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 10 +- .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo/.git_keep}/HEAD | 0 .../expected/repo/.git_keep/ORIG_HEAD | 1 + .../expected/{ => repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 550 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 14 ++ .../repo/.git_keep/logs/refs/heads/master | 10 ++ .../.git_keep/logs/refs/remotes/origin/master | 1 + .../00/a0b67048be84a6aeaa50b27ad90ab567d65837 | Bin .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../26/02a2a5727666c205fef7f152786e1edb1c5d4b | Bin .../28/1c7e805fd7bf133611e701ef01f0a4f362f232 | Bin 0 -> 158 bytes .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../32/2d2d5205fe70df6899f8d58474941de4798aab | Bin 0 -> 67 bytes .../3c/2846a93bb9c2815e3218ac3c906da26d159068 | Bin 0 -> 145 bytes .../5d/0d8eb2623180ca95f2634f7e25f40521d5aea2 | Bin .../62/26d76652e77aba63c55f4f48344304f4f75879 | 4 + .../67/c00631fc73b6b4d61a1dcb0195777f0d832fd7 | Bin 0 -> 144 bytes .../6b/a64def9b38eb7bcf5aa1a6c513c490967062ad | Bin 0 -> 155 bytes .../6e/44f128bc1b25454eeb074e40dd15d02eff5c87 | 3 + .../72/da3b902dcd9e99b21bdc36891e028b8dbfb219 | Bin 0 -> 147 bytes .../8c/fc761d2799512553e491f7ceb3564a5e994999 | Bin .../9b/1719f5cf069568785080a0bbabbe7c377e22ae | Bin .../9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../a8/88f490faa49a665557b35171f4ce0896414ea2 | 2 + .../ae/d6c0a012c68a8b615ab0185b64f59c414d4746 | Bin .../b2/da3d615a1805f094849247add77d09aee06451 | Bin .../ce/137eabb7b8df81d4818ac8a16892b1f7327219 | 3 + .../d1/3fd4cd73174c7048108d2dc8d277a8e013d1e4 | 3 + .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../f0/bbe52a52883609acdb825c8af32b4b3ccb0607 | Bin .../fe/fea9e2c324080a61d03142554b81e410e9c87f | 2 + .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../expected/{ => repo}/myfile4 | 0 .../expected/{ => repo}/myfile5 | 0 .../expected/{ => repo}/myfile7 | 0 .../expected_remote/config | 8 - .../45/89efcaf3024e841825bb289bb88eb0e4f8530a | 2 - .../47/6a1939075b60aa47da50a8c40c5b4412a2f18b | Bin 149 -> 0 bytes .../57/59b6258419271e67a172e51cd90048dd21f9c0 | 3 - .../e0/47462bda495acbe565c85b205d614f38c0a692 | Bin 150 -> 0 bytes .../expected_remote/packed-refs | 2 - .../pullRebaseInteractiveWithDrop/setup.sh | 6 +- .../push/expected/.git_keep/FETCH_HEAD | 1 - .../integration/push/expected/.git_keep/index | Bin 353 -> 0 bytes .../push/expected/.git_keep/logs/HEAD | 4 - .../expected/.git_keep/logs/refs/heads/master | 4 - .../.git_keep/logs/refs/remotes/origin/master | 2 - .../54/7f41a06ebd3bee30fbba3f43631810fa24f1bb | Bin 150 -> 0 bytes .../a0/9547e07257ed0456f498fde1b8214152427384 | 2 - .../a6/e580c7c3c4ea40bc311466d57a946bb3f77541 | 4 - .../eb/831bc1251f71f602159d98f4550e380007ca4f | 2 - .../push/expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/origin}/HEAD | 0 .../expected/origin}/config | 2 +- .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../14/6ca480a776a466024a08d273987c4b2e71f23b | 2 + .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../69/fef9300b95338821093ec2dfb6e2974d303510 | Bin 0 -> 148 bytes .../71/4500c4933e4316cc9747711829560cc42c2f8e | 2 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../ee/53190e06796d55bf236a35d45249c90eff8594 | Bin 0 -> 150 bytes .../push/expected/origin/packed-refs | 2 + .../push/expected/origin/refs/heads/master | 1 + .../expected/repo}/.git_keep/COMMIT_EDITMSG | 0 .../push/expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo/.git_keep}/HEAD | 0 .../expected/repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../push/expected/repo/.git_keep/index | Bin 0 -> 353 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../push/expected/repo/.git_keep/logs/HEAD | 4 + .../repo/.git_keep/logs/refs/heads/master | 4 + .../.git_keep/logs/refs/remotes/origin/master | 2 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../14/6ca480a776a466024a08d273987c4b2e71f23b | 2 + .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../69/fef9300b95338821093ec2dfb6e2974d303510 | Bin 0 -> 148 bytes .../71/4500c4933e4316cc9747711829560cc42c2f8e | 2 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../ee/53190e06796d55bf236a35d45249c90eff8594 | Bin 0 -> 150 bytes .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected => push/expected/repo}/myfile1 | 0 .../expected => push/expected/repo}/myfile2 | 0 .../push/expected/{ => repo}/myfile3 | 0 .../push/expected/{ => repo}/myfile4 | 0 .../54/7f41a06ebd3bee30fbba3f43631810fa24f1bb | Bin 150 -> 0 bytes .../a0/9547e07257ed0456f498fde1b8214152427384 | 2 - .../a6/e580c7c3c4ea40bc311466d57a946bb3f77541 | 4 - .../eb/831bc1251f71f602159d98f4550e380007ca4f | 2 - .../push/expected_remote/packed-refs | 2 - .../push/expected_remote/refs/heads/master | 1 - test/integration/push/setup.sh | 6 +- .../expected/.git_keep/FETCH_HEAD | 1 - .../expected/.git_keep/index | Bin 353 -> 0 bytes .../expected/.git_keep/logs/HEAD | 5 - .../expected/.git_keep/logs/refs/heads/master | 4 - .../expected/.git_keep/logs/refs/heads/test | 1 - .../.git_keep/logs/refs/remotes/origin/master | 1 - .../.git_keep/logs/refs/remotes/origin/test | 1 - .../65/c52315dc238c164b914369f49bd70882cc1d85 | Bin 121 -> 0 bytes .../70/7a2a0835c897496934849bf6e0815593b140b3 | Bin 149 -> 0 bytes .../da/b77371cf53420955fc9baeb84303414f7e4a60 | Bin 150 -> 0 bytes .../db/d679941d871665b7ff70fffe6116725e56e270 | Bin 149 -> 0 bytes .../expected/.git_keep/refs/heads/master | 1 - .../expected/.git_keep/refs/heads/test | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../.git_keep/refs/remotes/origin/test | 1 - .../expected/origin}/HEAD | 0 .../pushAndSetUpstream/expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../97/8360cc5c0a9115bf3db5f10196cd135e1be962 | Bin 0 -> 150 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../d7/7ec09ecf2391f9b76e54de98187095cd2edf9d | 2 + .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e0/c356303c1b9b8fbe6acddb3e58f28b52348c60 | 3 + .../ef/f34f9e6233e534513bb4b2154da4edd316283f | 2 + .../expected/origin/packed-refs | 2 + .../expected/origin/refs/heads/test | 1 + .../expected/repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 353 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 5 + .../repo/.git_keep/logs/refs/heads/master | 4 + .../repo/.git_keep/logs/refs/heads/test | 1 + .../.git_keep/logs/refs/remotes/origin/master | 1 + .../.git_keep/logs/refs/remotes/origin/test | 1 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../97/8360cc5c0a9115bf3db5f10196cd135e1be962 | Bin 0 -> 150 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../d7/7ec09ecf2391f9b76e54de98187095cd2edf9d | 2 + .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e0/c356303c1b9b8fbe6acddb3e58f28b52348c60 | 3 + .../ef/f34f9e6233e534513bb4b2154da4edd316283f | 2 + .../expected/repo/.git_keep/refs/heads/master | 1 + .../expected/repo/.git_keep/refs/heads/test | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../repo/.git_keep/refs/remotes/origin/test | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../expected/{ => repo}/myfile4 | 0 .../pushAndSetUpstream/expected_remote/config | 8 - .../65/c52315dc238c164b914369f49bd70882cc1d85 | Bin 121 -> 0 bytes .../70/7a2a0835c897496934849bf6e0815593b140b3 | Bin 149 -> 0 bytes .../da/b77371cf53420955fc9baeb84303414f7e4a60 | Bin 150 -> 0 bytes .../db/d679941d871665b7ff70fffe6116725e56e270 | Bin 149 -> 0 bytes .../expected_remote/packed-refs | 2 - .../expected_remote/refs/heads/test | 1 - test/integration/pushAndSetUpstream/setup.sh | 6 +- .../expected/.git_keep/FETCH_HEAD | 1 - .../expected/.git_keep/index | Bin 353 -> 0 bytes .../expected/.git_keep/logs/HEAD | 5 - .../expected/.git_keep/logs/refs/heads/master | 4 - .../expected/.git_keep/logs/refs/heads/test | 1 - .../.git_keep/logs/refs/remotes/origin/master | 1 - .../.git_keep/logs/refs/remotes/origin/test | 1 - .../2d/0011f18dcd00e21fd13ede01792048ccd09e85 | Bin 150 -> 0 bytes .../65/52acdbb2da7b153b78bbd9f6a564a54fce1ed9 | Bin 149 -> 0 bytes .../d0/e2575d4cdf78f6845db57439c7b526d02dbc7d | 2 - .../dc/7117cc68b23798cabb2c388a45036da33c2f10 | Bin 150 -> 0 bytes .../expected/.git_keep/refs/heads/master | 1 - .../expected/.git_keep/refs/heads/test | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../.git_keep/refs/remotes/origin/test | 1 - .../expected/origin}/HEAD | 0 .../expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../30/9d64f4b30c8a17897642eb8966189d2b054af2 | Bin 0 -> 150 bytes .../83/d120ae6a09eeef4e082d1c2cc81aac81075988 | Bin 0 -> 149 bytes .../8d/eea9ab6bed53871b952a62607704ea47d6d50e | 2 + .../a1/6265d00b218b3961405fc0c71a5ec2ffff879e | Bin 0 -> 150 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../expected/origin/packed-refs | 2 + .../expected/origin/refs/heads/test | 1 + .../expected/repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 353 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 5 + .../repo/.git_keep/logs/refs/heads/master | 4 + .../repo/.git_keep/logs/refs/heads/test | 1 + .../.git_keep/logs/refs/remotes/origin/master | 1 + .../.git_keep/logs/refs/remotes/origin/test | 1 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../30/9d64f4b30c8a17897642eb8966189d2b054af2 | Bin 0 -> 150 bytes .../83/d120ae6a09eeef4e082d1c2cc81aac81075988 | Bin 0 -> 149 bytes .../8d/eea9ab6bed53871b952a62607704ea47d6d50e | 2 + .../a1/6265d00b218b3961405fc0c71a5ec2ffff879e | Bin 0 -> 150 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../expected/repo/.git_keep/refs/heads/master | 1 + .../expected/repo/.git_keep/refs/heads/test | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../repo/.git_keep/refs/remotes/origin/test | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../expected/{ => repo}/myfile4 | 0 .../expected_remote/config | 8 - .../2d/0011f18dcd00e21fd13ede01792048ccd09e85 | Bin 150 -> 0 bytes .../65/52acdbb2da7b153b78bbd9f6a564a54fce1ed9 | Bin 149 -> 0 bytes .../d0/e2575d4cdf78f6845db57439c7b526d02dbc7d | 2 - .../dc/7117cc68b23798cabb2c388a45036da33c2f10 | Bin 150 -> 0 bytes .../expected_remote/packed-refs | 2 - .../expected_remote/refs/heads/test | 1 - .../pushAndSetUpstreamDefault/setup.sh | 6 +- .../expected/.git_keep/FETCH_HEAD | 1 - .../pushFollowTags/expected/.git_keep/index | Bin 281 -> 0 bytes .../expected/.git_keep/logs/HEAD | 3 - .../expected/.git_keep/logs/refs/heads/master | 3 - .../.git_keep/logs/refs/remotes/origin/master | 2 - .../34/10e6811881ccede9ff762c875f9b99a3e6eaef | Bin 126 -> 0 bytes .../ae/a6b2960cc3e7a2453ce3490ca09d090d7ce223 | Bin 149 -> 0 bytes .../d0/d3bfe09c1a5a9631f3041a184d6b9c6d927c83 | 4 - .../f2/7af92910b10e6ddf592fae975337355579464b | 2 - .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/.git_keep/refs/tags/v1.0 | 1 - .../expected/origin}/HEAD | 0 .../pushFollowTags/expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../03/63748fdf3c7a6947886a53d51208c0866f76af | 3 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../8a/c21a1d236ab7fb92c8f8082a98399596b59dd5 | Bin 0 -> 150 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../bc/1bee0a92515554303f848cbdecb4f7bc219e55 | Bin 0 -> 119 bytes .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../f6/19224ae5e8ac2a5fa8e01624df4ca3d1b50d69 | Bin 0 -> 150 bytes .../expected/origin/packed-refs | 2 + .../expected/origin/refs/heads/master | 1 + .../expected/origin/refs/tags/v1.0 | 1 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo/.git_keep}/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 281 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 3 + .../repo/.git_keep/logs/refs/heads/master | 3 + .../.git_keep/logs/refs/remotes/origin/master | 2 + .../03/63748fdf3c7a6947886a53d51208c0866f76af | 3 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../8a/c21a1d236ab7fb92c8f8082a98399596b59dd5 | Bin 0 -> 150 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../bc/1bee0a92515554303f848cbdecb4f7bc219e55 | Bin 0 -> 119 bytes .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../f6/19224ae5e8ac2a5fa8e01624df4ca3d1b50d69 | Bin 0 -> 150 bytes .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected/repo/.git_keep/refs/tags/v1.0 | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../pushFollowTags/expected_remote/config | 8 - .../34/10e6811881ccede9ff762c875f9b99a3e6eaef | Bin 126 -> 0 bytes .../ae/a6b2960cc3e7a2453ce3490ca09d090d7ce223 | Bin 149 -> 0 bytes .../d0/d3bfe09c1a5a9631f3041a184d6b9c6d927c83 | 4 - .../f2/7af92910b10e6ddf592fae975337355579464b | 2 - .../expected_remote/packed-refs | 2 - .../expected_remote/refs/heads/master | 1 - .../expected_remote/refs/tags/v1.0 | 1 - test/integration/pushFollowTags/setup.sh | 6 +- .../expected/.git_keep/FETCH_HEAD | 1 - .../expected/.git_keep/config | 16 -- .../pushNoFollowTags/expected/.git_keep/index | Bin 281 -> 0 bytes .../expected/.git_keep/logs/HEAD | 3 - .../expected/.git_keep/logs/refs/heads/master | 3 - .../.git_keep/logs/refs/remotes/origin/master | 2 - .../03/009ca2af4be2a9bb49206974ce9c97eaa2da23 | Bin 148 -> 0 bytes .../8f/99b05bf3462e1a797335475bff5fabe3ae9ec5 | 3 - .../e1/9bd88e6b3a0d7e4ffc1de39b34d5a312fb9b77 | Bin 127 -> 0 bytes .../fb/20b9e96648c61699f9faf3a4383340fefd5f91 | 3 - .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/.git_keep/refs/tags/v1.0 | 1 - .../expected/origin}/HEAD | 0 .../pushNoFollowTags/expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../32/a7825dd9144b755bd2bbefa9f0f75047d53aae | Bin 0 -> 119 bytes .../4f/7c2bf086a8b6ba8cdb00cf76dbb18543c4ef3b | 2 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../f0/ce9150789c4aef204270b5201d22e6f7e8b23b | Bin 0 -> 150 bytes .../expected/origin/packed-refs | 2 + .../expected/origin/refs/heads/master | 1 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo/.git_keep}/HEAD | 0 .../expected/repo/.git_keep/config | 16 ++ .../expected/repo/.git_keep}/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 281 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 3 + .../repo/.git_keep/logs/refs/heads/master | 3 + .../.git_keep/logs/refs/remotes/origin/master | 2 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../32/a7825dd9144b755bd2bbefa9f0f75047d53aae | Bin 0 -> 119 bytes .../4f/7c2bf086a8b6ba8cdb00cf76dbb18543c4ef3b | 2 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../bc/74fd77b84a00637ff1a30dc835d7d9d48e5e16 | 2 + .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../f0/ce9150789c4aef204270b5201d22e6f7e8b23b | Bin 0 -> 150 bytes .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected/repo/.git_keep/refs/tags/v1.0 | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../pushNoFollowTags/expected_remote/config | 8 - .../03/009ca2af4be2a9bb49206974ce9c97eaa2da23 | Bin 148 -> 0 bytes .../8f/99b05bf3462e1a797335475bff5fabe3ae9ec5 | 3 - .../fb/20b9e96648c61699f9faf3a4383340fefd5f91 | 3 - .../expected_remote/packed-refs | 2 - .../expected_remote/refs/heads/master | 1 - test/integration/pushNoFollowTags/setup.sh | 6 +- .../pushTag/expected/.git_keep/FETCH_HEAD | 1 - .../pushTag/expected/.git_keep/config | 16 -- .../pushTag/expected/.git_keep/index | Bin 209 -> 0 bytes .../pushTag/expected/.git_keep/logs/HEAD | 2 - .../expected/.git_keep/logs/refs/heads/master | 2 - .../.git_keep/logs/refs/remotes/origin/master | 1 - .../5e/8100f80934cb3f1530579225107a478afac4ee | Bin 149 -> 0 bytes .../f5/e0cf8631fc56de2f374ef60e123a2b643381e5 | 2 - .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../pushTag/expected/.git_keep/refs/tags/v1.0 | 1 - .../expected/origin}/HEAD | 0 .../expected/origin}/config | 2 +- .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../a4/72e4256e0cabe433e1655f13d45f5093f502f3 | Bin 0 -> 119 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../f4/d17a0fe9700c664eb4227b5992a4117c481eb4 | 2 + .../pushTag/expected/origin/packed-refs | 2 + .../pushTag/expected/origin/refs/tags/v1.0 | 1 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo/.git_keep}/HEAD | 0 .../pushTag/expected/repo/.git_keep/config | 16 ++ .../expected/repo/.git_keep}/description | 0 .../pushTag/expected/repo/.git_keep/index | Bin 0 -> 209 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../pushTag/expected/repo/.git_keep/logs/HEAD | 2 + .../repo/.git_keep/logs/refs/heads/master | 2 + .../.git_keep/logs/refs/remotes/origin/master | 1 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../a4/72e4256e0cabe433e1655f13d45f5093f502f3 | Bin 0 -> 119 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../f4/d17a0fe9700c664eb4227b5992a4117c481eb4 | 2 + .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected/repo/.git_keep/refs/tags/v1.0 | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../pushTag/expected_remote/config | 8 - .../5e/8100f80934cb3f1530579225107a478afac4ee | Bin 149 -> 0 bytes .../f5/e0cf8631fc56de2f374ef60e123a2b643381e5 | 2 - .../pushTag/expected_remote/packed-refs | 2 - .../pushTag/expected_remote/refs/tags/v1.0 | 1 - test/integration/pushTag/setup.sh | 6 +- .../expected/.git_keep/FETCH_HEAD | 1 - .../expected/.git_keep/config | 16 -- .../expected/.git_keep/index | Bin 353 -> 0 bytes .../expected/.git_keep/logs/HEAD | 4 - .../expected/.git_keep/logs/refs/heads/master | 4 - .../.git_keep/logs/refs/remotes/origin/master | 2 - .../75/c50688e5a8e48a00d1a824124221bcc6aad640 | Bin 150 -> 0 bytes .../ba/8cb1da2a48c38706b15552877d79e8745c4bff | 2 - .../d9/ea8db22c1655e9861309cc97139357d20e4e64 | Bin 150 -> 0 bytes .../ff/7015f162da19450f2eaf0fc24987104df30e15 | Bin 150 -> 0 bytes .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/origin}/HEAD | 0 .../expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../3e/912c74bc7c237df0c521aff7b3f4932d7e8616 | 2 + .../5b/85aaf0806d1bc5830bb10291727f773c3402dc | Bin 0 -> 150 bytes .../5d/98350a913b48a35001ff9b54335f065b25fd7c | Bin 0 -> 120 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d1/08cb97213835c25d44e14d167e7c5b48f94ce2 | 2 + .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../expected/origin/packed-refs | 2 + .../expected/origin/refs/heads/master | 1 + .../expected/repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo}/.git_keep/HEAD | 0 .../expected/repo/.git_keep/config | 16 ++ .../expected/repo}/.git_keep/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 353 bytes .../expected/repo}/.git_keep/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 4 + .../repo/.git_keep/logs/refs/heads/master | 4 + .../.git_keep/logs/refs/remotes/origin/master | 2 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../3e/912c74bc7c237df0c521aff7b3f4932d7e8616 | 2 + .../5b/85aaf0806d1bc5830bb10291727f773c3402dc | Bin 0 -> 150 bytes .../5d/98350a913b48a35001ff9b54335f065b25fd7c | Bin 0 -> 120 bytes .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d1/08cb97213835c25d44e14d167e7c5b48f94ce2 | 2 + .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../expected/{ => repo}/myfile4 | 0 .../expected_remote/config | 8 - .../75/c50688e5a8e48a00d1a824124221bcc6aad640 | Bin 150 -> 0 bytes .../ba/8cb1da2a48c38706b15552877d79e8745c4bff | 2 - .../d9/ea8db22c1655e9861309cc97139357d20e4e64 | Bin 150 -> 0 bytes .../ff/7015f162da19450f2eaf0fc24987104df30e15 | Bin 150 -> 0 bytes .../expected_remote/packed-refs | 2 - .../expected_remote/refs/heads/master | 1 - test/integration/pushWithCredentials/setup.sh | 8 +- .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../18/24d7294d6d3524d83510db27086177a6db97bf | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../44/e5064a45438ffa3e6e4a0f1444552e2199be97 | Bin .../47/614f63053804bc596291b8f7cff3b460b1b3ee | Bin .../57/8ebf1736e797b78fb670c718ebf177936eb2ef | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e8/ece6af94d443b67962124243509d8f61a29758 | 0 .../ec/fc5809e3397bbda6bd4c9f47267a8c5f22346c | Bin .../fa/af373a925c1e335894ebf4343a00a917f04edc | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../rebase/expected/{ => repo}/file0 | 0 .../rebase/expected/{ => repo}/file1 | 0 .../rebase/expected/{ => repo}/file2 | 0 .../rebase/expected/{ => repo}/file4 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/MERGE_MSG | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/REBASE_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../26/d430fb59900099e9992a3c79f30e42309cdce3 | 0 .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../44/e5064a45438ffa3e6e4a0f1444552e2199be97 | Bin .../4a/edafb1a5d371825cbfea5ffcf2692cc786a1bf | Bin .../4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f | Bin .../61/baf480bb5ddfad6d66c785b321d4aadd5367b4 | 0 .../8d/3ce0d821345b25fef1188e48cba4a1d44c30be | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../bb/c22338ee174004f5c5fa117688249bc5b7e205 | Bin .../bc/e4745137c540943900ca78e4b31dd1315bf57c | Bin .../c3/6e808d2fa61e16952b7d0ffb8f18d08156cc94 | Bin .../c3/901284a9e7fc063d6fa7f0c5797d031445ba45 | Bin .../cc/01bf15804065932f5e50340902614b3c04c948 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../f9/4292928d0bc034fe88c753306b1959300e1264 | 0 .../ff/3fb62dafc2fdd0c81ed64bc132b53584e5e1e2 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../rebase2/expected/{ => repo}/file0 | 0 .../rebase2/expected/{ => repo}/file1 | 0 .../rebase2/expected/{ => repo}/file2 | 0 .../rebase2/expected/{ => repo}/file4 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3c/21f03d819ae34b74084712c3ef1b9b99b2f40e | Bin .../44/e5064a45438ffa3e6e4a0f1444552e2199be97 | Bin .../4b/f6ae41c5ef2186c87f5f39dbb8cadd76c597cc | Bin .../4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f | Bin .../51/a0e4a6635c22a062a48b7134dd556541a1e06c | Bin .../7b/42ba8a9f370bbbf0db85c5aca61f4e8a7b3d26 | Bin .../8f/2acebb8a7a83cfaf3cffc6a9103f633f5cf292 | Bin .../9e/68fbe4291e7416d50587d9b6968aa5ceeccff9 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../cc/01bf15804065932f5e50340902614b3c04c948 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../d8/ae31faf375fd293cedb0c88c41a9c7a77a2530 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../f0/6dfb4e9e5a9dfab869590058f2c1ce1c72b2ac | 0 .../fd/ecf9e3e742db4c8690d56b328b2533e67d2866 | Bin .../ff/3fb62dafc2fdd0c81ed64bc132b53584e5e1e2 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../rebase3/expected/{ => repo}/file0 | 0 .../rebase3/expected/{ => repo}/file1 | 0 .../rebase3/expected/{ => repo}/file2 | 0 .../rebase3/expected/{ => repo}/file4 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../0d/633de5bd380e6b42e03ec1e7a055ba4f3c860d | Bin .../12/ed10a6439eadfdb8877e39b7c6547591a0a91c | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1d/197a4c509a5e71bad9b0b439c8fd26323ff218 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../44/e5064a45438ffa3e6e4a0f1444552e2199be97 | Bin .../4a/e4346ad59bf70d5ba07184af5a138b6a65c224 | 0 .../4d/c7f318f68fe1890dba6fb595009c4652c0a861 | Bin .../4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f | Bin .../74/d431c56eac1e359f6f5736978347af68af5702 | 0 .../76/79fc004a4a40da12907d72ccef14991976aaff | Bin .../7b/01314ccdeccc57cee454feca6369237410e786 | Bin .../8a/db7457de59c3945566ce7675a31bbf048b38ee | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../cc/01bf15804065932f5e50340902614b3c04c948 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../db/ab7e62cd7517f73425d46120a931a59c8eda6e | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../ff/3fb62dafc2fdd0c81ed64bc132b53584e5e1e2 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/file0 | 0 .../expected/{ => repo}/file1 | 0 .../expected/{ => repo}/file2 | 0 .../expected/{ => repo}/file4 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../10/56fd624d61daad06a8726c0ea5626820cafe59 | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1d/7ab21ab5322589052cf9d2d62ca58677f454cc | 0 .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../2a/627747a92ce8c274f7df0da3329616f69b9856 | Bin .../2b/d4d58d29b60b5868c19437ff4467d84ed270aa | Bin .../30/a685cfa43930aadd5b56b2ec0746564d1a1d22 | Bin .../33/1be377b5889b19b5900bc4bed98b1c9cc40095 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../44/e5064a45438ffa3e6e4a0f1444552e2199be97 | Bin .../4d/7b35df7f8ced30495fc0f62b91a270bad7076b | Bin .../4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f | Bin .../69/ebe8bf01f728a9bc787e8553694e36127b48c0 | Bin .../77/741cf500de50347e9f4e5a091515e4568ddad3 | Bin .../83/90c32b5e687b97e242da46498b574ace0e1eb5 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../ac/e527b9737b6c554963361f50ce98a0509c2344 | Bin .../ad/46c1683d660e21b4f13ad808420a4de18326b7 | 0 .../b8/c4d6287efcb68cdffbac00ec15ffc25f575cc5 | Bin .../ba/860ef885ce294ade006af8afda01a8cc584a12 | 0 .../c8/07dfd74adc1e1b732025cab46cf56b4d193e74 | Bin .../c8/738908c85292494dba61be9c050ad95ff0e182 | Bin .../cc/01bf15804065932f5e50340902614b3c04c948 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../d1/3e563982268d8ab77ad47793a2b501dfe6a0dc | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../dc/bade3308277dabb66de476c1cce03bd840d22a | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e3/ad04c1fd3c9137b052ecb422855052f044d88f | Bin .../ff/3fb62dafc2fdd0c81ed64bc132b53584e5e1e2 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../rebaseFixups/expected/{ => repo}/file0 | 0 .../rebaseFixups/expected/{ => repo}/file1 | 0 .../rebaseFixups/expected/{ => repo}/file2 | 0 .../rebaseFixups/expected/{ => repo}/file4 | 0 .../rebaseFixups/expected/{ => repo}/file5 | 0 .../rebaseFixups/expected/{ => repo}/file6 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../59/f4e88de812c15bf0fa7b224cdb361f7ede8931 | Bin .../74/abc9e0d0ec8dd0f5ea872a851364206008ea2b | Bin .../97/066d3866b8e5ead0b68fc746a02222408f28a3 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../d4/83ea1d742e44d9191f3e31e926d7621c513042 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../e2/98537fd470f70bbb174d78f610fe49539cfe66 | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/file0 | 0 .../expected/{ => repo}/file1 | 0 .../expected/{ => repo}/file2 | 0 .../expected/{ => repo}/file3 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1b/cb7e30b3a5a5ae64397dcfe6b74cc18fc55784 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3c/3125afd7a6475dcdd4c4a6b20cc920b31eb96f | Bin .../44/79c0a1c7e43a55a3a6909be88a810dbad3fc42 | Bin .../64/7b9df53752363ecdc1d4c5cebe7d66e6132bfe | 0 .../7c/5b8c907caad01842aa84e91b7d4724d57de4fd | Bin .../9d/793e4fc04a0583eed7670d52fbb16b402f7499 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../c0/793b482cdf9ca48686dbf56fc0a46e982003e1 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../d4/83ea1d742e44d9191f3e31e926d7621c513042 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/file0 | 0 .../expected/{ => repo}/file1 | 0 .../expected/{ => repo}/file2 | 0 .../expected/{ => repo}/file3 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/REBASE_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../0e/45fe2fb8b21adfe348ec5419bd87e4c796c02a | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../41/eefd8a741d391640c4e0528e0b6fff31f90a18 | Bin .../44/e5064a45438ffa3e6e4a0f1444552e2199be97 | Bin .../4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f | Bin .../5e/6e75233f7d0501f030400c0b55d4c778b72b73 | Bin .../61/3c1bfa180babe5e67317d1ef42d566718a7d8f | Bin .../84/c7a918e6bd704aaf4f789ecaea479ab31d4741 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../ac/32b36c1b300cc79ad3f16dfb3c8a77ea7f4965 | Bin .../b2/18d34eec545f29156411f24ab609b970082e1c | 0 .../cc/01bf15804065932f5e50340902614b3c04c948 | Bin .../ce/ada384bff8df54abb8acbf497b751aa9220f00 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../d2/3bcf26566cbf601e766d12ea206cb7827d6630 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../ff/3fb62dafc2fdd0c81ed64bc132b53584e5e1e2 | Bin .../ff/8d9889fccee3b361f37c46c9f0de3f5ef6d70f | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../rebaseSwapping/expected/{ => repo}/file0 | 0 .../rebaseSwapping/expected/{ => repo}/file1 | 0 .../rebaseSwapping/expected/{ => repo}/file2 | 0 .../rebaseSwapping/expected/{ => repo}/file4 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/branch2 | 0 .../{ => repo}/.git_keep/logs/refs/heads/ma | 0 .../.git_keep/logs/refs/heads/master | 0 .../0c/2aa38e0600e0d2df09c2f84664d8a14f899879 | Bin .../10/e005e1fa2db07721aa63cb048b87b7a2830b64 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../2b/16e862b7fc2a6ce1e711e5e174bc2f08c0e001 | Bin .../2d/00bd505971a8bc7318d98e003aee708a367c85 | Bin .../37/661793a793e075730b85b9c3b300195738fc63 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a | Bin .../3d/b2086f780b1cf632eec29111ef395913a8ab2b | Bin .../40/e3ff58efe2f50bc70ab084aba687ffd56dcd38 | Bin .../59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 | Bin .../8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 | Bin .../9a/cb41da3b683497b3966135ccd64411b8ef698f | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../ce/d0c7ee1af3cd078a0bd940fa45e973dfd0f226 | 0 .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../e5/c5c5583f49a34e86ce622b59363df99e09d4c6 | Bin .../e7/76522ac28860d2eba6fe98fa4fad67e798419a | Bin .../fd/c461cdae46cbcd0e8b6f33898b25a17ab36f32 | 0 .../{ => repo}/.git_keep/refs/heads/branch2 | 0 .../{ => repo}/.git_keep/refs/heads/ma | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../reflogCheckout/expected/{ => repo}/file0 | 0 .../reflogCheckout/expected/{ => repo}/file1 | 0 .../reflogCheckout/expected/{ => repo}/file2 | 0 .../reflogCheckout/expected/{ => repo}/file4 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/branch2 | 0 .../.git_keep/logs/refs/heads/master | 0 .../0c/2aa38e0600e0d2df09c2f84664d8a14f899879 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../2d/00bd505971a8bc7318d98e003aee708a367c85 | Bin .../35/bedc872b1ca9e026e51c4017416acba4b3d64b | 0 .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a | Bin .../3d/b2086f780b1cf632eec29111ef395913a8ab2b | Bin .../43/12f3a59c644c52ad89254be43d7a7987e56bed | Bin .../59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 | Bin .../5a/5a519752ffd367bbd85dfbc19e5b18d44d6223 | 0 .../71/3ec49844ebad06a5c98fd3c5ce1445f664c3c6 | 0 .../8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a9/55e641b00e7e896842122a3537c70476d7b4e0 | Bin .../ac/7b38400c8aed050f379f9643b953b9d428fda1 | 0 .../af/eb127e4579981e4b852e8aabb44b07f2ea4e09 | Bin .../bc/8891320172f4cfa3efd7bb8767a46daa200d79 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../e2/3253d1f81331e1c94a5a5f68e2d4cc1cbee2fd | Bin .../e5/c5c5583f49a34e86ce622b59363df99e09d4c6 | Bin .../e7/76522ac28860d2eba6fe98fa4fad67e798419a | Bin .../{ => repo}/.git_keep/refs/heads/branch2 | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/file0 | 0 .../expected/{ => repo}/file1 | 0 .../expected/{ => repo}/file2 | 0 .../expected/{ => repo}/file4 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/branch2 | 0 .../.git_keep/logs/refs/heads/master | 0 .../07/e795700fa240713f5577867a45eb6f2071d856 | Bin .../0c/2aa38e0600e0d2df09c2f84664d8a14f899879 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../2d/00bd505971a8bc7318d98e003aee708a367c85 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a | Bin .../3d/b2086f780b1cf632eec29111ef395913a8ab2b | Bin .../44/5557afd2775df735bc53b891678e6bd9072638 | Bin .../53/26459d9a0c196b18cc31dc95f05c9a4e4462de | Bin .../59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 | Bin .../75/6e436bdd05b965c967edc1929432917e3864cd | 0 .../7d/61d1707885895d92f021111196df4466347327 | Bin .../86/3cae3fe21db864bc92b74ae4820e628e5eaf8b | Bin .../8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a6/cc56fedc3f0fc234dcacef1f1de2706c32c44b | Bin .../b0/bf1c26d59a724c767948a6de15664bfc0c292f | 0 .../c5/4d82926c7b673499d675aec8732cfe08aed761 | 0 .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../e5/c5c5583f49a34e86ce622b59363df99e09d4c6 | Bin .../e7/76522ac28860d2eba6fe98fa4fad67e798419a | Bin .../{ => repo}/.git_keep/refs/heads/branch2 | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/file0 | 0 .../expected/{ => repo}/file1 | 0 .../expected/{ => repo}/file2 | 0 .../expected/{ => repo}/file4 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/branch2 | 0 .../.git_keep/logs/refs/heads/master | 0 .../0c/2aa38e0600e0d2df09c2f84664d8a14f899879 | Bin .../16/fc0fdb6ae48d0bdffbfa7013410227e5fac6f3 | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../18/83828474eb5bac8cb27c8a7a3614f9ea3137a0 | 0 .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../1f/d818af9eb65653e98def81168002cabc353b6a | Bin .../2d/00bd505971a8bc7318d98e003aee708a367c85 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a | Bin .../3d/b2086f780b1cf632eec29111ef395913a8ab2b | Bin .../3e/0b28f0bcdd445c5f6d6b80b7a42f6fa8a536d2 | Bin .../49/6408d5ed7b1edff760bf2ce56a43b9fab737e0 | Bin .../59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 | Bin .../7c/03a659737f2cc728a2a572cedee98019bbd04b | Bin .../8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 | Bin .../94/0576e482f2193afad72ea2205c05fd01507e1a | 0 .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../e5/c5c5583f49a34e86ce622b59363df99e09d4c6 | Bin .../e7/76522ac28860d2eba6fe98fa4fad67e798419a | Bin .../{ => repo}/.git_keep/refs/heads/branch2 | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../reflogHardReset/expected/{ => repo}/file0 | 0 .../reflogHardReset/expected/{ => repo}/file1 | 0 .../reflogHardReset/expected/{ => repo}/file2 | 0 .../reflogHardReset/expected/{ => repo}/file4 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../6c/493ff740f9380390d5c9ddef4af18697ac9375 | Bin .../ae/ac8b060acee50f309eb1f6698a981c50bdf493 | Bin .../c2/bf9b666a310383fd7095bc5bd993bba11b040e | Bin .../c9/62a96f68e65b4dc8e0fea12db5f9006091efdf | Bin .../d0/ce4cb10cd926f646a08889b077a6d7eddd3534 | Bin .../e2/129701f1a4d54dc44f03c93bca0a2aec7c5449 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/file1 | 0 .../expected/{ => repo}/file2 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../33/f3da8081c87015eb5b43b148362af87ce6011c | Bin .../3e/c60bb22aa39d08428e57e3251563f797b40fc8 | Bin .../4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f | Bin .../5f/b9c54526790a11246b733354bf896da8ffc09d | 0 .../6b/94b71598d5aa96357ab261599cfd99a4c2c9d0 | 0 .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../f0/5f4d92d7babb2f40ebd2829dccee0afff44c70 | 0 .../fc/759ce6e48e0012eab3f02ec3524a55be938dd5 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/repo}/myfile1 | 0 .../searching/expected/{ => repo}/myfile3 | 0 .../searching/expected/{ => repo}/myfile4 | 0 .../searching/expected/{ => repo}/myfile5 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo/.git_keep}/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo/.git_keep}/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo/.git_keep}/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../16/4d8eaeabbb4b1082fdfb6735be0134535340b2 | Bin .../36/4e6307f708c6f17d83c7309aaf9a3034210236 | Bin .../4e/a1f9142dd3ced7ae2180752f770ce203fb8ac3 | Bin .../70/dcf03faa734af0278690e1b0f8e767b733d88a | 0 .../88/4971c742724377080ba3d75d4b4d6bceee4e4b | Bin .../89/b24ecec50c07aef0d6640a2a9f6dc354a33125 | Bin .../9c/2a7090627d0fffa9ed001bf7be98f86c2c8068 | Bin .../a9/2d664bc20a04b1621b1fc893d1196b41182fdf | Bin .../cb/f7f40f0ffe31d36ddc23bc6ce251c66f6f4e87 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/myfile1 | 0 .../setUpstream/expected/.git_keep/FETCH_HEAD | 1 - .../setUpstream/expected/.git_keep/ORIG_HEAD | 1 - .../setUpstream/expected/.git_keep/config | 16 -- .../setUpstream/expected/.git_keep/index | Bin 353 -> 0 bytes .../setUpstream/expected/.git_keep/logs/HEAD | 6 - .../expected/.git_keep/logs/refs/heads/master | 6 - .../.git_keep/logs/refs/remotes/origin/master | 1 - .../05/8c8904c25889dd77ee3e817325fd1a28134037 | 2 - .../14/8a38f7ce513079d6cd40e4a02f11e46ea2ba6b | 3 - .../40/9dd039b9ec270067678ae23b710c8e4c49c458 | 3 - .../7d/7da1f440cca8d28eaf4b46e63f207993562b84 | 3 - .../expected/.git_keep/refs/heads/master | 1 - .../.git_keep/refs/remotes/origin/master | 1 - .../expected/origin}/HEAD | 0 .../setUpstream/expected/origin/config | 8 + .../expected/origin}/description | 0 .../expected/origin}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../30/ef3df33d31f0b98298881be4dbe69c54758ba2 | Bin 0 -> 149 bytes .../63/05259d1908bee46b3b686702ed55b6f12e9ba2 | 2 + .../a2/6a9d22097eb77a8cf2fbb18512aa44c0c536a2 | 4 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../c6/ffcbed8902934d462722ff6ef471813b9a4df5 | Bin 0 -> 149 bytes .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../setUpstream/expected/origin/packed-refs | 2 + .../expected/repo/.git_keep/COMMIT_EDITMSG | 1 + .../expected/repo/.git_keep/FETCH_HEAD | 1 + .../expected/repo}/.git_keep/HEAD | 0 .../expected/repo/.git_keep/ORIG_HEAD | 1 + .../expected/repo/.git_keep/config | 16 ++ .../expected/repo}/.git_keep/description | 0 .../setUpstream/expected/repo/.git_keep/index | Bin 0 -> 353 bytes .../expected/repo}/.git_keep/info/exclude | 0 .../expected/repo/.git_keep/logs/HEAD | 7 + .../repo/.git_keep/logs/refs/heads/master | 6 + .../.git_keep/logs/refs/remotes/origin/master | 1 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin 0 -> 103 bytes .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../30/ef3df33d31f0b98298881be4dbe69c54758ba2 | Bin 0 -> 149 bytes .../63/05259d1908bee46b3b686702ed55b6f12e9ba2 | 2 + .../a2/6a9d22097eb77a8cf2fbb18512aa44c0c536a2 | 4 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../c6/ffcbed8902934d462722ff6ef471813b9a4df5 | Bin 0 -> 149 bytes .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin 0 -> 21 bytes .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../expected/repo/.git_keep/refs/heads/master | 1 + .../repo/.git_keep/refs/remotes/origin/master | 1 + .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../setUpstream/expected/{ => repo}/myfile3 | 0 .../setUpstream/expected/{ => repo}/myfile4 | 0 .../setUpstream/expected_remote/config | 8 - .../05/8c8904c25889dd77ee3e817325fd1a28134037 | 2 - .../14/8a38f7ce513079d6cd40e4a02f11e46ea2ba6b | 3 - .../40/9dd039b9ec270067678ae23b710c8e4c49c458 | 3 - .../7d/7da1f440cca8d28eaf4b46e63f207993562b84 | 3 - .../setUpstream/expected_remote/packed-refs | 2 - test/integration/setUpstream/recording.json | 2 +- test/integration/setUpstream/setup.sh | 4 +- .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../07/5bd21694c75fd12e11cbd487eb64d831362e8c | Bin .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1b/838df93e188ddacfce91d03dfcf1386ca57714 | Bin .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin 0 -> 103 bytes .../2f/6174050380438f14b16658a356e762435ca591 | Bin .../30/a1ca3481fdec3245b02aeacfb72ddfe2a433be | Bin .../3c/752371dc0c58af7ff63f7a6c252da9f4d96251 | Bin .../4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f | Bin .../88/fb48b35f6ece4da3ad62dd3426bca0240d63a5 | Bin .../9f/83377e9068d956fe3085934bb32ce22aeb4bf7 | 0 .../a1/cf7798606057d592f8ef1bee884165b6f629f1 | 0 .../a5/9b3d4800dcbf39ab31887402dc178e7b7f82a5 | 0 .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../c5/9791a0d43d3e0a7ed0a40a62b7929acf675bf0 | 0 .../d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 | Bin 0 -> 21 bytes .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../haha => squash/expected/repo}/myfile1 | 0 .../haha => squash/expected/repo}/myfile2 | 0 .../squash/expected/{ => repo}/myfile3 | 0 .../squash/expected/{ => repo}/myfile5 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../15/8e9a9c1a9627ea0ef4de8b00a503ed0f80a09e | Bin .../18/54ab416d299cda0227d62b9ab0765e5551ef57 | Bin .../2c/484c0a45f3726375600319f73978221a74b783 | Bin .../7b/9c2149f16c706cea79b03234cb67fde7e9b68f | Bin .../8a/af931e5367e5af9d2e2c014800d22190352b14 | Bin .../fd/c28832bb15c80146150a24a018088c9df4f8cd | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/one.txt | 0 .../staginWithDiffContextChange/setup.sh | 4 +- .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../05/9586b468b89bf98e3b62126f455ab15bea4a5f | Bin .../0b/6860367a6e7794985007cadf0aaf04c801e59e | Bin .../12/c4186053ecd4056526743060a8fe87429b7306 | Bin .../3e/95c983db9349a26b20fccbdaa933e805ff817e | Bin .../40/ce5b93f72e04cb876afaaf91398c2821260b95 | Bin .../63/5b45efaba0c2415658bc121de201ec43a47920 | 0 .../6f/7e9e66f080162af7ebab016d02550145cfda66 | Bin .../79/8369253f104fe8cdc91db6f7d3525be532218e | Bin .../a0/425534134de68284a0a7250b83b0e6303f0ed7 | Bin .../a4/7182dc057408b3c6b1749cb46db0e0c5fd626b | Bin .../a4/8a7caa799e7859b8f21d373e3f01b06002d42f | Bin .../b6/77e3e5777e122a22ebb001532c5017b199b0c0 | 0 .../dc/02541428fdc15b30bd2174fcbcd43d388eab82 | Bin .../e8/aaa2f356eb341c693e239467fd200d0117b487 | 0 .../fb/e09a11933b44ea60b46bd0f3d44142cb6189a4 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../staging/expected/{ => repo}/one.txt | 0 .../staging/expected/{ => repo}/three.txt | 0 .../staging/expected/{ => repo}/two.txt | 0 test/integration/staging/setup.sh | 12 +- .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../15/8e9a9c1a9627ea0ef4de8b00a503ed0f80a09e | Bin .../7b/9c2149f16c706cea79b03234cb67fde7e9b68f | Bin .../f7/93cf3fd99464dbd3499093e95197229b771b11 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../stagingTwo/expected/{ => repo}/one.txt | 0 test/integration/stagingTwo/setup.sh | 4 +- .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../stash/expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../{ => repo}/.git_keep/logs/refs/stash | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../25/abc3e66a6aa505fb0a2ceb6ad5cda0cc89ecbc | Bin .../2e/fac8148440778cbddcd80ac7477981277dcffe | 0 .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3b/29b35d4357f8e64cafd95140a70d7c9b25138a | Bin .../4c/c838ea1466afc5be1d3bc3e7a937641ec84d7d | Bin .../56/52247b638d1516506790d6648b864ba3447f68 | Bin .../5c/ef9afea6a37d89f925e24ebf71adecb63d1f07 | Bin .../66/bbc809cdafd867cf9320bfb7484bb8fa898448 | 0 .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../9f/2757166809c291c65f09778abb46cfcc4e4a0c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a6/ada9f3d895e751ec289c69913a02146c0ca844 | Bin .../a7/dde526f2e93ffa08897fbfca2c98ce40a8fa5b | Bin .../c7/c7da3c64e86c3270f2639a1379e67e14891b6a | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../e0/9b4dfcd66bfa1c81feeaf67e04d55368a2b065 | Bin .../f3/48ff60bdbb3695f2f519db6bc115b1b8d50886 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/.git_keep/refs/stash | 0 .../stash/expected/{ => repo}/file0 | 0 .../stash/expected/{ => repo}/file1 | 0 .../stash/expected/{ => repo}/file2 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../{ => repo}/.git_keep/logs/refs/stash | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../1e/6f4a55f3dd26848238337763f249681ef9397b | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../56/52247b638d1516506790d6648b864ba3447f68 | Bin .../5c/ef9afea6a37d89f925e24ebf71adecb63d1f07 | Bin .../66/bbc809cdafd867cf9320bfb7484bb8fa898448 | 0 .../6d/c07da80aed51d01a56a89ef37f4411adbd75c5 | Bin .../76/05fecac5dee01fb9df55ca984dcc7a72810f48 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../9f/2757166809c291c65f09778abb46cfcc4e4a0c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a6/ed180e13649885eed39866051ca0e25c0ad6ac | Bin .../c0/0c9eb1ae239494475772c3f3dbae5ea4169575 | 0 .../c7/c7da3c64e86c3270f2639a1379e67e14891b6a | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../d2/2496528fe3c076a668c496ae7ba1f8136f1614 | 0 .../e0/61c8716830532562f919dcb125ea804f87ca2b | Bin .../e5/cef1a548f3613b3e538bd0fc2b4ec88043fc25 | Bin .../f4/f81b6542e98a2f80269449674b0f8f454b74b0 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/.git_keep/refs/stash | 0 .../stashDrop/expected/{ => repo}/file0 | 0 .../stashDrop/expected/{ => repo}/file1 | 0 .../stashDrop/expected/{ => repo}/file2 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/hello | 0 .../.git_keep/logs/refs/heads/master | 0 .../{ => repo}/.git_keep/logs/refs/stash | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../28/59c9a5f343c80929844d6e49d3792b9169c4da | Bin .../2a/b31642272ef6607700326d4ddb78f35e609d2b | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../5b/9d4ea51af3db649ff3ae4d92b9eacb84218368 | Bin .../71/890c9b458697fbb4a6a9dde41614bea569aac8 | 0 .../79/7c030ec107d77fa39a1e453ad620235cb26725 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../ac/b6fb50a77cf7bb6fb9cd5e45bc98010012d7c6 | Bin .../c7/c7da3c64e86c3270f2639a1379e67e14891b6a | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../{ => repo}/.git_keep/refs/heads/hello | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/.git_keep/refs/stash | 0 .../stashNewBranch/expected/{ => repo}/file0 | 0 .../stashNewBranch/expected/{ => repo}/file1 | 0 .../stashNewBranch/expected/{ => repo}/file2 | 0 .../stashNewBranch/expected/{ => repo}/file3 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../{ => repo}/.git_keep/logs/refs/stash | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3a/e4e5d4920afbb1bac23426afb237524c8dbe41 | Bin .../43/7b9b0ca941f1e12c8b45958f5d6ebd11cdd41a | 0 .../5c/ef9afea6a37d89f925e24ebf71adecb63d1f07 | Bin .../66/bbc809cdafd867cf9320bfb7484bb8fa898448 | 0 .../82/cc524693ae9fb40af0ed8ab7e22581084dcd17 | Bin .../86/34432ef171aa4b8d8e688fc1e5645245bf36ac | Bin .../8b/081dcb0e1fd5e9862d1aa6891b805b101abe7b | Bin .../8b/d86c566a91e9f8ace9883f7017f562c971b3f7 | Bin .../8e/b0f6c64dea2004a684ea55f9589b71b45d76a6 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../b0/00623a052b4d2226c43ba396b830738799740e | Bin .../c6/a8d49b926afc9ff2b4c64398ee678c50c2c953 | 0 .../c7/c7da3c64e86c3270f2639a1379e67e14891b6a | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../e0/0e994a4acb98bcbe93ad478e09dcb3bed6b26c | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/.git_keep/refs/stash | 0 .../stashPop/expected/{ => repo}/file0 | 0 .../stashPop/expected/{ => repo}/file1 | 0 .../stashPop/expected/{ => repo}/file2 | 0 .../stashPop/expected/{ => repo}/file3 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo/.git_keep}/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo/.git_keep}/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../expected/repo/.git_keep}/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../{ => repo}/.git_keep/logs/refs/stash | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../25/abc3e66a6aa505fb0a2ceb6ad5cda0cc89ecbc | Bin .../2e/fac8148440778cbddcd80ac7477981277dcffe | 0 .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3b/29b35d4357f8e64cafd95140a70d7c9b25138a | Bin .../4c/c838ea1466afc5be1d3bc3e7a937641ec84d7d | Bin .../56/52247b638d1516506790d6648b864ba3447f68 | Bin .../5c/ef9afea6a37d89f925e24ebf71adecb63d1f07 | Bin .../66/bbc809cdafd867cf9320bfb7484bb8fa898448 | 0 .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../9f/2757166809c291c65f09778abb46cfcc4e4a0c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a6/ada9f3d895e751ec289c69913a02146c0ca844 | Bin .../a7/dde526f2e93ffa08897fbfca2c98ce40a8fa5b | Bin .../c7/c7da3c64e86c3270f2639a1379e67e14891b6a | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../e0/9b4dfcd66bfa1c81feeaf67e04d55368a2b065 | Bin .../f3/48ff60bdbb3695f2f519db6bc115b1b8d50886 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/.git_keep/refs/stash | 0 .../stash_Copy/expected/{ => repo}/file0 | 0 .../stash_Copy/expected/{ => repo}/file1 | 0 .../stash_Copy/expected/{ => repo}/file2 | 0 .../submoduleAdd/expected/.git_keep/index | Bin 361 -> 0 bytes .../expected/.git_keep/modules/blah/index | Bin 209 -> 0 bytes .../expected/.git_keep/modules/blah/logs/HEAD | 1 - .../modules/blah/logs/refs/heads/master | 1 - .../blah/logs/refs/remotes/origin/HEAD | 1 - .../6d/e70e35394a99cc437d1bc70b0852b70c5bb03d | Bin 146 -> 0 bytes .../expected/.git_keep/refs/heads/master | 1 - .../expected/other_repo}/HEAD | 0 .../expected/other_repo}/config | 2 +- .../expected/other_repo}/description | 0 .../expected/other_repo}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../42/530e986dbb65877ed8d61ca0c816e425e5c62e | Bin .../a5/0a5125768001a3ea263ffb7cafbc421a508153 | 0 .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../expected/other_repo/packed-refs | 2 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo/.git_keep}/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 361 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 2 +- .../.git_keep/logs/refs/heads/master | 2 +- .../repo/.git_keep/modules/blah}/HEAD | 0 .../{ => repo}/.git_keep/modules/blah/config | 2 +- .../repo/.git_keep/modules/blah}/description | 0 .../repo/.git_keep/modules/blah/index | Bin 0 -> 209 bytes .../repo/.git_keep/modules/blah}/info/exclude | 0 .../repo/.git_keep/modules/blah/logs/HEAD | 1 + .../modules/blah/logs/refs/heads/master | 1 + .../blah/logs/refs/remotes/origin/HEAD | 1 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../42/530e986dbb65877ed8d61ca0c816e425e5c62e | Bin .../a5/0a5125768001a3ea263ffb7cafbc421a508153 | 0 .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../.git_keep/modules/blah/packed-refs | 0 .../.git_keep/modules/blah/refs/heads/master | 0 .../modules/blah/refs/remotes/origin/HEAD | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../42/530e986dbb65877ed8d61ca0c816e425e5c62e | Bin .../5f/77fb3622a1035782a7dacc0cca12e674066b9e | Bin .../a5/0a5125768001a3ea263ffb7cafbc421a508153 | 0 .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../b9/7660affc790464b00ad45c7186a882238d77fb | Bin .../dc/5bde4a09968b0819f34d193f6780df295d71cf | Bin 0 -> 146 bytes .../expected/repo/.git_keep/refs/heads/master | 1 + .../expected/{ => repo}/.gitmodules_keep | 0 .../expected/{ => repo}/haha/.git_keep | 0 .../expected/{ => repo/haha}/myfile1 | 0 .../expected/{ => repo/haha}/myfile2 | 0 .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 test/integration/submoduleAdd/setup.sh | 4 +- .../submoduleEnter/expected/.git_keep/index | Bin 441 -> 0 bytes .../.git_keep/modules/other_repo/index | Bin 137 -> 0 bytes .../.git_keep/modules/other_repo/logs/HEAD | 5 - .../c8/3cc777cf98a8c0f3c0995d7c1b21db92a71c66 | 2 - .../expected/.git_keep/refs/heads/master | 1 - .../expected/other_repo}/HEAD | 0 .../submoduleEnter/expected/other_repo/config | 8 + .../expected/other_repo}/description | 0 .../expected/other_repo}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../42/530e986dbb65877ed8d61ca0c816e425e5c62e | Bin .../96/c588f28aac5a8ebd6430526697e82e46b3180c | Bin .../a5/0a5125768001a3ea263ffb7cafbc421a508153 | 0 .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../fc/4712e93d74ad4fb68e2fd219ac253ae03e19a4 | 0 .../expected/other_repo/packed-refs | 2 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 2 +- .../expected/repo/.git_keep}/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 441 bytes .../expected/repo/.git_keep}/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 2 +- .../.git_keep/logs/refs/heads/master | 2 +- .../repo/.git_keep/modules/other_repo}/HEAD | 0 .../.git_keep/modules/other_repo/ORIG_HEAD | 0 .../.git_keep/modules/other_repo/config | 2 +- .../.git_keep/modules/other_repo}/description | 0 .../repo/.git_keep/modules/other_repo/index | Bin 0 -> 137 bytes .../modules/other_repo}/info/exclude | 0 .../.git_keep/modules/other_repo/logs/HEAD | 5 + .../modules/other_repo/logs/refs/heads/master | 6 +- .../other_repo/logs/refs/remotes/origin/HEAD | 2 +- .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../42/530e986dbb65877ed8d61ca0c816e425e5c62e | Bin .../96/c588f28aac5a8ebd6430526697e82e46b3180c | Bin .../a5/0a5125768001a3ea263ffb7cafbc421a508153 | 0 .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin .../fc/4712e93d74ad4fb68e2fd219ac253ae03e19a4 | 0 .../.git_keep/modules/other_repo/packed-refs | 0 .../modules/other_repo/refs/heads/master | 0 .../other_repo/refs/remotes/origin/HEAD | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin 0 -> 52 bytes .../10/7f435787895be1068f01326df55c355a9d29b1 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/864257bf2d49adbad8785540d85030a60852ff | Bin .../42/530e986dbb65877ed8d61ca0c816e425e5c62e | Bin .../59/a9aee220657762e2d1c60799a0f5b03137d906 | Bin .../96/c588f28aac5a8ebd6430526697e82e46b3180c | Bin 0 -> 83 bytes .../a5/0a5125768001a3ea263ffb7cafbc421a508153 | 0 .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin 0 -> 77 bytes .../e1/eb418c0ff98940d4ea817eebcff5dcdde645ce | 0 .../fc/4712e93d74ad4fb68e2fd219ac253ae03e19a4 | 2 + .../fd/65a5c96edfc884a78bfe3d0240cb8a7ea0a31a | 4 + .../expected/repo/.git_keep/refs/heads/master | 1 + .../expected/{ => repo}/.gitmodules_keep | 0 .../expected/{other_repo => repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 .../expected/{ => repo}/myfile3 | 0 .../expected/{ => repo}/other_repo/.git_keep | 0 .../expected/repo/other_repo}/myfile1 | 0 test/integration/submoduleEnter/setup.sh | 4 +- .../submoduleRemove/expected/.git_keep/index | Bin 289 -> 0 bytes .../40/f121d7563ed318d461996b8d84e2ec8632687e | 2 - .../expected/.git_keep/refs/heads/master | 1 - .../expected/other_repo}/HEAD | 0 .../expected/other_repo/config | 8 + .../expected/other_repo}/description | 0 .../expected/other_repo}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin 0 -> 52 bytes .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../42/530e986dbb65877ed8d61ca0c816e425e5c62e | Bin .../a5/0a5125768001a3ea263ffb7cafbc421a508153 | 0 .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin 0 -> 77 bytes .../expected/other_repo/packed-refs | 2 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo/.git_keep/HEAD | 1 + .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 289 bytes .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 2 +- .../.git_keep/logs/refs/heads/master | 2 +- .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin 0 -> 52 bytes .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../2b/864257bf2d49adbad8785540d85030a60852ff | Bin .../2e/eb2c1e6451d1318b506eecddf936b59a5f32b8 | Bin .../42/530e986dbb65877ed8d61ca0c816e425e5c62e | Bin 0 -> 150 bytes .../61/1cac756ef1944ab56d12f4ea3ae4623724c8cf | Bin 0 -> 155 bytes .../9d/10a5a0a21eb2cfdb6206f474ed57fd5cd51440 | Bin .../a5/0a5125768001a3ea263ffb7cafbc421a508153 | 2 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin 0 -> 77 bytes .../e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 | Bin .../f1/43043bb53b17b5727a43b6cfbb1a8d1f5a222d | Bin .../expected/repo/.git_keep/refs/heads/master | 1 + .../expected/{ => repo}/.gitmodules_keep | 0 .../expected/repo}/myfile1 | 0 .../expected/repo}/myfile2 | 0 test/integration/submoduleRemove/setup.sh | 4 +- .../submoduleReset/expected/.git_keep/index | Bin 369 -> 0 bytes .../.git_keep/modules/other_repo/index | Bin 209 -> 0 bytes .../.git_keep/modules/other_repo/logs/HEAD | 5 - .../modules/other_repo/logs/refs/stash | 1 - .../84/69b6d9b0a33be075f9e0df61c5a3ebba3ecfd2 | 2 - .../9d/13001fc1d98cd178f9e604f6f2c2e52794079e | Bin 177 -> 0 bytes .../f3/5aba17e85e3fe18f7b01c0f65306c9289c482e | Bin 230 -> 0 bytes .../.git_keep/modules/other_repo/refs/stash | 1 - .../submoduleReset/expected/other_repo/HEAD | 1 + .../submoduleReset/expected/other_repo/config | 8 + .../expected/other_repo}/description | 0 .../expected/other_repo}/info/exclude | 0 .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin 0 -> 52 bytes .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin .../42/530e986dbb65877ed8d61ca0c816e425e5c62e | Bin 0 -> 150 bytes .../a5/0a5125768001a3ea263ffb7cafbc421a508153 | 2 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin 0 -> 77 bytes .../expected/other_repo/packed-refs | 2 + .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/repo/.git_keep/HEAD | 1 + .../expected/{ => repo}/.git_keep/config | 2 +- .../expected/repo}/.git_keep/description | 0 .../expected/repo/.git_keep/index | Bin 0 -> 369 bytes .../expected/repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../.git_keep/modules/other_repo/HEAD | 0 .../.git_keep/modules/other_repo/ORIG_HEAD | 0 .../.git_keep/modules/other_repo/config | 2 +- .../.git_keep/modules/other_repo}/description | 0 .../repo/.git_keep/modules/other_repo/index | Bin 0 -> 209 bytes .../.git_keep/modules/other_repo/info/exclude | 7 + .../.git_keep/modules/other_repo/logs/HEAD | 5 + .../modules/other_repo/logs/refs/heads/master | 4 +- .../other_repo/logs/refs/remotes/origin/HEAD | 2 +- .../modules/other_repo/logs/refs/stash | 1 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin 0 -> 52 bytes .../17/a177705e91137f8c55965c9c8818dd55e97c89 | 2 + .../17/defcd0e1f9ad96542aa66845e53cb46c91c30d | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin 0 -> 21 bytes .../42/530e986dbb65877ed8d61ca0c816e425e5c62e | Bin 0 -> 150 bytes .../4b/825dc642cb6eb9a060e54bf8d69288fbee4904 | Bin .../5a/d28e22767f979da2c198dc6c1003b25964e3da | Bin .../87/4e570cb4ea7387ba59054b315aa584038cacea | 2 + .../a5/0a5125768001a3ea263ffb7cafbc421a508153 | 2 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin 0 -> 77 bytes .../d2/2afbf8d80bbd74bcd87cae8a17a0315cfc915b | Bin 0 -> 180 bytes .../.git_keep/modules/other_repo/packed-refs | 0 .../modules/other_repo/refs/heads/master | 0 .../other_repo/refs/remotes/origin/HEAD | 0 .../.git_keep/modules/other_repo/refs/stash | 1 + .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin 0 -> 52 bytes .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin 0 -> 21 bytes .../2b/864257bf2d49adbad8785540d85030a60852ff | Bin .../2e/eb2c1e6451d1318b506eecddf936b59a5f32b8 | Bin .../42/530e986dbb65877ed8d61ca0c816e425e5c62e | Bin 0 -> 150 bytes .../9d/10a5a0a21eb2cfdb6206f474ed57fd5cd51440 | Bin .../a5/0a5125768001a3ea263ffb7cafbc421a508153 | 2 + .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin 0 -> 77 bytes .../{ => repo}/.git_keep/refs/heads/master | 0 .../expected/{ => repo}/.gitmodules_keep | 0 .../expected/{other_repo => repo}/myfile1 | 0 .../expected/{other_repo => repo}/myfile2 | 0 .../expected/{ => repo}/other_repo/.git_keep | 0 .../expected/repo/other_repo/myfile1} | 0 .../expected/repo/other_repo/myfile2} | 0 test/integration/submoduleReset/setup.sh | 4 +- .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../expected/repo}/.git_keep/description | 0 .../expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../09/767bd3484e22b41138116992cc1cb5bc45fb7f | Bin .../72/068e9a852a790a9b867e8b5d21cb4ede3ba4d7 | 0 .../c4/534c51b41b7c85f4fad4657885792d95797e8c | Bin .../e0/aeb3ba0b32392aaf7d88a5190aca76be967225 | 0 .../e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 | Bin .../{ => repo}/.git_keep/refs/heads/master | 0 .../{ => repo}/.git_keep/refs/tags/0.0.1 | 0 .../{ => repo}/.git_keep/refs/tags/0.0.2 | 0 .../expected/{ => repo}/file0 | 0 .../expected/{ => repo}/file1 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../tags/expected/repo/.git_keep/HEAD | 1 + .../tags/expected/{ => repo}/.git_keep/config | 0 .../tags/expected/repo/.git_keep/description | 1 + .../tags/expected/{ => repo}/.git_keep/index | Bin .../tags/expected/repo/.git_keep/info/exclude | 7 + .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../07/b4cadb018ce914237e3f31ee264c9555acc1d1 | Bin .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3e/46e87f3ca37fad40d7dd6aca00223d7f49e424 | 0 .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin 0 -> 21 bytes .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../expected/{ => repo}/.git_keep/packed-refs | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../{ => repo}/.git_keep/refs/tags/tag1 | 0 .../{ => repo}/.git_keep/refs/tags/tag3 | 0 .../{ => repo}/.git_keep/refs/tags/tag4 | 0 .../tags/expected/{ => repo}/file0 | 0 .../expected => tags/expected/repo}/file1 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../tags2/expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../tags2/expected/repo/.git_keep/description | 1 + .../tags2/expected/{ => repo}/.git_keep/index | Bin .../expected/repo/.git_keep/info/exclude | 7 + .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../17/50e9a4016c985ef97d002ae40ed554e3db6c87 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin 0 -> 21 bytes .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../44/e5064a45438ffa3e6e4a0f1444552e2199be97 | Bin .../56/a89d6aebdfa4f2d717efc0d115656cc9b602e7 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin 0 -> 21 bytes .../ae/fe968910ad84a58bfac631b56eb422968766fb | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../dc/b11a2a23383bd5f4a1085bf3a64e73e5bd963a | Bin .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin 0 -> 21 bytes .../{ => repo}/.git_keep/refs/heads/master | 0 .../{ => repo}/.git_keep/refs/tags/one | 0 .../{ => repo}/.git_keep/refs/tags/two | 0 .../tags2/expected/{ => repo}/file0 | 0 .../expected => tags2/expected/repo}/file1 | 0 .../expected => tags2/expected/repo}/file2 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../tags3/expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../tags3/expected/repo/.git_keep/description | 1 + .../tags3/expected/{ => repo}/.git_keep/index | Bin .../expected/repo/.git_keep/info/exclude | 7 + .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../{ => repo}/.git_keep/logs/refs/heads/test | 0 .../08/c28e4e15f3de3b024524894d9235dfcdb48c19 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin 0 -> 21 bytes .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../25/15eabac6791725f4a3326676a1491f09664afc | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../44/e5064a45438ffa3e6e4a0f1444552e2199be97 | Bin .../46/b4990797fac897fb135dd639a4cad3b0269f2d | Bin .../88/d7a40883abd57297127b3777a2a7ec3696c33a | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin 0 -> 21 bytes .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin 0 -> 21 bytes .../{ => repo}/.git_keep/refs/heads/master | 0 .../{ => repo}/.git_keep/refs/heads/test | 0 .../{ => repo}/.git_keep/refs/tags/one | 0 .../tags3/expected/{ => repo}/file0 | 0 .../expected => tags3/expected/repo}/file1 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../tags4/expected/repo/.git_keep/HEAD | 1 + .../expected/{ => repo}/.git_keep/config | 0 .../tags4/expected/repo/.git_keep/description | 1 + .../tags4/expected/{ => repo}/.git_keep/index | Bin .../{ => repo}/.git_keep/info/exclude | 0 .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/master | 0 .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3a/64c1649510c0dcaca3815291e3d43980f1bb99 | Bin .../56/18f31c7550111a878fb63f6079e8462ae94c42 | 0 .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin 0 -> 21 bytes .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../db/03048dbacea165536b49c030c9aaca108cc571 | Bin .../f0/4e94a59e6159acf554fc1268742df10fe6b0d3 | Bin .../expected/{ => repo}/.git_keep/packed-refs | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../{ => repo}/.git_keep/refs/tags/atag2 | 0 .../tags4/expected/{ => repo}/file0 | 0 .../expected => tags4/expected/repo}/file1 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../undo/expected/{ => repo}/.git_keep/HEAD | 0 .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../undo/expected/{ => repo}/.git_keep/config | 0 .../undo/expected/repo/.git_keep/description | 1 + .../undo/expected/{ => repo}/.git_keep/index | Bin .../undo/expected/repo/.git_keep/info/exclude | 7 + .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/branch2 | 0 .../.git_keep/logs/refs/heads/master | 0 .../0c/2aa38e0600e0d2df09c2f84664d8a14f899879 | Bin .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin 0 -> 21 bytes .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../2d/00bd505971a8bc7318d98e003aee708a367c85 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a | Bin .../3d/b2086f780b1cf632eec29111ef395913a8ab2b | Bin .../3e/4f2b1aeb076cff592279f94b1f495442690521 | Bin .../4f/77a25a15ccca0273baa522f7281727f31ceeb8 | 0 .../59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 | Bin .../5d/2b236ff0e8342ef1e531506f6f99070d53cf25 | Bin .../68/ac4e416c01408d37c59465852aa1856a4abdb1 | Bin .../6d/95d7a7842625152ba887482879dfdaf247f591 | Bin .../7c/e8eac65e3ae50cb50a570dc775b745464f3a3e | Bin .../8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 | Bin .../99/36b8f380c2937bb457ade468bfc7dc850293f9 | Bin .../9d/187b7f4819a69996dd27e3d66a5224e05d9f41 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin 0 -> 21 bytes .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../e5/c5c5583f49a34e86ce622b59363df99e09d4c6 | Bin .../e7/76522ac28860d2eba6fe98fa4fad67e798419a | Bin .../fc/f46511d7819220e0cc310ae6d891fadfdb79aa | 0 .../{ => repo}/.git_keep/refs/heads/branch2 | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../undo/expected/{ => repo}/file0 | 0 .../expected => undo/expected/repo}/file1 | 0 .../expected => undo/expected/repo}/file2 | 0 .../undo/expected/{ => repo}/file4 | 0 .../{ => repo}/.git_keep/COMMIT_EDITMSG | 0 .../expected/{ => repo}/.git_keep/FETCH_HEAD | 0 .../undo2/expected/repo/.git_keep/HEAD | 1 + .../expected/{ => repo}/.git_keep/ORIG_HEAD | 0 .../expected/{ => repo}/.git_keep/config | 0 .../undo2/expected/repo/.git_keep/description | 1 + .../undo2/expected/{ => repo}/.git_keep/index | Bin .../expected/repo/.git_keep/info/exclude | 7 + .../expected/{ => repo}/.git_keep/logs/HEAD | 0 .../.git_keep/logs/refs/heads/branch2 | 0 .../.git_keep/logs/refs/heads/master | 0 .../0c/2aa38e0600e0d2df09c2f84664d8a14f899879 | Bin .../0e/2680a41392859e5159716b50525850017c6a59 | 0 .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin 0 -> 21 bytes .../1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 | Bin .../2d/00bd505971a8bc7318d98e003aee708a367c85 | Bin .../38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da | Bin .../3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a | Bin .../3d/b2086f780b1cf632eec29111ef395913a8ab2b | Bin .../48/1ce2cf9d037b83acb1d452973695764bf7b95e | 0 .../59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 | Bin .../8d/31a10ce1a1a1606ab02e8a2a59a6c56808f7c5 | Bin .../8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 | Bin .../9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c | Bin .../a3/bf51bf610771f997de1d3f313ab7c43e20bef5 | Bin .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin 0 -> 21 bytes .../bc/e6c0c795a3d37c0a2c382a6d9c146b1889f86c | Bin .../d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 | 0 .../df/1876c035ade1ba199afadd399a6d4273190cd8 | Bin .../e5/1d8e24ead991fdd7fd9b9d90924c2e24576981 | Bin .../e5/c5c5583f49a34e86ce622b59363df99e09d4c6 | Bin .../e7/76522ac28860d2eba6fe98fa4fad67e798419a | Bin .../{ => repo}/.git_keep/refs/heads/branch2 | 0 .../{ => repo}/.git_keep/refs/heads/master | 0 .../undo2/expected/{ => repo}/file0 | 0 test/integration/undo2/expected/repo/file1 | 1 + test/integration/undo2/expected/repo/file2 | 1 + .../undo2/expected/{ => repo}/file4 | 0 3991 files changed, 1205 insertions(+), 968 deletions(-) rename test/integration/bisect/expected/{ => repo}/.git_keep/BISECT_ANCESTORS_OK (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/BISECT_EXPECTED_REV (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/BISECT_LOG (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/BISECT_NAMES (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/BISECT_START (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/BISECT_TERMS (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/config (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/description (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/index (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/logs/refs/heads/test (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/00/5ca78c7fb8157683fa61158235b250d2316004 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/00/750edc07d6415dcc07ae0351e9397b0222b7ba (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/05/4bdf969fdcf1f90f1998666f628d40f72fde4f (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/07/552205114379b7c1abd7cb39575cb7a30a2e8c (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/0c/fbf08886fca9a91cb753ec8734c84fcbe52c9f (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/11/0046b8d92b877def6cda61639cf8f37bc2829c (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/12/e46e3c37d1a43a26b909a346ecd2d97677c641 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/1b/01733c2b372c7b5544c7f2293c3b7341824112 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/1e/8b314962144c26d5e0e50fd29d2ca327864913 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/20/9e3ef4b6247ce746048d5711befda46206d235 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/26/7465454f74736bbe5b493c7f69dd3d024e26e5 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/32/e7b0308424a817ed5aa5bba94b06b72a1b8ce5 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/39/983ea412adebe6c5a3d4451a7673cf0962c472 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/3c/032078a4a21c5c51d3c93d91717c1dabbb8cd0 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/3e/02ce90348f3386128ebb2972515fb1a3788818 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/3f/f8b0f3820fd2eb3da53a5b803f94caf30dc2ab (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/43/78c740dfa0de7a973216b54b99c45a3c03f83c (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/45/a4fb75db864000d01701c0f7a51864bd4daabf (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/47/8a007451b33c7a234c60f0d13b164561b29094 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/48/082f72f087ce7e6fa75b9c41d7387daecd447b (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/4b/65d66c089cd4f6bfa69dff2d7ba4c27337cd23 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/54/3c0ef66d928051f16f8b9d7d33d6c4ea1f4e4f (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/5f/9397e5bcee1ac2a3fe6d834d42e36b74ef4ca8 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/60/d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/66/19c0a1a3eb6449eb15ce6cd0916fec0e410c10 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/67/fbfb3b74c2381ad1e058949231f2b4f0c8921f (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/78/d41b2abbd2f52c1ebf2f496268a915d59eb27b (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/7e/d6ff82de6bcc2a78243fc9c54d3ef5ac14da69 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/7f/8f011eb73d6043d2e6db9d2c101195ae2801f2 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/80/eeef1a7c49b376f3373ea26c6ba44d69d90d9c (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/82/d721eb037f7045056023d0904989781ce1f526 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/83/51c19397f4fcd5238d10034fa7fa384f14d580 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/91/36f315e5952043f1e7ecdc0d28c208eaeaed71 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/96/202a92c1d3bde1b20d6f3dec8e742d09732b4d (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/98/d9bcb75a685dfbfd60f611c309410152935b3d (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/ae/95e9aa3b8881aedb7a526c86ec5d60f371ca6c (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/af/f6316148f1524977997c486bcfe624c9094c4e (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/b1/bd38b62a0800a4f6a80c34e21c5acffae52c7e (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/b4/de3947675361a7770d29b8982c407b0ec6b2a0 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/b5/31696093a6482eca9ad4bcab63407172225b93 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/b6/a7d89c68e0ca66e96a9a51892cc33db66fb8a3 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/b8/626c4cff2849624fb67f87cd0ad72b163671ad (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/b9/7844c9437a4ab69c8165cadd97bc597b43135b (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/ba/8e7277a0ee7cdf84cd5c6138057adb85947a90 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/bc/21c8fabc28201fab6c60503168ecda25ad8626 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/d0/0491fd7e5bb6fa28c517a0bb32b8b506539d4d (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/d1/f7a85555fe6f10dd44754d35459ae741cb107c (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/d5/42aa84743f8ba1380358d4009408f03dbfb247 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/d6/b24041cf04154f8f902651969675021f4d93a5 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/d9/328d9b2c9536fdf01641dd03f4a254d2c86601 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/d9/cc608eedd5d2cc63c262272b7a0f6ab6aed5dd (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/db/b21289ee21b2ff0f3de2bc7d00038b30c4e353 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/e5/9bbaffe94b06acaadab4245f30ff3e11c66e5b (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/e9/27f0f9467e772eea36f24053c9b534303b106a (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/e9/d2f825e793bc9ac2be698348dbe669bad34cad (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/ea/684d3f868c358400465f2ec16a640c319ea6a3 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/eb/e59a71e9750e75fb983f241687cdf7f0c8ce94 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/ec/635144f60048986bc560c5576355344005e6e7 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/f2/7c6ae26adb8396d3861976ba268f87ad8afa0b (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/objects/f5/99e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/packed-refs (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/refs/bisect/bad (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/refs/bisect/good-39983ea412adebe6c5a3d4451a7673cf0962c472 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/refs/bisect/good-67fbfb3b74c2381ad1e058949231f2b4f0c8921f (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/refs/bisect/good-e927f0f9467e772eea36f24053c9b534303b106a (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/refs/bisect/good-e9d2f825e793bc9ac2be698348dbe669bad34cad (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/refs/bisect/skip-bc21c8fabc28201fab6c60503168ecda25ad8626 (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/refs/bisect/skip-d1f7a85555fe6f10dd44754d35459ae741cb107c (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/bisect/expected/{ => repo}/.git_keep/refs/heads/test (100%) rename test/integration/bisect/expected/{ => repo}/file (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/BISECT_ANCESTORS_OK (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/BISECT_EXPECTED_REV (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/BISECT_LOG (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/BISECT_NAMES (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/BISECT_START (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/BISECT_TERMS (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/config (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/description (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/index (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/logs/refs/heads/other (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/logs/refs/heads/test (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/00/750edc07d6415dcc07ae0351e9397b0222b7ba (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/03/ecdaa424af1fdaeab1bd1852319652b9518f11 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/04/a577be2858b8024716876aefe6b665a98e1e4f (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/05/57fc43da38567eae00831e9b385fd2cad22643 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/0c/fbf08886fca9a91cb753ec8734c84fcbe52c9f (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/0d/1bbe8d012c8c070167a006a4898b525cfbd930 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/0f/373801691c466240bd131d28b2168712b045ba (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/10/e171beacb963e4f8a4dc1d80fd291c135902bb (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/11/e4fd4011c9ed3800bb33b85580dd1d09f6aefd (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/15/d4c5b8608fe472fd224333e60d44ea826cc80e (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/1a/35564b85e24c96e647b477aaf8d35dcf0de84d (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/1a/b342c03b4226cca1c751dba71fa2df0e7d82ee (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/1e/8b314962144c26d5e0e50fd29d2ca327864913 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/20/9e3ef4b6247ce746048d5711befda46206d235 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/26/661287266e53bda69d8daa3aac1f714650f13c (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/30/68d0d730547aaa5b86dbfe638db83133ae1421 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/31/df6c951dc82b75b11bc48836e780134a16e6ad (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/33/3ff293caf2d3216edf22e3f1df64d43a7e1311 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/36/903784186b1b8b4a150dc656eccd49f94e114e (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/38/242e5215bc35b3e418c1d6d63fd0291001e10b (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/3a/05ed1ca9671bc362c7197eb09bddff040c9110 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/3b/e94d6b1b1b3b63db9e412b2e788d08979bc176 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/3c/032078a4a21c5c51d3c93d91717c1dabbb8cd0 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/3f/bb9e626d4b7d30e58346b3eefaa342b15ab776 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/3f/d9ad29c185eac6106cfa005a3aa594e21b9e06 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/43/99b07bd31d1f58a0ff10b5434d5ff4f36e38fb (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/45/a4fb75db864000d01701c0f7a51864bd4daabf (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/48/082f72f087ce7e6fa75b9c41d7387daecd447b (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/4a/9e01012c736e5e0998b7184d9a54e8c610ed02 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/54/93d27d38b9902cf28b1035c644bf470df76060 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/60/d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/6f/a769bf11bd9dc4ff4e85f4951950b0bc34326f (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/74/cd0e856d938eb6b665284c5485c00f87e20dc5 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/7c/fd51ebd06287effcfdab241235305cb6439d40 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/7e/d6ff82de6bcc2a78243fc9c54d3ef5ac14da69 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/7f/8f011eb73d6043d2e6db9d2c101195ae2801f2 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/83/51c19397f4fcd5238d10034fa7fa384f14d580 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/88/8633a131a49f1b8981d70c13d666defed6ba15 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/8b/0156bd25a1ecd82ef7c4c53e9d6d312bb6d403 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/90/dfebd90b0a89766c39928f22901b8c02b51fda (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/98/d9bcb75a685dfbfd60f611c309410152935b3d (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/9c/836a5c3f513818d300b410f8cb3a2e3bbd42a1 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/9d/33ec0915534bf6401be9412203697791e40a04 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/b1/bd38b62a0800a4f6a80c34e21c5acffae52c7e (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/b2/970eba9fd8dba8655094dc38fb4ee50b9bf23e (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/b4/de3947675361a7770d29b8982c407b0ec6b2a0 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/b6/14152a335aabd8b5daa2c6abccc9425eb14177 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/b6/a7d89c68e0ca66e96a9a51892cc33db66fb8a3 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/b8/626c4cff2849624fb67f87cd0ad72b163671ad (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/cd/c58c0f95a2313ded9185e102bc35253f6a1bed (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/d0/0491fd7e5bb6fa28c517a0bb32b8b506539d4d (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/d2/7a997859219951ecc95c351174c70ea0cf9d37 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/d3/6e09d97bf2c1527118bde353ad64b157f8b269 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/d4/e982570808a24722649e852a92bda5cf54c9dd (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/d6/b24041cf04154f8f902651969675021f4d93a5 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/d8/4e0684b1038552d5c8d86e67398d634f77ad3b (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/da/8dacb2a073ebc2adeddceb3cc2b39b6c95c858 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/db/76c03074879025735b647b825786a7b3fcfe7c (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/e5/59f83c6e8dd11680de70b487725e37ff2e283f (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/ec/635144f60048986bc560c5576355344005e6e7 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/f5/99e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/objects/ff/231021500c7beb87de0d6d5edc29b6f9c000b1 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/packed-refs (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/refs/bisect/bad (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/refs/bisect/good-38242e5215bc35b3e418c1d6d63fd0291001e10b (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/refs/bisect/good-3fbb9e626d4b7d30e58346b3eefaa342b15ab776 (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/refs/heads/other (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/.git_keep/refs/heads/test (100%) rename test/integration/bisectFromOtherBranch/expected/{ => repo}/myfile (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/config (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/description (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/index (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/logs/refs/heads/four (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/logs/refs/heads/one (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/logs/refs/heads/three (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/logs/refs/heads/two (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/objects/b4/9fda1c7a9af6a4f0b6b07a2cb31aecb8c01a6c (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/objects/f7/53f4dfc98d148a7e685c46c8d148bcac56707d (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/refs/heads/four (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/refs/heads/one (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/refs/heads/three (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/.git_keep/refs/heads/two (100%) rename test/integration/branchAutocomplete/expected/{ => repo}/myfile.txt (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/config (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/description (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/index (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/logs/refs/heads/new-branch (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/logs/refs/heads/new-branch-2 (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/logs/refs/heads/new-branch-3 (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/logs/refs/heads/old-branch (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/logs/refs/heads/old-branch-3 (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/objects/21/b436d66d2c515ad17285e53d9e6380d599b044 (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/refs/heads/new-branch (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/refs/heads/new-branch-2 (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/refs/heads/new-branch-3 (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/refs/heads/old-branch (100%) rename test/integration/branchDelete/expected/{ => repo}/.git_keep/refs/heads/old-branch-3 (100%) rename test/integration/branchDelete/expected/{ => repo}/file0 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/config (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/description (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/index (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/logs/refs/heads/develop (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/2e/83133d8d6b88c588de66c3ff8405501b5215b4 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/36/27f93f3cc779dc2f99484fb8ffa49953e43b2f (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/3e/1706cdf670f5641be0715178471abfc9ed1748 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/42/1b29bba240f23ea39e216bb0873cd4012624b5 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/42/597904331c82f6d5c8c902755c8dfa5767ea95 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/69/f11ae88c8712fe38ffd0fe9ff9df05371500a6 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/70/95508e3cd0fd40572f8e711170db38ef2342d7 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/7a/45b8933308e43f2597ee5d290862a62a9b46b3 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/8c/7a45270a95d66c8e3b843df3f466be5dc19960 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/8d/3bd1cbd5560c759c78a948bc0d24acb9cfae73 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/9a/6521a3788b4d9e679b1709130ff8dc3f73ab18 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/a8/381c9130b03aef530b60b5a4546b93dc59ae12 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/cb/289e645aed5251ce74fa2eaf0cd1145b9cb014 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/cc/52f7d833c761b3b11a5fa1ae76ba9aba2edd6f (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/e9/57aaf2eef0c03a9052b472d4862d9ee684c3e5 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/f5/067da83b48f8588edce682fd2715a575f34373 (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/objects/fe/427b52bbbe9dac81b463a162f37ab979ca772b (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/refs/heads/develop (100%) rename test/integration/branchRebase/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/branchRebase/expected/{ => repo}/directory/file (100%) rename test/integration/branchRebase/expected/{ => repo}/directory/file2 (100%) rename test/integration/branchRebase/expected/{ => repo}/file1 (100%) rename test/integration/branchRebase/expected/{ => repo}/file3 (100%) rename test/integration/branchRebase/expected/{ => repo}/file4 (100%) rename test/integration/branchRebase/expected/{ => repo}/file5 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/config (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/description (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/index (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/logs/refs/heads/develop (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/10/6606554f129e8b6e4b942908734deef5628dcd (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/27/ba706fa463253f9189b2f258430877d2b5ed4f (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/37/14b55ba17f3d8b0233c6e5924a5e497eb09bb7 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/7a/45b8933308e43f2597ee5d290862a62a9b46b3 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/7c/d86f0c3e1894b4270d0bf9fa246c33568f9bf1 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/8b/24e74245461f6ad529c77c040fe17e415cf3da (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/8c/7a45270a95d66c8e3b843df3f466be5dc19960 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/a7/3e01f9d181ff16b3d821dd962e98accbd62936 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/bd/8db1919bbbbd4509ad4d9fa3baf546460e17a2 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/c2/3c3e0496a9b3decc42344bfd94514f0834b93c (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/cb/289e645aed5251ce74fa2eaf0cd1145b9cb014 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/ee/a0cf47f42fe8d027b4cecaf534ecc0673f7981 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/objects/fe/427b52bbbe9dac81b463a162f37ab979ca772b (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/refs/heads/develop (100%) rename test/integration/branchReset/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/branchReset/expected/{ => repo}/directory/file (100%) rename test/integration/branchReset/expected/{ => repo}/directory/file2 (100%) rename test/integration/branchReset/expected/{ => repo}/file1 (100%) rename test/integration/branchReset/expected/{ => repo}/file3 (100%) rename test/integration/branchReset/expected/{ => repo}/file4 (100%) rename test/integration/branchReset/expected/{ => repo}/file5 (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/config (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/description (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/index (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/logs/refs/heads/new-branch (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/logs/refs/heads/new-branch-2 (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/logs/refs/heads/new-branch-3 (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/logs/refs/heads/old-branch (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/logs/refs/heads/old-branch-2 (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/logs/refs/heads/old-branch-3 (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/objects/75/e9e90a1d58c37d97d46a543dfbfd0f33fc52d8 (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/refs/heads/new-branch (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/refs/heads/new-branch-2 (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/refs/heads/new-branch-3 (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/refs/heads/old-branch (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/refs/heads/old-branch-2 (100%) rename test/integration/branchSuggestions/expected/{ => repo}/.git_keep/refs/heads/old-branch-3 (100%) rename test/integration/branchSuggestions/expected/{ => repo}/file0 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/REBASE_HEAD (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/config (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/description (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/index (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/logs/refs/heads/base_branch (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/logs/refs/heads/develop (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/logs/refs/heads/feature/cherry-picking (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/logs/refs/heads/other_branch (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/05/56e5da1cda4e150d6cc1182be6efdb061f59fe (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/16/f2bcca6ce7bcc17277103a5555072a6c3322a2 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/19/079c78db18112c5a2720896a040014a2d05f6d (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/21/28c3c3def18d6e2a389957252fdb69ba85fce0 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/23/4e2fa9a01b8d7e849b0c2a1bbd550e788ea18d (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/24/93c87610e0a9b8edfca592cb01a027f60ce587 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/2c/f63d6da8c52131dd79622f8572b44a1267e420 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/33/9e2d062760be9ecdb4bb90f97bdb0e634e7831 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/3e/0d4389ab458a8643281e494e3ebae7ce307eec (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/45/20f99d650662a3f597a200fea5f2599f528180 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/5d/2484f3cb6ce658e296526c48e1a376b2790dfc (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/65/c0438e428cd1aa94588eaa52eb7ebad7ec62fd (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/68/728b56ed31d03ca94496b9e2a45c62ba0f4e8f (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/69/6a8fd43c580b3bed203977faab4566b052a4e4 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/6b/6092c6840d05583489cc32a1260db0d5390a98 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/73/17cf7580efd92f974c8dfb3cde84eded8dafec (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/78/a5ec82970200538b70f5ac61c18acb45ccb8ee (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/79/23e4a952f4b169373b0389be6a9db3cd929547 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/9b/b8cd97914c8e8a7b8a6ec6f94bca0b09fa0048 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/b8/ab98a9ab0599193a3f41a9cc5cb988283e6722 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/bd/6f34089ba29cbae102003bd973e9f37a235c2e (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/bf/cc5725cd2ef871ff804996f4e02beef3e4dec2 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/ce/ecbe69460104e09eb2cd7c865df520c5679a68 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/d8/e5ca46d2bbd7c115e5849e637efe2361203368 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/e4/aa98b835d0a871d9ea02e6d286f0fbb2204cdc (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/ef/029771f117b5f31c972dfa546037662e243ca7 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/f3/7d8713ef1390c277b45a084a08c0c142ff7ed9 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/f4/ffac820a371104fe611d81bc13a45b70a3ebb3 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/fa/cb56c48e4718f71c08116153c93d87bc699671 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/refs/heads/base_branch (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/refs/heads/develop (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/refs/heads/feature/cherry-picking (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/cherryPicking/expected/{ => repo}/.git_keep/refs/heads/other_branch (100%) rename test/integration/cherryPicking/expected/{ => repo}/cherrypicking3 (100%) rename test/integration/cherryPicking/expected/{ => repo}/cherrypicking4 (100%) rename test/integration/cherryPicking/expected/{ => repo}/cherrypicking5 (100%) rename test/integration/cherryPicking/expected/{ => repo}/directory/file (100%) rename test/integration/cherryPicking/expected/{ => repo}/directory/file2 (100%) rename test/integration/cherryPicking/expected/{ => repo}/file (100%) rename test/integration/cherryPicking/expected/{ => repo}/file1 (100%) rename test/integration/cherryPicking/expected/{ => repo}/file3 (100%) rename test/integration/cherryPicking/expected/{ => repo}/file4 (100%) rename test/integration/cherryPicking/expected/{ => repo}/file5 (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/config (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/description (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/index (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/14/40bc6cc888a09dca2329d1060eec6de78d9d21 (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/3d/f3d8761bc0f0828596b11845aeac175b7b7393 (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/4b/a4f1ed711a9081fab21bc222469aa5176a01f8 (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/a7/d53cc21fd53100f955377be379423b0e386274 (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/objects/e7/560e2cd4783a261ad32496cefed2d9f69a46e7 (100%) rename test/integration/commit/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/commit/expected/{ => repo}/myfile1 (100%) rename test/integration/commit/expected/{ => repo}/myfile2 (100%) rename test/integration/commit/expected/{ => repo}/myfile3 (100%) rename test/integration/commit/expected/{ => repo}/myfile4 (100%) rename test/integration/commit/expected/{ => repo}/myfile5 (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/config (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/description (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/index (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/17/6069f0ded1db43eecb3b629a6077dba6c68295 (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/37/128a3020849daa0847462d14c384cc74c42ae0 (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/39/33a268c502712421b7bfa04888319d6f108574 (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/57/4013716a7f007a27b647b90cdbc78d006d792b (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/9f/1b5440546da24daad7014ccf3e1f4d81f9414b (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/commitMultiline/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/commitMultiline/expected/{ => repo}/myfile1 (100%) rename test/integration/commitMultiline/expected/{ => repo}/myfile2 (100%) rename test/integration/commitMultiline/expected/{ => repo}/myfile3 (100%) rename test/integration/commitMultiline/expected/{ => repo}/myfile4 (100%) rename test/integration/commitMultiline/expected/{ => repo}/myfile5 (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/config (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/description (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/index (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/logs/refs/heads/lol (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/objects/00/29f9bf66e346d47ede6a501abb5b82bee60096 (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/objects/99/01fd9b7766be600bed07f55f1794a759527a98 (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/objects/e1/cb250774fb8606d33062518d0ae03831130249 (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/refs/heads/lol (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/file0 (100%) rename test/integration/commitsNewBranch/expected/{ => repo}/file1 (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/config (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/description (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/index (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/objects/17/27eeb6864e52a8967a1a494099359dbdfcc235 (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/objects/3a/1ee58e5736049ad5b9266715d3642614816c1f (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/objects/7e/03c9a9538a907c936de5c9a2154707b9ee541c (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/objects/9e/aae8f342ca71c060b760870a715a6303905935 (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/objects/ab/15072795e72a2061bc40060494c3ca2138b297 (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/objects/b7/81ffd3aa940dde39f73c9149b67e2b128de085 (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/commitsRevert/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/commitsRevert/expected/{ => repo}/file0 (100%) rename test/integration/commitsRevert/expected/{ => repo}/file2 (100%) rename test/integration/confirmQuit/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/confirmQuit/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/confirmQuit/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/confirmQuit/expected/{ => repo}/.git_keep/config (100%) rename test/integration/confirmQuit/expected/{ => repo}/.git_keep/description (100%) rename test/integration/confirmQuit/expected/{ => repo}/.git_keep/index (100%) rename test/integration/confirmQuit/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/confirmQuit/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/confirmQuit/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/confirmQuit/expected/{ => repo}/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/confirmQuit/expected/{ => repo}/.git_keep/objects/54/4efed4e669ec3bd64b44799175bffac95035f5 (100%) rename test/integration/confirmQuit/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/confirmQuit/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/confirmQuit/expected/{ => repo}/myfile1 (100%) rename test/integration/customCommands/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/customCommands/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/customCommands/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/customCommands/expected/{ => repo}/.git_keep/config (100%) rename test/integration/customCommands/expected/{ => repo}/.git_keep/description (100%) rename test/integration/customCommands/expected/{ => repo}/.git_keep/index (100%) rename test/integration/customCommands/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/customCommands/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/customCommands/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/customCommands/expected/{ => repo}/.git_keep/objects/15/bdb2c31c825116ad5af06ee25517d90b24f13b (100%) rename test/integration/customCommands/expected/{ => repo}/.git_keep/objects/20/f11a5545b04a86ca81f7a9967d5207349052d7 (100%) rename test/integration/customCommands/expected/{ => repo}/.git_keep/objects/8a/2e45643093ea7cf7b06382e38470034c24e812 (100%) rename test/integration/customCommands/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/customCommands/expected/{ => repo}/blah (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/config (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/description (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/index (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/05/3cf208ac3728c36c6ed86f2a03a1fb72a8e6bc (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/4f/dfedfd9d406506be8b02f5b863dbc08d43cc9f (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/54/28838691c97ac192c8b8e1c3f573d8541a94b6 (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/7d/b446a082f8c10183f1f27178698f07f3750b6b (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/7d/d93a4be3d27d40fbe791d6d77e0d2fedc4d785 (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/ab/38b1ca116f77648925d952e731f419db360cdb (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/objects/f7/08d3e3819470a69f6c8562ff1e68eef02f8cac (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/myfile1 (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/myfile2 (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/myfile3 (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/myfile4 (100%) rename test/integration/customCommandsComplex/expected/{ => repo}/output.txt (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/config (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/description (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/index (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/logs/refs/heads/branch2 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/05/19814b4923f4639f1a47348b1539e3c5c54904 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/14/4da8a531224129210249f43dded86056891506 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/57/51731b38a36f8eb54a4bb304522ca539e04522 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/75/b31f81dd4387724638dbd3aff7380155c672cd (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/96/a6d041bbb131df0e74d179c3adcd2ace0e7f9c (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/a1/00b407f33fd2e97a3cb6f62b68ed6b7cc6c676 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/d1/5e253139400c94b42fc266641d1698720d4ecf (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/objects/f6/77ef8a14ca2770e48129cc13acfa1c369908cc (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/refs/heads/branch2 (100%) rename test/integration/diffing/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/diffing/expected/{ => repo}/file0 (100%) rename test/integration/diffing/expected/{ => repo}/file1 (100%) rename test/integration/diffing/expected/{ => repo}/file2 (100%) rename test/integration/diffing/expected/{ => repo}/file4 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/config (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/description (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/index (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/logs/refs/heads/branch2 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/06/da465196938ea235323950ee451ffb36a431cf (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/08/04f2069f5af172770da3d231be982ca320bf8b (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/1b/74d64fe4055d4502ac600072586068b27d4aa7 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/6d/04f5ed53b383c0a4c63cac168df557b6df1e44 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/7b/f3d13079ced18f5b00e29c48c777e23f687d0a (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/a1/1d868e88adb55a48fc55ee1377b3255c0cd329 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/c6/756882cc166f52b096a5e4fb9e4f5d507870c8 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/objects/e8/76c3dfe2826621bea1bd3c87c2b9e2be88e69e (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/refs/heads/branch2 (100%) rename test/integration/diffing2/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/diffing2/expected/{ => repo}/file0 (100%) rename test/integration/diffing2/expected/{ => repo}/file1 (100%) rename test/integration/diffing2/expected/{ => repo}/file2 (100%) rename test/integration/diffing2/expected/{ => repo}/file4 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/config (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/description (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/index (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/logs/refs/heads/branch2 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/13/d8ce6d541ffd4b323376e2530ccdd3bcc7b8d5 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/1e/dd26fd03ee6243bd1513788874c6c57ef1d41a (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/27/5e6a821120c07a9068a9701ed14a82eeed3117 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/4e/2d07409901af28a47f5d3b126953a5fb8b36ee (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/57/695899c35539821690c4c132bd0e872a01c192 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/93/b73046d6820607f1da09399b55a145d5389ab8 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/b2/5b8446022fb5fcded2bab1ed2b02828a5c4d0b (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/objects/ff/b13702e6bc59e2806bc3a5f93500e46925b131 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/refs/heads/branch2 (100%) rename test/integration/diffing3/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/diffing3/expected/{ => repo}/file0 (100%) rename test/integration/diffing3/expected/{ => repo}/file1 (100%) rename test/integration/diffing3/expected/{ => repo}/file2 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/config (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/description (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/index (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/logs/refs/heads/conflict (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/logs/refs/heads/conflict_second (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/11/bdfc142c42c6ffaa904890ab61ec76262ec9ca (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/15/fe7f43604da957ffb663b4db95b60d0af66469 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/1c/9488b0e1b8abd1ec8645b3345bdac91290b464 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/26/80cfddbd9fa03c059ac60d2bec5e59a1c34281 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/2c/e75e2a24f7d6841a504cf3616ef5a59edb3a2d (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/30/07c9c07bf80aaa72b1f1f704e7fea622446678 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/3f/7bd8f68987d4e16b8f6fa7f6b0738b42180d1f (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/47/966dcaa8ee736e89279b895faf8707de898e04 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/48/f9387742d3cc3017c1a7e292c9187e35321753 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/4d/8452fc76beed0c7b15e40e45d06922bf746c5f (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/59/cf7b78af9aab84813bcb0bc8be27fdd9216b2b (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/5a/d28e22767f979da2c198dc6c1003b25964e3da (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/5b/e4a414b32cf4204f889469942986d3d783da84 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/7a/22af9d1908d85e3c4b6d916a9b6c733c55c990 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/85/4f08fa802293e0679d07771547fe9fe5d159e8 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/89/44a13fdfc597e4cf1d23797df51977680f8e77 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/8c/82faa1358ce6cddba19d59b2924cbcc5ef1c8e (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/90/7b308167f0880fb2a5c0e1614bb0c7620f9dc3 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/90/be1f3056c4f471f977a28497b8d4b392c55a02 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/98/e834e9cdae1191de7fafb2b6f334bddd0793e8 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/99/76d7948def8b082e9d20135d6a04624d711752 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/9f/5118ee216a6e44728305f90633b0c0e2ad235c (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/a1/be04124078e38a592c153942bf75edf210f1ed (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/a1/e09c2fda67b9f8d4440073c0c33f6e45689b7c (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/ab/addc0b9edd523c69166a2c9f3a9e31a4c873e3 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/c9/1b3b139ea108475c19839fcda3a4e33db4ccc9 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/ce/e08babc6b109f011f42eaba5f79e6e693c09e7 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/d4/d1b67951582a751c12ff7ea29ede7d37fd9ee8 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/d7/98b86744c3997c186e0f0dc666f02943c797a7 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/e9/55de60e73263440d4651e79e947ec8b2902373 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/objects/fa/938d99f6ee5cc562cd0f33fa64fd68d78ce2e9 (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/refs/heads/conflict (100%) rename test/integration/discardFileChanges/expected/{ => repo}/.git_keep/refs/heads/conflict_second (100%) rename test/integration/discardFileChanges/expected/{ => repo}/both-added.txt (100%) rename test/integration/discardFileChanges/expected/{ => repo}/both-modded.txt (100%) rename test/integration/discardFileChanges/expected/{ => repo}/change-delete.txt (100%) rename test/integration/discardFileChanges/expected/{ => repo}/changed-them-added-us.txt (100%) rename test/integration/discardFileChanges/expected/{ => repo}/delete-change.txt (100%) rename test/integration/discardFileChanges/expected/{ => repo}/deleted-staged.txt (100%) rename test/integration/discardFileChanges/expected/{ => repo}/deleted-them.txt (100%) rename test/integration/discardFileChanges/expected/{ => repo}/deleted.txt (100%) rename test/integration/discardFileChanges/expected/{ => repo}/double-modded.txt (100%) rename test/integration/discardFileChanges/expected/{ => repo}/modded-staged.txt (100%) rename test/integration/discardFileChanges/expected/{ => repo}/modded.txt (100%) rename test/integration/discardFileChanges/expected/{ => repo}/renamed.txt (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/config (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/description (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/index (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/00/cbccfd35a05ef9373bba9d5633cf6e67f83dd5 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/0a/91dcf3772f7fd7409b3df04eb6ef177219303a (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/0c/db6daba7e25b6d6d10da326e0ab74401021370 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/18/e987d34afb121659724591cd709e2a789184fc (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/22/5ad83faa797c1831a2bc956a21e2d472f21443 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/42/786aead9ca20a3427c38e5e5262fa787ce9868 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/78/80a9728615a4d196df39600a0c8c71b40d96d6 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/7b/8a8396be4352039598acb43acaadc1c380551f (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/af/6725ba23f43a286deff0747476d7874113df1e (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/b7/a702b642978f2a9b1af9c1c67b22127af78c92 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/d1/4505f281a54cda96fc5fb8cd4b4ee14bae6264 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/file0 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/file1 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/file2 (100%) rename test/integration/discardOldFileChanges/expected/{ => repo}/file3 (100%) delete mode 100644 test/integration/fetchPrune/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/fetchPrune/expected/.git_keep/index delete mode 100644 test/integration/fetchPrune/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/other_branch delete mode 100644 test/integration/fetchPrune/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/fetchPrune/expected/.git_keep/objects/f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 delete mode 100644 test/integration/fetchPrune/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/fetchPrune/expected/.git_keep/refs/heads/other_branch delete mode 100644 test/integration/fetchPrune/expected/.git_keep/refs/remotes/origin/master rename test/integration/fetchPrune/expected/{.git_keep => origin}/HEAD (100%) create mode 100644 test/integration/fetchPrune/expected/origin/config rename test/integration/fetchPrune/expected/{.git_keep => origin}/description (100%) rename test/integration/fetchPrune/expected/{.git_keep => origin}/info/exclude (100%) rename test/integration/fetchPrune/expected/{.git_keep => origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) create mode 100644 test/integration/fetchPrune/expected/origin/objects/75/f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 rename test/integration/fetchPrune/expected/{.git_keep => origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) create mode 100644 test/integration/fetchPrune/expected/origin/packed-refs rename test/integration/fetchPrune/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/fetchPrune/expected/repo/.git_keep/FETCH_HEAD rename test/integration/fetchPrune/{expected_remote => expected/repo/.git_keep}/HEAD (100%) rename test/integration/fetchPrune/expected/{ => repo}/.git_keep/config (94%) rename test/integration/fetchPrune/{expected_remote => expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/fetchPrune/expected/repo/.git_keep/index rename test/integration/fetchPrune/{expected_remote => expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/fetchPrune/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/fetchPrune/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/fetchPrune/expected/repo/.git_keep/logs/refs/heads/other_branch create mode 100644 test/integration/fetchPrune/expected/repo/.git_keep/logs/refs/remotes/origin/master rename test/integration/fetchPrune/{expected_remote => expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) create mode 100644 test/integration/fetchPrune/expected/repo/.git_keep/objects/75/f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 rename test/integration/fetchPrune/{expected_remote => expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/fetchPrune/expected/{ => repo}/.git_keep/packed-refs (100%) create mode 100644 test/integration/fetchPrune/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/fetchPrune/expected/repo/.git_keep/refs/heads/other_branch create mode 100644 test/integration/fetchPrune/expected/repo/.git_keep/refs/remotes/origin/master rename test/integration/fetchPrune/expected/{ => repo}/myfile1 (100%) delete mode 100644 test/integration/fetchPrune/expected_remote/objects/f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 delete mode 100644 test/integration/fetchPrune/expected_remote/packed-refs rename test/integration/filterPath/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/config (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/description (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/index (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/22/adc4567aba3d1a0acf28b4cef312922d516aeb (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/2e/a97a56215f6adbe991eaf0dcf61c7086880ea5 (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/4b/9d1f9f9fc76b123a5c90cd8396390cac41a3e3 (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/8b/476a1094290d7251c56305e199eb2a203d8682 (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/af/3ef564e968dbe92fb4e08a67dd5f835f43d4e8 (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/b7/c728d5b4e9dfc210ec19f0549f25c94b766e4e (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/d7/236d5f85ad303f5f23141661e4c8959610b70b (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/f2/4812da035a21812bc4c73018349ac2f0a6ec39 (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/objects/f3/d94fa1d4be39b8daae35b82525bf357aa712de (100%) rename test/integration/filterPath/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/filterPath/expected/{ => repo}/file (100%) rename test/integration/filterPath/expected/{ => repo}/file0 (100%) rename test/integration/filterPath/expected/{ => repo}/file2 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/config (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/description (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/index (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/6c/dce80c062ba2c8f8758879834a936b84ead78c (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/70/3f7069185227287623aaba7cdb0e56ae7a6c60 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/92/ec47058a2894afbbbd69c5f79bff20c503e686 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/a5/c053a7a46bce2775edb371a9aa97424b542ab7 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/c5/f9a8793f15aa0db816944424adb4303eb036a8 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/c8/68546458601b9c71b76b893f9020ecf7405528 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/objects/e7/c2bd00356720683d5bc4362ef5b92655fa8914 (100%) rename test/integration/filterPath2/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/filterPath2/expected/{ => repo}/file (100%) rename test/integration/filterPath2/expected/{ => repo}/file0 (100%) rename test/integration/filterPath2/expected/{ => repo}/file1 (100%) rename test/integration/filterPath2/expected/{ => repo}/file2 (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/config (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/description (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/index (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/23/1410172e8f51138f06d8dff963898fb1e97b30 (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/72/226d27a85fff688d32c134a22ebe650d6c2e41 (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/8e/d4f7b4eae8cc97d9add459348cc95e936b8f25 (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/b3/5d7fa77c939890020952987eeb461f410297d8 (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/c1/a1ba9d2873d7163606bb5fdf46e50975db042b (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/c8/68546458601b9c71b76b893f9020ecf7405528 (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/db/6681a3e9fb9fb6ef524771cdc763904dd2b54d (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/filterPath3/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/filterPath3/expected/{ => repo}/file (100%) rename test/integration/filterPath3/expected/{ => repo}/file0 (100%) rename test/integration/filterPath3/expected/{ => repo}/file1 (100%) rename test/integration/filterPath3/expected/{ => repo}/file2 (100%) delete mode 100644 test/integration/forcePush/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/forcePush/expected/.git_keep/ORIG_HEAD delete mode 100644 test/integration/forcePush/expected/.git_keep/index delete mode 100644 test/integration/forcePush/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/forcePush/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/forcePush/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/forcePush/expected/.git_keep/objects/1f/e60e6b7023a1b9751850f83ac5bda49ddd9278 delete mode 100644 test/integration/forcePush/expected/.git_keep/objects/66/bd8d357f6226ec264478db3606bc1c4be87e63 delete mode 100644 test/integration/forcePush/expected/.git_keep/objects/a9/848fd98935937cd7d3909023ed1b588ccd4bfb delete mode 100644 test/integration/forcePush/expected/.git_keep/objects/ae/d1af42535c9c6a27b9f660119452328fddd7cd delete mode 100644 test/integration/forcePush/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/forcePush/expected/.git_keep/refs/remotes/origin/master rename test/integration/forcePush/expected/{.git_keep => origin}/HEAD (100%) rename test/integration/{pull/expected_remote => forcePush/expected/origin}/config (78%) rename test/integration/forcePush/expected/{.git_keep => origin}/description (100%) rename test/integration/forcePush/expected/{.git_keep => origin}/info/exclude (100%) rename test/integration/forcePush/expected/{.git_keep => origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/forcePush/expected/{.git_keep => origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/forcePush/expected/{.git_keep => origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) create mode 100644 test/integration/forcePush/expected/origin/objects/55/58e3589b913d8280499a5f9bf698971a83c5bd create mode 100644 test/integration/forcePush/expected/origin/objects/77/ead8cf99f5fa1084e9ffa40eb18f37157b22c8 rename test/integration/forcePush/expected/{.git_keep => origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/forcePush/expected/{.git_keep => origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/forcePush/expected/origin/objects/b8/568c2ecaef7e2f47647057ad47b040e8c5df53 rename test/integration/forcePush/expected/{.git_keep => origin}/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 (100%) rename test/integration/forcePush/expected/{.git_keep => origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/forcePush/expected/{.git_keep => origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/forcePush/expected/origin/objects/e3/8b0dbe9634034957d8ebe0088587abd9ae938d create mode 100644 test/integration/forcePush/expected/origin/packed-refs create mode 100644 test/integration/forcePush/expected/origin/refs/heads/master rename test/integration/forcePush/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/forcePush/expected/repo/.git_keep/FETCH_HEAD rename test/integration/forcePush/{expected_remote => expected/repo/.git_keep}/HEAD (100%) create mode 100644 test/integration/forcePush/expected/repo/.git_keep/ORIG_HEAD rename test/integration/{pullAndSetUpstream/expected => forcePush/expected/repo}/.git_keep/config (92%) rename test/integration/forcePush/{expected_remote => expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/forcePush/expected/repo/.git_keep/index rename test/integration/forcePush/{expected_remote => expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/forcePush/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/forcePush/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/forcePush/expected/repo/.git_keep/logs/refs/remotes/origin/master rename test/integration/forcePush/{expected_remote => expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/forcePush/{expected_remote => expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/forcePush/{expected_remote => expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) create mode 100644 test/integration/forcePush/expected/repo/.git_keep/objects/55/58e3589b913d8280499a5f9bf698971a83c5bd create mode 100644 test/integration/forcePush/expected/repo/.git_keep/objects/77/ead8cf99f5fa1084e9ffa40eb18f37157b22c8 rename test/integration/forcePush/{expected_remote => expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/forcePush/{expected_remote => expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/forcePush/expected/repo/.git_keep/objects/b8/568c2ecaef7e2f47647057ad47b040e8c5df53 rename test/integration/forcePush/{expected_remote => expected/repo/.git_keep}/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 (100%) rename test/integration/forcePush/{expected_remote => expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/forcePush/{expected_remote => expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/forcePush/expected/repo/.git_keep/objects/e3/8b0dbe9634034957d8ebe0088587abd9ae938d create mode 100644 test/integration/forcePush/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/forcePush/expected/repo/.git_keep/refs/remotes/origin/master rename test/integration/forcePush/expected/{ => repo}/myfile1 (100%) rename test/integration/forcePush/expected/{ => repo}/myfile2 (100%) rename test/integration/forcePush/expected/{ => repo}/myfile4 (100%) delete mode 100644 test/integration/forcePush/expected_remote/objects/1f/e60e6b7023a1b9751850f83ac5bda49ddd9278 delete mode 100644 test/integration/forcePush/expected_remote/objects/66/bd8d357f6226ec264478db3606bc1c4be87e63 delete mode 100644 test/integration/forcePush/expected_remote/objects/a9/848fd98935937cd7d3909023ed1b588ccd4bfb delete mode 100644 test/integration/forcePush/expected_remote/objects/ae/d1af42535c9c6a27b9f660119452328fddd7cd delete mode 100644 test/integration/forcePush/expected_remote/packed-refs delete mode 100644 test/integration/forcePush/expected_remote/refs/heads/master delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/ORIG_HEAD delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/index delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/other_branch delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/other_branch delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/16/d8875e19987b16f1991a41fd3f4536d16f7cb4 delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/b8/2ed4a67bef9ef50807adf409f103ef7b0832ab delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/objects/d3/708eeec2b9d69acbe87862330e844e85f77de1 delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/refs/heads/other_branch delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/master delete mode 100644 test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/other_branch delete mode 100644 test/integration/forcePushMultiple/expected_remote/objects/16/d8875e19987b16f1991a41fd3f4536d16f7cb4 delete mode 100644 test/integration/forcePushMultiple/expected_remote/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 delete mode 100644 test/integration/forcePushMultiple/expected_remote/objects/b8/2ed4a67bef9ef50807adf409f103ef7b0832ab delete mode 100644 test/integration/forcePushMultiple/expected_remote/objects/d3/708eeec2b9d69acbe87862330e844e85f77de1 delete mode 100644 test/integration/forcePushMultiple/expected_remote/packed-refs delete mode 100644 test/integration/forcePushMultiple/expected_remote/refs/heads/master delete mode 100644 test/integration/forcePushMultiple/expected_remote/refs/heads/other_branch delete mode 100644 test/integration/forcePushMultiple/recording.json rename test/integration/{forcePushMultiple/expected/.git_keep => forcePushMultipleMatching/expected/origin}/HEAD (100%) create mode 100644 test/integration/forcePushMultipleMatching/expected/origin/config rename test/integration/{forcePushMultiple/expected/.git_keep => forcePushMultipleMatching/expected/origin}/description (100%) rename test/integration/{forcePushMultiple/expected/.git_keep => forcePushMultipleMatching/expected/origin}/info/exclude (100%) rename test/integration/{forcePushMultiple/expected/.git_keep => forcePushMultipleMatching/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{forcePushMultiple/expected/.git_keep => forcePushMultipleMatching/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{forcePushMultiple/expected/.git_keep => forcePushMultipleMatching/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) create mode 100644 test/integration/forcePushMultipleMatching/expected/origin/objects/7a/35f0bb6bd8dc18ae462465e51f02362ba6babe rename test/integration/{forcePushMultiple/expected/.git_keep => forcePushMultipleMatching/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{forcePushMultiple/expected/.git_keep => forcePushMultipleMatching/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/forcePushMultipleMatching/expected/origin/objects/bd/739fb752ed02ccd49422196e31599c87ff90ad rename test/integration/{forcePushMultiple/expected/.git_keep => forcePushMultipleMatching/expected/origin}/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 (100%) rename test/integration/{forcePushMultiple/expected/.git_keep => forcePushMultipleMatching/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{forcePushMultiple/expected/.git_keep => forcePushMultipleMatching/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/forcePushMultipleMatching/expected/origin/objects/e6/7f344f42afdb79c87a590f22537160241d8d61 create mode 100644 test/integration/forcePushMultipleMatching/expected/origin/objects/fe/67c3eaf819025990d3688d5f147a064e669ca5 create mode 100644 test/integration/forcePushMultipleMatching/expected/origin/packed-refs create mode 100644 test/integration/forcePushMultipleMatching/expected/origin/refs/heads/master create mode 100644 test/integration/forcePushMultipleMatching/expected/origin/refs/heads/other_branch rename test/integration/{forcePushMultiple/expected => forcePushMultipleMatching/expected/repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{forcePushMultiple/expected_remote => forcePushMultipleMatching/expected/repo/.git_keep}/HEAD (100%) create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/ORIG_HEAD rename test/integration/{forcePushMultiple/expected => forcePushMultipleMatching/expected/repo}/.git_keep/config (94%) rename test/integration/{forcePushMultiple/expected_remote => forcePushMultipleMatching/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/index rename test/integration/{forcePushMultiple/expected_remote => forcePushMultipleMatching/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/heads/other_branch create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/remotes/origin/master create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/remotes/origin/other_branch rename test/integration/{forcePushMultiple/expected_remote => forcePushMultipleMatching/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{forcePushMultiple/expected_remote => forcePushMultipleMatching/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{forcePushMultiple/expected_remote => forcePushMultipleMatching/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/7a/35f0bb6bd8dc18ae462465e51f02362ba6babe rename test/integration/{forcePushMultiple/expected_remote => forcePushMultipleMatching/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{forcePushMultiple/expected_remote => forcePushMultipleMatching/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/bd/739fb752ed02ccd49422196e31599c87ff90ad rename test/integration/{forcePushMultiple/expected_remote => forcePushMultipleMatching/expected/repo/.git_keep}/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 (100%) rename test/integration/{forcePushMultiple/expected_remote => forcePushMultipleMatching/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{forcePushMultiple/expected_remote => forcePushMultipleMatching/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/e6/7f344f42afdb79c87a590f22537160241d8d61 create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/fe/67c3eaf819025990d3688d5f147a064e669ca5 create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/heads/other_branch create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/remotes/origin/master create mode 100644 test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/remotes/origin/other_branch rename test/integration/{forcePushMultiple/expected => forcePushMultipleMatching/expected/repo}/myfile1 (100%) rename test/integration/{forcePushMultiple/expected => forcePushMultipleMatching/expected/repo}/myfile2 (100%) create mode 100644 test/integration/forcePushMultipleMatching/recording.json rename test/integration/{forcePushMultiple => forcePushMultipleMatching}/setup.sh (90%) rename test/integration/{forcePushMultiple => forcePushMultipleMatching}/test.json (65%) rename test/integration/{initialOpen/expected/.git_keep => forcePushMultipleUpstream/expected/origin}/HEAD (100%) create mode 100644 test/integration/forcePushMultipleUpstream/expected/origin/config rename test/integration/{initialOpen/expected/.git_keep => forcePushMultipleUpstream/expected/origin}/description (100%) rename test/integration/{initialOpen/expected/.git_keep => forcePushMultipleUpstream/expected/origin}/info/exclude (100%) rename test/integration/{initialOpen/expected/.git_keep => forcePushMultipleUpstream/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{mergeConflictUndo/expected/.git_keep => forcePushMultipleUpstream/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pull/expected/.git_keep => forcePushMultipleUpstream/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) create mode 100644 test/integration/forcePushMultipleUpstream/expected/origin/objects/48/6301f318c84045827013a3c3246b8c6a319eb8 create mode 100644 test/integration/forcePushMultipleUpstream/expected/origin/objects/49/ea44f3ec1792142714930c8e4c3073f137936c create mode 100644 test/integration/forcePushMultipleUpstream/expected/origin/objects/81/bdc116083cd4b4655333f4eb94dc0320197082 rename test/integration/{initialOpen/expected/.git_keep => forcePushMultipleUpstream/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pull/expected/.git_keep => forcePushMultipleUpstream/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/forcePushMultipleUpstream/expected/origin/objects/c8/4375dda9d81c1f2103defe4384e31f859dac86 rename test/integration/{pullMerge/expected/.git_keep => forcePushMultipleUpstream/expected/origin}/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 (100%) rename test/integration/{patchBuildingToggleAll/expected/.git_keep => forcePushMultipleUpstream/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{mergeConflictUndo/expected/.git_keep => forcePushMultipleUpstream/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/forcePushMultipleUpstream/expected/origin/packed-refs create mode 100644 test/integration/forcePushMultipleUpstream/expected/origin/refs/heads/master create mode 100644 test/integration/forcePushMultipleUpstream/expected/origin/refs/heads/other_branch rename test/integration/{pull/expected => forcePushMultipleUpstream/expected/repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{patchBuilding/expected => forcePushMultipleUpstream/expected/repo}/.git_keep/HEAD (100%) create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/ORIG_HEAD create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/config rename test/integration/{mergeConflictRevert/expected => forcePushMultipleUpstream/expected/repo}/.git_keep/description (100%) create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/index rename test/integration/{mergeConflictRevert/expected => forcePushMultipleUpstream/expected/repo}/.git_keep/info/exclude (100%) create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/heads/other_branch create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/remotes/origin/master create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/remotes/origin/other_branch rename test/integration/{patchBuilding/expected => forcePushMultipleUpstream/expected/repo}/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{mergeConflicts/expected => forcePushMultipleUpstream/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pull/expected_remote => forcePushMultipleUpstream/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/48/6301f318c84045827013a3c3246b8c6a319eb8 create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/49/ea44f3ec1792142714930c8e4c3073f137936c create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/81/bdc116083cd4b4655333f4eb94dc0320197082 rename test/integration/{mergeConflictUndo/expected => forcePushMultipleUpstream/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pull/expected_remote => forcePushMultipleUpstream/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/c8/4375dda9d81c1f2103defe4384e31f859dac86 create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 rename test/integration/{patchBuildingWithFiletree/expected => forcePushMultipleUpstream/expected/repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{mergeConflicts/expected => forcePushMultipleUpstream/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/heads/other_branch create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/remotes/origin/master create mode 100644 test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/remotes/origin/other_branch rename test/integration/{initialOpen/expected => forcePushMultipleUpstream/expected/repo}/myfile1 (100%) rename test/integration/{pull/expected => forcePushMultipleUpstream/expected/repo}/myfile2 (100%) create mode 100644 test/integration/forcePushMultipleUpstream/recording.json create mode 100644 test/integration/forcePushMultipleUpstream/setup.sh create mode 100644 test/integration/forcePushMultipleUpstream/test.json rename test/integration/initialOpen/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/initialOpen/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{patchBuilding2/expected => initialOpen/expected/repo}/.git_keep/HEAD (100%) rename test/integration/initialOpen/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{mergeConflictUndo/expected => initialOpen/expected/repo}/.git_keep/description (100%) rename test/integration/initialOpen/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{mergeConflictUndo/expected => initialOpen/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/initialOpen/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/initialOpen/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/{patchBuilding2/expected => initialOpen/expected/repo}/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/initialOpen/expected/{ => repo}/.git_keep/objects/46/f86259c48ec60496e43d9c962e32f40e7cdefb (100%) rename test/integration/initialOpen/expected/{ => repo}/.git_keep/objects/62/b35f5751dd871e0908247223d276b5efeb4cb4 (100%) rename test/integration/{mergeConflicts/expected => initialOpen/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/initialOpen/expected/{ => repo}/.git_keep/objects/e4/776798a2a73374b45e6321b60b5578b9fb590c (100%) rename test/integration/initialOpen/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/{patchBuilding/expected => initialOpen/expected/repo}/myfile1 (100%) rename test/integration/initialOpen/expected/{ => repo}/myfile2 (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{mergeConflicts/expected => mergeConflictRevert/expected/repo}/.git_keep/description (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{mergeConflicts/expected => mergeConflictRevert/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/logs/refs/heads/another (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/logs/refs/heads/other (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/1e/7d643e0db24ebee10f92aa2f8099d50dbe0f0f (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/3c/3594b2fd655fb7ffe36077ee8a9c3f79fb5fc6 (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/41/bed9f222cc54e68d7846dc010bea6d23bea33e (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/61/3e54e7fd6e080d53ef44c18ecd33c545ac0e08 (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/89/8618af3fef6edf472d0f4a483ed8010d7bcfbb (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/98/f656b294e5f3b447e3fd66814a80d0d4080627 (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/a4/942a576eec3a1a15fb790c942b6860331bee32 (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/a7/fd052c52f174943cdea637f2d11f5ab7d090cd (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/ba/4581dc53b5b2ff56803651dfd79245203d546b (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/be/5b46b808c9c808be26710daeb2ce9ed2c7a070 (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/c5/af43f6cc1d51ebb3ab4800347595541f81799c (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/d3/b35176a575d48743900b1f0863cefbc198f84c (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/dd/ad764e9e78b555cd41e5e81f8ce969cfa3972c (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/e5/265503c8aea2860fc4754c1025e4597530ce0e (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/objects/fa/0b6bf64815f57729716334319596c926b6564a (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/refs/heads/another (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/.git_keep/refs/heads/other (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/file1 (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/file2 (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/file4 (100%) rename test/integration/mergeConflictRevert/expected/{ => repo}/file5 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/MERGE_HEAD (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/MERGE_MODE (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/MERGE_MSG (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{mergeConflictsFiltered/expected => mergeConflictUndo/expected/repo}/.git_keep/description (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{mergeConflictsFiltered/expected => mergeConflictUndo/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/logs/refs/heads/base_branch (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/logs/refs/heads/develop (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/logs/refs/heads/feature/cherry-picking (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/logs/refs/heads/other_branch (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/08/e2576bb7cd0dd9be54f9a523c4bedea0643557 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/17/dc45dd142947e06cf7e635d62f2c0acbb86da7 (100%) rename test/integration/{mergeConflictsFiltered/expected => mergeConflictUndo/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/18/c07ac9568c564ececb199f78f64babc92214cb (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/24/10ee12b940bade9d9e99413732faa6dc60adb1 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/27/94411aa7b73b44f533fb862cdb9dbfd13c5d92 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/27/9f068805e089660f7ddd17ff32f66100e0dca5 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/31/f2a971f823279ba1ef877be7599da288f6e24b (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/3d/1213374cd86b841f034768571d0b5f2c870a16 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/44/2a53c1b023b4816085fdc4eaa85d0c5fd897e2 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/4e/5d3ae0b6e865073bcbd79531a75c55bf7bfcb4 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/5d/c2e019349371e9b3e4f1be99754ba70094cad6 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/68/7ff9526e0d56fafe1445ee4c182a83afc3cc35 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/6d/fbfa4bd19cb38608681df40ebb3a78bd13a824 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/7b/c178be031c4645110e9accb4accf16902d2d7f (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/82/db6d0e4502f489719ea0f3dbe7e14413c6d28a (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/8c/d762c119834784fdbf97e9bb3b4c15e804ebaa (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 (100%) rename test/integration/{mergeConflictsFiltered/expected => mergeConflictUndo/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/c2/7ef6b4964209a875191eca7e56605c8efa5eee (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/c5/0f7e1375a30118c2886d4b31318579f3419231 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/c9/b473bec307b18fd94a913658f4d759be63ca47 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/ce/d01df5f1a270490c1b9d4efe5ceb0c53626279 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/d2/5721fffa7dc911ff2a9102bef201db225e2f16 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/db/f5ab9a4fa3f976d266f3be50670aa83121b420 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c (100%) rename test/integration/{mergeConflictsFiltered/expected => mergeConflictUndo/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/refs/heads/base_branch (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/refs/heads/develop (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/refs/heads/feature/cherry-picking (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/.git_keep/refs/heads/other_branch (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/cherrypicking1 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/cherrypicking2 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/cherrypicking3 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/cherrypicking4 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/cherrypicking5 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/cherrypicking6 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/cherrypicking7 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/cherrypicking8 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/cherrypicking9 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/directory/file (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/directory/file2 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/file (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/file1 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/file3 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/file4 (100%) rename test/integration/mergeConflictUndo/expected/{ => repo}/file5 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{mergeConflictsResolvedExternally/expected => mergeConflicts/expected/repo}/.git_keep/description (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{mergeConflictsResolvedExternally/expected => mergeConflicts/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/logs/refs/heads/base_branch (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/logs/refs/heads/develop (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/logs/refs/heads/feature/cherry-picking (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/logs/refs/heads/other_branch (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/0b/2387a3f67ec050f6d4e08f379e3cbb0a9913f1 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/16/18ce1085acb41fd710e279ac38911aadfb0a09 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c (100%) rename test/integration/{patchBuildingToggleAll/expected => mergeConflicts/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/1f/bc3eb4b11cb89b204a593572c2e01462ca5a89 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/24/10ee12b940bade9d9e99413732faa6dc60adb1 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/27/94411aa7b73b44f533fb862cdb9dbfd13c5d92 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/34/1cf8213827614a274c750cd7dec4307eb41de7 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/49/7b1e236588f0e2674c9a5787abeb226abf3680 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/55/9043765dc6c32c943b6278b4abbff1e6f52839 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/55/f688e6b47b7a5ca8ffc4e25b77c1af6222b503 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/56/2af0640203fb5a6e92c090d8d1ded26806d2c4 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/61/db24350a92fa37b2fe35f13eb3dd3f7655f6cf (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/a1/9ec0b99e516795f349033f09383f87be0b74e9 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/a1/e00cd67130c6f7e2b9bb7f23f0cda2b37eb30b (100%) rename test/integration/{patchBuilding/expected => mergeConflicts/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/b0/753bdba91b84e3f406e21dbc7deba8e98f1fc8 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/b2/d5312a06a9c56e9ada21c48a12f57ce8dd4c4a (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/cc/19bee93215b6c20ab129fb2c006762d4ae1497 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/d3/e2708327280097b5e1f8ab69309934b24f8b64 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/dd/259e90c3748e269bdf1ee3ce537a006d2394aa (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/df/2c0daa40dcba0dded361a25ff7806b13db59a6 (100%) rename test/integration/{patchBuilding/expected => mergeConflicts/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/e5/63585cb87cc39b553ca421902d631ea8890118 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/ed/d4e2e50eb82125428b045c540a9194d934e180 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/f7/f30ea7f84d4521d3ce9cc08b780c7a1bf7cc5e (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/f8/9097f0bd23eda6d8977c0edfae7f913ffc5db3 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/f8/dd12b796f400be7f59d9471670c3080f9c90a1 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/refs/heads/base_branch (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/refs/heads/develop (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/refs/heads/feature/cherry-picking (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/mergeConflicts/expected/{ => repo}/.git_keep/refs/heads/other_branch (100%) rename test/integration/mergeConflicts/expected/{ => repo}/cherrypicking1 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/cherrypicking2 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/cherrypicking3 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/cherrypicking4 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/cherrypicking5 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/cherrypicking6 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/cherrypicking7 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/cherrypicking8 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/cherrypicking9 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/directory/file (100%) rename test/integration/mergeConflicts/expected/{ => repo}/directory/file2 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/file (100%) rename test/integration/mergeConflicts/expected/{ => repo}/file1 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/file3 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/file4 (100%) rename test/integration/mergeConflicts/expected/{ => repo}/file5 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{patchBuilding/expected => mergeConflictsFiltered/expected/repo}/.git_keep/description (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{patchBuilding/expected => mergeConflictsFiltered/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/logs/refs/heads/base_branch (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/logs/refs/heads/develop (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/logs/refs/heads/feature/cherry-picking (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/logs/refs/heads/other_branch (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/0f/8c9b8f1cac20c63e92e8df34f6d8b3fa74accd (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c (100%) rename test/integration/{patchBuildingWithFiletree/expected => mergeConflictsFiltered/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/21/730e75ee0eec374cc54eb1140d24e03db834fc (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/34/d20faa891d1857610dce8f790a35b702ebd7ee (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/41/893d444283aa0c46aa7b5ee01811522cca473d (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/4b/6f90d670c40e5ac78d9c405a5bc40932a0980b (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/5e/66799d4a5a3fed89757f3df445a962c9ce2d4f (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/67/b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/6c/590c6a21f4e6d335528b5ecf6c52993b914996 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/72/c9bf1e687e81778850d517953c64f03adbaa1b (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/72/df4fceb0be99deb091ece3f501ef80b39a876a (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/79/6a5a2670ccb2d08db89b9cfcaa07e9be5358e6 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/9a/92a03fdc6eb492ea1ac7acf4fdb04962092f81 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/a5/1a44d96e13555215619b32065d0a22d95b8476 (100%) rename test/integration/{patchBuilding2/expected => mergeConflictsFiltered/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/ab/daa06b758aa198cc4afb9c406c87c5690d0ca0 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/b2/afb2548f2d143fdd691058f2283b03933a1749 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/c6/2b5bc94e327ddb9b545213ff77b207ade48aba (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/d4/f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/d7/d52ecd690fe82c7d820ddb437e82d78b0fa7b2 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/d8/8617710499a59992caf98d6df1b5f981c58ab1 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/dd/401e3ee3d58b648207cee7f737364a37139bea (100%) rename test/integration/{patchBuilding2/expected => mergeConflictsFiltered/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/f3/7ec566036d715d6995f55dbc82a4fb3cf56f2f (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/fa/5c5dac095b577173e47b4a0c139525eced009f (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/refs/heads/base_branch (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/refs/heads/develop (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/refs/heads/feature/cherry-picking (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/.git_keep/refs/heads/other_branch (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/cherrypicking1 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/cherrypicking2 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/cherrypicking3 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/cherrypicking4 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/cherrypicking5 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/cherrypicking6 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/cherrypicking7 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/cherrypicking8 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/cherrypicking9 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/directory/file (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/directory/file2 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/file (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/file1 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/file3 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/file4 (100%) rename test/integration/mergeConflictsFiltered/expected/{ => repo}/file5 (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{patchBuilding2/expected => mergeConflictsResolvedExternally/expected/repo}/.git_keep/description (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{patchBuilding2/expected => mergeConflictsResolvedExternally/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/logs/refs/heads/other (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/objects/03/959db9f70fcb4a8f0931e4ad64e1c9ec1016a4 (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/objects/08/84a47e04257f4c85435a8b10ff4f15fffa63fc (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/objects/0b/e6e80a67f6276c5ede28dd6b8fa8873f1b23c5 (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/objects/2d/8021ed8803ed6142d31b331850ef46246391a7 (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/objects/53/502c7023f80c046a1b00b45614d5ffef8977d9 (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/objects/69/1ee9e9d9c654c81214f56c514ff725f46cb9e4 (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/objects/6b/03bc7537ecf00b48a0ea57ce1edf388ed3f1ad (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/objects/76/9c8b8d89700f6f196b8331159150746a839662 (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/objects/bd/2b32f02abf86a2bb79a12ab09758e44b204b34 (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/objects/c0/565d7cfcf1039c969105f2e1c86ca5eff64381 (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/objects/f2/df244fb87b6ba1d2ab484d76c66baba168a867 (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/.git_keep/refs/heads/other (100%) rename test/integration/mergeConflictsResolvedExternally/expected/{ => repo}/file (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{patchBuildingToggleAll/expected => patchBuilding/expected/repo}/.git_keep/HEAD (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{patchBuildingToggleAll/expected => patchBuilding/expected/repo}/.git_keep/description (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{patchBuildingToggleAll/expected => patchBuilding/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/01/5689313279311c9356ea3fd3628f73ca4ea797 (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/01/ed22faef05591076721466e07fb10962642887 (100%) rename test/integration/{pull/expected => patchBuilding/expected/repo}/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/24/4cec6fa9704d5dc61fc5e60faba4125dfe3baa (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/24/79abfe7bd6b64a753d3c3797f614bbb422f627 (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/47/5a06b7978eef6509efdd2a86e341992d9f2908 (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/52/863675692b53d9e34dd72da8c35a72bf0a5b51 (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/7a/40dadc0814bf7f1418d005eae184848a9f1c94 (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/92/2fc2ed1965fe8436ce7837c634379f14faf3c3 (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/92/571130f37c70766612048271f1d4dca63ef0b5 (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/93/96d8d0c471661257f6c16c1957452912c0c6f5 (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/a3/2f90adf7ee0f14ae300e49cdf8779507746c27 (100%) rename test/integration/{patchBuildingToggleAll/expected => patchBuilding/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/ad/e030587c8ae5d240ad7669bff9030b24bd6385 (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/c6/9e35e8cae5688bbfcf8278c20ab43c1b8dbae3 (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/ce/024fc694fd464cfb5b43cb7702f0bd7345d882 (100%) rename test/integration/{patchBuildingToggleAll/expected => patchBuilding/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/e3/31050363ceb0b12d9d042e37879d892d867ea0 (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/objects/f3/c8a074e65b02d1bc364caf0b4c1516abf9eb5a (100%) rename test/integration/patchBuilding/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/{patchBuilding2/expected => patchBuilding/expected/repo}/myfile1 (100%) rename test/integration/patchBuilding/expected/{ => repo}/myfile2 (100%) rename test/integration/patchBuilding/expected/{ => repo}/myfile3 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{patchBuildingWithFiletree/expected => patchBuilding2/expected/repo}/.git_keep/HEAD (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{patchBuildingWithFiletree/expected => patchBuilding2/expected/repo}/.git_keep/description (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{patchBuildingWithFiletree/expected => patchBuilding2/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/logs/refs/stash (100%) rename test/integration/{pull/expected_remote => patchBuilding2/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/1a/b6a62ed874b19c1191ba2b0106741ca4ca4b50 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/2c/60d208ba3ec966b77ca756237843af7584cf93 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/47/5a06b7978eef6509efdd2a86e341992d9f2908 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/50/63202049f1980e035c390732a7e6da8783357f (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/52/863675692b53d9e34dd72da8c35a72bf0a5b51 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/9a/939087472cfaf305396d4b177ee888ced193d9 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/a3/2f90adf7ee0f14ae300e49cdf8779507746c27 (100%) rename test/integration/{patchBuildingWithFiletree/expected => patchBuilding2/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/ad/27dd25048bff07da92d2d9d829e4dd75472da4 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/ad/e030587c8ae5d240ad7669bff9030b24bd6385 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/ce/024fc694fd464cfb5b43cb7702f0bd7345d882 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/d0/ec73019f9c5e426c9b37fa58757855367580a5 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/d3/4fc4a9c0c675a5cb11d848e5afef4c89160dc0 (100%) rename test/integration/{patchBuildingWithFiletree/expected => patchBuilding2/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/e3/31050363ceb0b12d9d042e37879d892d867ea0 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/e4/74bc2d1712ed5fdf14fb7223392f1b0dcc8d37 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/objects/f3/c8a074e65b02d1bc364caf0b4c1516abf9eb5a (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/patchBuilding2/expected/{ => repo}/.git_keep/refs/stash (100%) rename test/integration/{pull/expected => patchBuilding2/expected/repo}/myfile1 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/myfile2 (100%) rename test/integration/patchBuilding2/expected/{ => repo}/myfile3 (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{pull/expected => patchBuildingToggleAll/expected/repo}/.git_keep/HEAD (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{pull/expected => patchBuildingToggleAll/expected/repo}/.git_keep/description (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{pull/expected => patchBuildingToggleAll/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/{pull/expected => patchBuildingToggleAll/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/objects/41/05b6da4ccc191a4abd24b1ffac6a2031534c0b (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/objects/44/eb4bd0e7419049a8e4176945786c20dae60d7c (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/objects/68/bbd52379d849022495dcfd11b13f2fb3103d37 (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/objects/70/28eaec19b2723b62690974057c92ba7d8c1b11 (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/objects/98/1651deb012f8e684dd306c1f5bf8edd5c3db67 (100%) rename test/integration/{pull/expected => patchBuildingToggleAll/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/objects/cf/149a94a18c990b2c5cdd0cf15ec4880f51c8b0 (100%) rename test/integration/{pull/expected => patchBuildingToggleAll/expected/repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pull/expected => patchBuildingToggleAll/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/patchBuildingToggleAll/expected/{ => repo}/one/two/three/file3 (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{pull/expected_remote => patchBuildingWithFiletree/expected/repo/.git_keep}/HEAD (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{pull/expected_remote => patchBuildingWithFiletree/expected/repo/.git_keep}/description (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{pull/expected_remote => patchBuildingWithFiletree/expected/repo/.git_keep}/info/exclude (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/{pull/expected_remote => patchBuildingWithFiletree/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/41/05b6da4ccc191a4abd24b1ffac6a2031534c0b (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/43/9a6f2a3c627cd37ba1c5eda6a49c26a85ad610 (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/44/eb4bd0e7419049a8e4176945786c20dae60d7c (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/54/57a1e78421c0c1bf9eb3bcc89f6c0996b9f89e (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/5a/abb4aaf3d6cc113fec7f7a3c0a880988085c23 (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/68/bbd52379d849022495dcfd11b13f2fb3103d37 (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/88/981dbb0664057b766113679127284f69f4fb69 (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/98/1651deb012f8e684dd306c1f5bf8edd5c3db67 (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/9f/aac09750995930a5d55eccf91ad6f802e8c66b (100%) rename test/integration/{pull/expected_remote => patchBuildingWithFiletree/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/b5/e8fb99b011265d28065d0d545ff6b0245b1fa1 (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/objects/c1/7dc7400fbb649385064c27544ba1e6c4751566 (100%) rename test/integration/{pull/expected_remote => patchBuildingWithFiletree/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pull/expected_remote => patchBuildingWithFiletree/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/one/two/file2 (100%) rename test/integration/patchBuildingWithFiletree/expected/{ => repo}/one/two/three/file3 (100%) delete mode 100644 test/integration/pull/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pull/expected/.git_keep/ORIG_HEAD delete mode 100644 test/integration/pull/expected/.git_keep/index delete mode 100644 test/integration/pull/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pull/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pull/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pull/expected/.git_keep/objects/00/3527daa0801470151d8f93140a02fc306fea00 delete mode 100644 test/integration/pull/expected/.git_keep/objects/0c/0f210a4e5ff3b58e4190501c2b755695f439fa delete mode 100644 test/integration/pull/expected/.git_keep/objects/33/6826e035e431ac94eca7f3cb6dd3fb072f7a5a delete mode 100644 test/integration/pull/expected/.git_keep/objects/6a/d6c42187d356f4eab4f004cca17863746adec1 delete mode 100644 test/integration/pull/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pull/expected/.git_keep/refs/remotes/origin/master rename test/integration/{pullAndSetUpstream/expected/.git_keep => pull/expected/origin}/HEAD (100%) rename test/integration/{push/expected_remote => pull/expected/origin}/config (80%) rename test/integration/{pullAndSetUpstream/expected/.git_keep => pull/expected/origin}/description (100%) rename test/integration/{pullAndSetUpstream/expected/.git_keep => pull/expected/origin}/info/exclude (100%) rename test/integration/{pullAndSetUpstream/expected/.git_keep => pull/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullAndSetUpstream/expected/.git_keep => pull/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pullAndSetUpstream/expected/.git_keep => pull/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pull/expected/{.git_keep => origin}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pull/expected/origin/objects/3e/a0c134bed03d0a2cb7eeaff586af277d137129 create mode 100644 test/integration/pull/expected/origin/objects/7b/9a91f4ecba02fd55dbf3f372bc3faee3897939 create mode 100644 test/integration/pull/expected/origin/objects/97/bf06c598032ab5ad0faf744c91545071f3cb38 rename test/integration/{pullAndSetUpstream/expected/.git_keep => pull/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pullAndSetUpstream/expected/.git_keep => pull/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pullAndSetUpstream/expected/.git_keep => pull/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pullAndSetUpstream/expected/.git_keep => pull/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pull/expected/origin/objects/f0/eb4a85b26f51dc8c23e31bb7f541f0e2d1d2d0 create mode 100644 test/integration/pull/expected/origin/packed-refs rename test/integration/{pullAndSetUpstream/expected => pull/expected/repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/pull/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{pullAndSetUpstream/expected_remote => pull/expected/repo/.git_keep}/HEAD (100%) create mode 100644 test/integration/pull/expected/repo/.git_keep/ORIG_HEAD rename test/integration/{push/expected => pull/expected/repo}/.git_keep/config (92%) rename test/integration/{pullAndSetUpstream/expected_remote => pull/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/pull/expected/repo/.git_keep/index rename test/integration/{pullAndSetUpstream/expected_remote => pull/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/pull/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pull/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pull/expected/repo/.git_keep/logs/refs/remotes/origin/master rename test/integration/{pullAndSetUpstream/expected_remote => pull/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullAndSetUpstream/expected_remote => pull/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pullAndSetUpstream/expected_remote => pull/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pull/{expected_remote => expected/repo/.git_keep}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pull/expected/repo/.git_keep/objects/3e/a0c134bed03d0a2cb7eeaff586af277d137129 create mode 100644 test/integration/pull/expected/repo/.git_keep/objects/7b/9a91f4ecba02fd55dbf3f372bc3faee3897939 create mode 100644 test/integration/pull/expected/repo/.git_keep/objects/97/bf06c598032ab5ad0faf744c91545071f3cb38 rename test/integration/{pullAndSetUpstream/expected_remote => pull/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pullAndSetUpstream/expected_remote => pull/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pullAndSetUpstream/expected_remote => pull/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pullAndSetUpstream/expected_remote => pull/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pull/expected/repo/.git_keep/objects/f0/eb4a85b26f51dc8c23e31bb7f541f0e2d1d2d0 create mode 100644 test/integration/pull/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pull/expected/repo/.git_keep/refs/remotes/origin/master rename test/integration/{pullAndSetUpstream/expected => pull/expected/repo}/myfile1 (100%) rename test/integration/{pullAndSetUpstream/expected => pull/expected/repo}/myfile2 (100%) rename test/integration/pull/expected/{ => repo}/myfile3 (100%) rename test/integration/pull/expected/{ => repo}/myfile4 (100%) delete mode 100644 test/integration/pull/expected_remote/objects/00/3527daa0801470151d8f93140a02fc306fea00 delete mode 100644 test/integration/pull/expected_remote/objects/0c/0f210a4e5ff3b58e4190501c2b755695f439fa delete mode 100644 test/integration/pull/expected_remote/objects/33/6826e035e431ac94eca7f3cb6dd3fb072f7a5a delete mode 100644 test/integration/pull/expected_remote/objects/6a/d6c42187d356f4eab4f004cca17863746adec1 delete mode 100644 test/integration/pull/expected_remote/packed-refs delete mode 100644 test/integration/pullAndSetUpstream/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pullAndSetUpstream/expected/.git_keep/ORIG_HEAD delete mode 100644 test/integration/pullAndSetUpstream/expected/.git_keep/index delete mode 100644 test/integration/pullAndSetUpstream/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pullAndSetUpstream/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pullAndSetUpstream/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pullAndSetUpstream/expected/.git_keep/objects/06/d3929607b7519beb45ca67165a1f2b5c0e578b delete mode 100644 test/integration/pullAndSetUpstream/expected/.git_keep/objects/76/6e681a51daa75233c1c4ae8845be2c893577d5 delete mode 100644 test/integration/pullAndSetUpstream/expected/.git_keep/objects/97/2fb9caab8b8536ae38687fec98304b76748b9d delete mode 100644 test/integration/pullAndSetUpstream/expected/.git_keep/objects/c9/fd61f40de25556977e063683d1de612f931ccb delete mode 100644 test/integration/pullAndSetUpstream/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pullAndSetUpstream/expected/.git_keep/refs/remotes/origin/master rename test/integration/{pullMerge/expected/.git_keep => pullAndSetUpstream/expected/origin}/HEAD (100%) create mode 100644 test/integration/pullAndSetUpstream/expected/origin/config rename test/integration/{pullMerge/expected/.git_keep => pullAndSetUpstream/expected/origin}/description (100%) rename test/integration/{pullMerge/expected/.git_keep => pullAndSetUpstream/expected/origin}/info/exclude (100%) rename test/integration/{pullMerge/expected/.git_keep => pullAndSetUpstream/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullMerge/expected/.git_keep => pullAndSetUpstream/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) create mode 100644 test/integration/pullAndSetUpstream/expected/origin/objects/1f/027c0e280612f8e5e2cf0a5361f6ab0c4baed6 rename test/integration/{pullMerge/expected/.git_keep => pullAndSetUpstream/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pullAndSetUpstream/expected/{.git_keep => origin}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullAndSetUpstream/expected/origin/objects/64/d950eb46bf13d35cd27dd7a3ad621422dee6ac rename test/integration/{pullMerge/expected/.git_keep => pullAndSetUpstream/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pullMerge/expected/.git_keep => pullAndSetUpstream/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pullMerge/expected/.git_keep => pullAndSetUpstream/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pullMerge/expected/.git_keep => pullAndSetUpstream/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pullAndSetUpstream/expected/origin/objects/df/fd8a2962e840dfcbce39a0315e0cded7873b29 create mode 100644 test/integration/pullAndSetUpstream/expected/origin/objects/f1/1c72f0484c803d954446036bf464c3b8523330 create mode 100644 test/integration/pullAndSetUpstream/expected/origin/packed-refs rename test/integration/{pullMerge/expected => pullAndSetUpstream/expected/repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/pullAndSetUpstream/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{pullMerge/expected_remote => pullAndSetUpstream/expected/repo/.git_keep}/HEAD (100%) create mode 100644 test/integration/pullAndSetUpstream/expected/repo/.git_keep/ORIG_HEAD rename test/integration/{forcePush/expected => pullAndSetUpstream/expected/repo}/.git_keep/config (92%) rename test/integration/{pullMerge/expected_remote => pullAndSetUpstream/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/pullAndSetUpstream/expected/repo/.git_keep/index rename test/integration/{pullMerge/expected_remote => pullAndSetUpstream/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/pullAndSetUpstream/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pullAndSetUpstream/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pullAndSetUpstream/expected/repo/.git_keep/logs/refs/remotes/origin/master rename test/integration/{pullMerge/expected_remote => pullAndSetUpstream/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullMerge/expected_remote => pullAndSetUpstream/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) create mode 100644 test/integration/pullAndSetUpstream/expected/repo/.git_keep/objects/1f/027c0e280612f8e5e2cf0a5361f6ab0c4baed6 rename test/integration/{pullMerge/expected_remote => pullAndSetUpstream/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pullAndSetUpstream/{expected_remote => expected/repo/.git_keep}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullAndSetUpstream/expected/repo/.git_keep/objects/64/d950eb46bf13d35cd27dd7a3ad621422dee6ac rename test/integration/{pullMerge/expected_remote => pullAndSetUpstream/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pullMerge/expected_remote => pullAndSetUpstream/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pullMerge/expected_remote => pullAndSetUpstream/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pullMerge/expected_remote => pullAndSetUpstream/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pullAndSetUpstream/expected/repo/.git_keep/objects/df/fd8a2962e840dfcbce39a0315e0cded7873b29 create mode 100644 test/integration/pullAndSetUpstream/expected/repo/.git_keep/objects/f1/1c72f0484c803d954446036bf464c3b8523330 create mode 100644 test/integration/pullAndSetUpstream/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pullAndSetUpstream/expected/repo/.git_keep/refs/remotes/origin/master rename test/integration/{pullMerge/expected => pullAndSetUpstream/expected/repo}/myfile1 (100%) rename test/integration/{pullMerge/expected => pullAndSetUpstream/expected/repo}/myfile2 (100%) rename test/integration/pullAndSetUpstream/expected/{ => repo}/myfile3 (100%) rename test/integration/pullAndSetUpstream/expected/{ => repo}/myfile4 (100%) delete mode 100644 test/integration/pullAndSetUpstream/expected_remote/config delete mode 100644 test/integration/pullAndSetUpstream/expected_remote/objects/06/d3929607b7519beb45ca67165a1f2b5c0e578b delete mode 100644 test/integration/pullAndSetUpstream/expected_remote/objects/76/6e681a51daa75233c1c4ae8845be2c893577d5 delete mode 100644 test/integration/pullAndSetUpstream/expected_remote/objects/97/2fb9caab8b8536ae38687fec98304b76748b9d delete mode 100644 test/integration/pullAndSetUpstream/expected_remote/objects/c9/fd61f40de25556977e063683d1de612f931ccb delete mode 100644 test/integration/pullAndSetUpstream/expected_remote/packed-refs delete mode 100644 test/integration/pullMerge/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pullMerge/expected/.git_keep/ORIG_HEAD delete mode 100644 test/integration/pullMerge/expected/.git_keep/index delete mode 100644 test/integration/pullMerge/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pullMerge/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pullMerge/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pullMerge/expected/.git_keep/objects/2a/0805355a8040f9eebfa2dbf70b8bc313d6f456 delete mode 100644 test/integration/pullMerge/expected/.git_keep/objects/55/29eadf398ce89032744d5f4151000f07d70124 delete mode 100644 test/integration/pullMerge/expected/.git_keep/objects/70/3e85166069a42b4254af06b68dffc159ea3f24 delete mode 100644 test/integration/pullMerge/expected/.git_keep/objects/7c/0bda1656e7695870ed15839643564b0a9283a8 delete mode 100644 test/integration/pullMerge/expected/.git_keep/objects/7f/157a65ec0c8d6cffce08d6768e6733939e75a1 delete mode 100644 test/integration/pullMerge/expected/.git_keep/objects/b1/0baba2f9d877322f94f8770e2e0c8ab1db6bcc delete mode 100644 test/integration/pullMerge/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pullMerge/expected/.git_keep/refs/remotes/origin/master rename test/integration/{pullMergeConflict/expected/.git_keep => pullMerge/expected/origin}/HEAD (100%) rename test/integration/{forcePush/expected_remote => pullMerge/expected/origin}/config (78%) rename test/integration/{pullMergeConflict/expected/.git_keep => pullMerge/expected/origin}/description (100%) rename test/integration/{pullMergeConflict/expected/.git_keep => pullMerge/expected/origin}/info/exclude (100%) create mode 100644 test/integration/pullMerge/expected/origin/objects/0d/5dd7784063912fe3efeaf7d2b6782019ee9e6e rename test/integration/{pullMergeConflict/expected/.git_keep => pullMerge/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullMergeConflict/expected/.git_keep => pullMerge/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) create mode 100644 test/integration/pullMerge/expected/origin/objects/22/4786fb3e4a16b22b4e2b43fe01d7797491adad create mode 100644 test/integration/pullMerge/expected/origin/objects/29/1b985e75f255f9947f064aee9e1f37af1a930d rename test/integration/{pullMergeConflict/expected/.git_keep => pullMerge/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pullMerge/expected/{.git_keep => origin}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullMerge/expected/origin/objects/82/422401226cbf89b60b7ba3c6d4fa74781250c9 rename test/integration/{pullMergeConflict/expected/.git_keep => pullMerge/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pullMergeConflict/expected/.git_keep => pullMerge/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pullMergeConflict/expected/.git_keep => pullMerge/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pullMergeConflict/expected/.git_keep => pullMerge/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pullMerge/expected/origin/packed-refs rename test/integration/{push/expected => pullMerge/expected/repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{pullMergeConflict/expected_remote => pullMerge/expected/repo/.git_keep}/HEAD (100%) create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/ORIG_HEAD rename test/integration/{pullMergeConflict/expected => pullMerge/expected/repo}/.git_keep/config (93%) rename test/integration/{pullMergeConflict/expected_remote => pullMerge/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/index rename test/integration/{pullMergeConflict/expected_remote => pullMerge/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/logs/refs/remotes/origin/master create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/objects/0d/5dd7784063912fe3efeaf7d2b6782019ee9e6e rename test/integration/{pullMergeConflict/expected_remote => pullMerge/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullMergeConflict/expected_remote => pullMerge/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/objects/22/4786fb3e4a16b22b4e2b43fe01d7797491adad create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/objects/29/1b985e75f255f9947f064aee9e1f37af1a930d rename test/integration/{pullMergeConflict/expected_remote => pullMerge/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pullMerge/{expected_remote => expected/repo/.git_keep}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/objects/67/3a4237450c6ea2a27b18f1d7a3c9293c5606ea create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/objects/82/422401226cbf89b60b7ba3c6d4fa74781250c9 rename test/integration/{pullMergeConflict/expected_remote => pullMerge/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/objects/a6/1316509295a5644a82e38e8bd455422fe477c5 rename test/integration/{pullMergeConflict/expected_remote => pullMerge/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 rename test/integration/{pullMergeConflict/expected_remote => pullMerge/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pullMergeConflict/expected_remote => pullMerge/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pullMerge/expected/repo/.git_keep/refs/remotes/origin/master rename test/integration/{pullMergeConflict/expected => pullMerge/expected/repo}/myfile1 (100%) rename test/integration/{pullMergeConflict/expected => pullMerge/expected/repo}/myfile2 (100%) rename test/integration/pullMerge/expected/{ => repo}/myfile3 (100%) rename test/integration/pullMerge/expected/{ => repo}/myfile4 (100%) delete mode 100644 test/integration/pullMerge/expected_remote/objects/55/29eadf398ce89032744d5f4151000f07d70124 delete mode 100644 test/integration/pullMerge/expected_remote/objects/70/3e85166069a42b4254af06b68dffc159ea3f24 delete mode 100644 test/integration/pullMerge/expected_remote/objects/7c/0bda1656e7695870ed15839643564b0a9283a8 delete mode 100644 test/integration/pullMerge/expected_remote/objects/7f/157a65ec0c8d6cffce08d6768e6733939e75a1 delete mode 100644 test/integration/pullMerge/expected_remote/packed-refs delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/ORIG_HEAD delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/index delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/objects/1f/e5d8152187295b171f171c0d55d809500ae80f delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/objects/38/699899bb94dfae74e3e55cf5bd6d92e6f3292a delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/objects/72/0c7e2dd34822d33cb24a0a3f0f4bdabf433500 delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/objects/7d/ba68a0030313e27b8dd5da2076952629485f2d delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/objects/80/f8aed01cdb61f9e94c6a53c39f400dfbcf05c9 delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/objects/dd/f4b7fe8f45d07a181c2b57cc3434c982d3f4aa delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/objects/f0/e8e7922de77a5ab20b924640c8b8435bae0b0b delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pullMergeConflict/expected/.git_keep/refs/remotes/origin/master rename test/integration/{pullRebase/expected/.git_keep => pullMergeConflict/expected/origin}/HEAD (100%) create mode 100644 test/integration/pullMergeConflict/expected/origin/config rename test/integration/{pullRebase/expected/.git_keep => pullMergeConflict/expected/origin}/description (100%) rename test/integration/{pullRebase/expected/.git_keep => pullMergeConflict/expected/origin}/info/exclude (100%) rename test/integration/{pullRebase/expected/.git_keep => pullMergeConflict/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullRebase/expected/.git_keep => pullMergeConflict/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) create mode 100644 test/integration/pullMergeConflict/expected/origin/objects/29/c0636a86cc64292b7a6b1083c2df10de9cde6c rename test/integration/{pullRebase/expected/.git_keep => pullMergeConflict/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pullMergeConflict/expected/{.git_keep => origin}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullMergeConflict/expected/origin/objects/77/a75278eb08101403d727a8ecaad724f5d9dc78 create mode 100644 test/integration/pullMergeConflict/expected/origin/objects/7c/201cb45dc62900f5f42281c1235219df5d0388 rename test/integration/{pullRebase/expected/.git_keep => pullMergeConflict/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pullRebase/expected/.git_keep => pullMergeConflict/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/pullMergeConflict/expected/origin/objects/c7/180f424ee6b59241eecffedcfa4472a86d927d rename test/integration/{pullRebase/expected/.git_keep => pullMergeConflict/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pullRebase/expected/.git_keep => pullMergeConflict/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pullMergeConflict/expected/origin/packed-refs rename test/integration/pullMergeConflict/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (85%) create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{pullRebase/expected_remote => pullMergeConflict/expected/repo/.git_keep}/HEAD (100%) create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/ORIG_HEAD rename test/integration/{pullMerge/expected => pullMergeConflict/expected/repo}/.git_keep/config (93%) rename test/integration/{pullRebase/expected_remote => pullMergeConflict/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/index rename test/integration/{pullRebase/expected_remote => pullMergeConflict/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/logs/refs/remotes/origin/master rename test/integration/{pullRebase/expected_remote => pullMergeConflict/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullRebase/expected_remote => pullMergeConflict/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/objects/29/c0636a86cc64292b7a6b1083c2df10de9cde6c rename test/integration/{pullRebase/expected_remote => pullMergeConflict/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pullMergeConflict/{expected_remote => expected/repo/.git_keep}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/objects/4d/b288af7bc797a3819441c734a4c4e7e3635296 create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/objects/77/a75278eb08101403d727a8ecaad724f5d9dc78 create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/objects/7c/201cb45dc62900f5f42281c1235219df5d0388 create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/objects/7d/a51df5143674eeec01d1bafa23ab8b9e69e8c2 rename test/integration/pullMergeConflict/expected/{ => repo}/.git_keep/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae (100%) rename test/integration/{pullRebase/expected_remote => pullMergeConflict/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pullRebase/expected_remote => pullMergeConflict/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/pullMergeConflict/expected/{ => repo}/.git_keep/objects/ae/d6c0a012c68a8b615ab0185b64f59c414d4746 (100%) create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/objects/c2/5833e74799f64c317fe3f112f934fcc57b71f9 create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/objects/c7/180f424ee6b59241eecffedcfa4472a86d927d rename test/integration/{pullRebase/expected_remote => pullMergeConflict/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pullRebase/expected_remote => pullMergeConflict/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pullMergeConflict/expected/repo/.git_keep/refs/remotes/origin/master rename test/integration/{pullRebase/expected => pullMergeConflict/expected/repo}/myfile1 (100%) rename test/integration/{pullRebase/expected => pullMergeConflict/expected/repo}/myfile2 (100%) rename test/integration/pullMergeConflict/expected/{ => repo}/myfile3 (100%) rename test/integration/pullMergeConflict/expected/{ => repo}/myfile4 (100%) delete mode 100644 test/integration/pullMergeConflict/expected_remote/config delete mode 100644 test/integration/pullMergeConflict/expected_remote/objects/38/699899bb94dfae74e3e55cf5bd6d92e6f3292a delete mode 100644 test/integration/pullMergeConflict/expected_remote/objects/80/f8aed01cdb61f9e94c6a53c39f400dfbcf05c9 delete mode 100644 test/integration/pullMergeConflict/expected_remote/objects/dd/f4b7fe8f45d07a181c2b57cc3434c982d3f4aa delete mode 100644 test/integration/pullMergeConflict/expected_remote/objects/f0/e8e7922de77a5ab20b924640c8b8435bae0b0b delete mode 100644 test/integration/pullMergeConflict/expected_remote/packed-refs delete mode 100644 test/integration/pullRebase/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pullRebase/expected/.git_keep/ORIG_HEAD delete mode 100644 test/integration/pullRebase/expected/.git_keep/index delete mode 100644 test/integration/pullRebase/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pullRebase/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pullRebase/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pullRebase/expected/.git_keep/objects/0b/bb382cb5729bfd2e6fd3e1d60237e03cb375a4 delete mode 100644 test/integration/pullRebase/expected/.git_keep/objects/74/755f34462bd712c676b84247831233da97a272 delete mode 100644 test/integration/pullRebase/expected/.git_keep/objects/7b/21277988b03a5fd9e933126e8d1f31d2498d08 delete mode 100644 test/integration/pullRebase/expected/.git_keep/objects/c0/ae07711df69fb0a21efaca9d63da42a67eaedf delete mode 100644 test/integration/pullRebase/expected/.git_keep/objects/d0/e04b2bced3bc76f0abf50698a7ab774cd54568 delete mode 100644 test/integration/pullRebase/expected/.git_keep/objects/fe/1d53ca86366f64f689586cb0fe243fed1d1482 delete mode 100644 test/integration/pullRebase/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pullRebase/expected/.git_keep/refs/remotes/origin/master rename test/integration/{pullRebaseConflict/expected/.git_keep => pullRebase/expected/origin}/HEAD (100%) create mode 100644 test/integration/pullRebase/expected/origin/config rename test/integration/{pullRebaseConflict/expected/.git_keep => pullRebase/expected/origin}/description (100%) rename test/integration/{pullRebaseConflict/expected/.git_keep => pullRebase/expected/origin}/info/exclude (100%) rename test/integration/{pullRebaseConflict/expected/.git_keep => pullRebase/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullRebaseConflict/expected/.git_keep => pullRebase/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pullRebaseConflict/expected/.git_keep => pullRebase/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pullRebase/expected/{.git_keep => origin}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullRebase/expected/origin/objects/7b/a4176e37b24d5c97f17214ca6d658dbc58ef9d create mode 100644 test/integration/pullRebase/expected/origin/objects/84/b9e43914aa7ae61a869a6b17cf0ec9f1bf04a9 rename test/integration/{pullRebaseConflict/expected/.git_keep => pullRebase/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pullRebaseConflict/expected/.git_keep => pullRebase/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pullRebaseConflict/expected/.git_keep => pullRebase/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pullRebaseConflict/expected/.git_keep => pullRebase/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pullRebase/expected/origin/objects/f2/744f41facc4c70c41f07c93c2a5fc010b4ccf6 create mode 100644 test/integration/pullRebase/expected/origin/objects/f2/b972db67c4667ac1896df3556a2cb2422bef8a create mode 100644 test/integration/pullRebase/expected/origin/packed-refs rename test/integration/pullRebase/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{pullRebaseConflict/expected_remote => pullRebase/expected/repo/.git_keep}/HEAD (100%) create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/ORIG_HEAD rename test/integration/{pullRebaseConflict/expected => pullRebase/expected/repo}/.git_keep/config (93%) rename test/integration/{pullRebaseConflict/expected_remote => pullRebase/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/index rename test/integration/{pullRebaseConflict/expected_remote => pullRebase/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/logs/refs/remotes/origin/master rename test/integration/{pullRebaseConflict/expected_remote => pullRebase/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullRebaseConflict/expected_remote => pullRebase/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/objects/25/b115c8ff09bf59b023af22277ea140b2833110 rename test/integration/{pullRebaseConflict/expected_remote => pullRebase/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pullRebase/{expected_remote => expected/repo/.git_keep}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/objects/7b/a4176e37b24d5c97f17214ca6d658dbc58ef9d create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/objects/84/b9e43914aa7ae61a869a6b17cf0ec9f1bf04a9 rename test/integration/pullRebase/expected/{ => repo}/.git_keep/objects/92/c2dd111eeb7daf4a0e30faff73b9441103805d (100%) rename test/integration/pullRebase/expected/{ => repo}/.git_keep/objects/98/fea3de076a474cabfac7130669625879051d43 (100%) rename test/integration/{pullRebaseConflict/expected_remote => pullRebase/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pullRebaseConflict/expected_remote => pullRebase/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pullRebaseConflict/expected_remote => pullRebase/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pullRebaseConflict/expected_remote => pullRebase/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/objects/ef/833c09ff39663448dd9582e3d6ac1fa777fb4f create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/objects/f2/744f41facc4c70c41f07c93c2a5fc010b4ccf6 create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/objects/f2/b972db67c4667ac1896df3556a2cb2422bef8a create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pullRebase/expected/repo/.git_keep/refs/remotes/origin/master rename test/integration/{pullRebaseConflict/expected => pullRebase/expected/repo}/myfile1 (100%) rename test/integration/{pullRebaseConflict/expected => pullRebase/expected/repo}/myfile2 (100%) rename test/integration/pullRebase/expected/{ => repo}/myfile3 (100%) rename test/integration/pullRebase/expected/{ => repo}/myfile4 (100%) rename test/integration/pullRebase/expected/{ => repo}/myfile5 (100%) delete mode 100644 test/integration/pullRebase/expected_remote/config delete mode 100644 test/integration/pullRebase/expected_remote/objects/0b/bb382cb5729bfd2e6fd3e1d60237e03cb375a4 delete mode 100644 test/integration/pullRebase/expected_remote/objects/c0/ae07711df69fb0a21efaca9d63da42a67eaedf delete mode 100644 test/integration/pullRebase/expected_remote/objects/d0/e04b2bced3bc76f0abf50698a7ab774cd54568 delete mode 100644 test/integration/pullRebase/expected_remote/objects/fe/1d53ca86366f64f689586cb0fe243fed1d1482 delete mode 100644 test/integration/pullRebase/expected_remote/packed-refs delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/ORIG_HEAD delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/index delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/objects/10/3c3eb899d173b83fc1b40261c8880fef359cc3 delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/objects/11/6cef0e366265c3d002cdb3dce4e285e32b5d12 delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/objects/34/574474ac6f7dd2d3142bc28ee39db88d8a16af delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/objects/3b/9389ff50095ad2d66d33bb6d67b5700f0bf6da delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/objects/aa/6ae0785290ee09875f6bd5a5d50c0e7002de13 delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/objects/db/7122c7f62714dfa854d8d22b2081d308912af8 delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pullRebaseConflict/expected/.git_keep/refs/remotes/origin/master rename test/integration/{pullRebaseInteractive/expected/.git_keep => pullRebaseConflict/expected/origin}/HEAD (100%) create mode 100644 test/integration/pullRebaseConflict/expected/origin/config rename test/integration/{pullRebaseInteractive/expected/.git_keep => pullRebaseConflict/expected/origin}/description (100%) rename test/integration/{pullRebaseInteractive/expected/.git_keep => pullRebaseConflict/expected/origin}/info/exclude (100%) create mode 100644 test/integration/pullRebaseConflict/expected/origin/objects/00/36ac0e5f5536f55bfdfcb4e09927f1eed3b37b rename test/integration/{pullRebaseInteractive/expected/.git_keep => pullRebaseConflict/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullRebaseInteractive/expected/.git_keep => pullRebaseConflict/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pullRebaseInteractive/expected/.git_keep => pullRebaseConflict/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pullRebaseConflict/expected/{.git_keep => origin}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullRebaseConflict/expected/origin/objects/30/8a85a7f740d42925175560337196f952ac6cf6 create mode 100644 test/integration/pullRebaseConflict/expected/origin/objects/70/2648e6efd5f8c60f5fe57e152850a5de756978 rename test/integration/{pullRebaseInteractive/expected/.git_keep => pullRebaseConflict/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pullRebaseInteractive/expected/.git_keep => pullRebaseConflict/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/pullRebaseConflict/expected/origin/objects/ae/0aa5a0d1c65005bd50012612b1c56c1ea06155 rename test/integration/{pullRebaseInteractive/expected/.git_keep => pullRebaseConflict/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pullRebaseInteractive/expected/.git_keep => pullRebaseConflict/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pullRebaseConflict/expected/origin/packed-refs rename test/integration/pullRebaseConflict/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{pullRebaseInteractive/expected_remote => pullRebaseConflict/expected/repo/.git_keep}/HEAD (100%) create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/ORIG_HEAD rename test/integration/{pullRebase/expected => pullRebaseConflict/expected/repo}/.git_keep/config (93%) rename test/integration/{pullRebaseInteractive/expected_remote => pullRebaseConflict/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/index rename test/integration/{pullRebaseInteractive/expected_remote => pullRebaseConflict/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/logs/refs/remotes/origin/master create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/objects/00/36ac0e5f5536f55bfdfcb4e09927f1eed3b37b rename test/integration/{pullRebaseInteractive/expected_remote => pullRebaseConflict/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullRebaseInteractive/expected_remote => pullRebaseConflict/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pullRebaseInteractive/expected_remote => pullRebaseConflict/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pullRebaseConflict/{expected_remote => expected/repo/.git_keep}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/objects/30/8a85a7f740d42925175560337196f952ac6cf6 rename test/integration/pullRebaseConflict/expected/{ => repo}/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 (100%) create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/objects/70/2648e6efd5f8c60f5fe57e152850a5de756978 rename test/integration/pullRebaseConflict/expected/{ => repo}/.git_keep/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae (100%) rename test/integration/{pullRebaseInteractive/expected_remote => pullRebaseConflict/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pullRebaseInteractive/expected_remote => pullRebaseConflict/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/objects/ae/0aa5a0d1c65005bd50012612b1c56c1ea06155 rename test/integration/pullRebaseConflict/expected/{ => repo}/.git_keep/objects/ae/d6c0a012c68a8b615ab0185b64f59c414d4746 (100%) rename test/integration/pullRebaseConflict/expected/{ => repo}/.git_keep/objects/b2/da3d615a1805f094849247add77d09aee06451 (100%) create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/objects/bd/d975a23140e915dd46a1a16575c71bcad754ca rename test/integration/{pullRebaseInteractive/expected_remote => pullRebaseConflict/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/objects/d4/50cc8f4e691e3043aac25ae71f0f1a3217368f rename test/integration/{pullRebaseInteractive/expected_remote => pullRebaseConflict/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/pullRebaseConflict/expected/{ => repo}/.git_keep/objects/e6/1e2c991de853082420fd27fd983098afd4c0c8 (100%) rename test/integration/pullRebaseConflict/expected/{ => repo}/.git_keep/objects/e6/9912eb1649ce8dbb33678796cec3e89da3675d (100%) create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pullRebaseConflict/expected/repo/.git_keep/refs/remotes/origin/master rename test/integration/{pullRebaseInteractive/expected => pullRebaseConflict/expected/repo}/myfile1 (100%) rename test/integration/{pullRebaseInteractive/expected => pullRebaseConflict/expected/repo}/myfile2 (100%) rename test/integration/pullRebaseConflict/expected/{ => repo}/myfile3 (100%) rename test/integration/pullRebaseConflict/expected/{ => repo}/myfile4 (100%) delete mode 100644 test/integration/pullRebaseConflict/expected_remote/config delete mode 100644 test/integration/pullRebaseConflict/expected_remote/objects/10/3c3eb899d173b83fc1b40261c8880fef359cc3 delete mode 100644 test/integration/pullRebaseConflict/expected_remote/objects/34/574474ac6f7dd2d3142bc28ee39db88d8a16af delete mode 100644 test/integration/pullRebaseConflict/expected_remote/objects/3b/9389ff50095ad2d66d33bb6d67b5700f0bf6da delete mode 100644 test/integration/pullRebaseConflict/expected_remote/objects/aa/6ae0785290ee09875f6bd5a5d50c0e7002de13 delete mode 100644 test/integration/pullRebaseConflict/expected_remote/packed-refs delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/ORIG_HEAD delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/index delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/objects/29/daf999882c9e60c6b6a2868913a6cfd856d620 delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/objects/3f/b33027aedae13ab0796292c821a0258f6c2f7b delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/objects/42/3f7757eb2eea3de217b54447a94820af933d3a delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/objects/5c/32741b468f0ab8ddd243e9871dcc8dec5c35f9 delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/objects/74/ca3dec707dde7c92727d9490517e498360fea8 delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/objects/89/ee54b2ed7aff7c3aae24f64be85568f9a9d329 delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/objects/91/47ce4817b84339d884cee1683f361fd3aa4696 delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/objects/b8/9e837219d9a8aceb8b0f13381be0afb0dac427 delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/objects/bf/4fb489636d4bde42e478b04cbdcc079dcd0183 delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/objects/ca/58e8d47d619ffb625dc021f0ab2bb0f0bcf623 delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/objects/e2/251a5b6d32bf5fc57f234946e3fabeba3b5cca delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/objects/ea/4a99ea801f54f1ec09a88a28c65eb4db5865aa delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/objects/ef/bb36c97316886b089b1b27233cd8bfdc37ed4a delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pullRebaseInteractive/expected/.git_keep/refs/remotes/origin/master rename test/integration/{pullRebaseInteractiveWithDrop/expected/.git_keep => pullRebaseInteractive/expected/origin}/HEAD (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/origin/config rename test/integration/{pullRebaseInteractiveWithDrop/expected/.git_keep => pullRebaseInteractive/expected/origin}/description (100%) rename test/integration/{pullRebaseInteractiveWithDrop/expected/.git_keep => pullRebaseInteractive/expected/origin}/info/exclude (100%) rename test/integration/{pullRebaseInteractiveWithDrop/expected/.git_keep => pullRebaseInteractive/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullRebaseInteractiveWithDrop/expected/.git_keep => pullRebaseInteractive/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pullRebaseInteractiveWithDrop/expected/.git_keep => pullRebaseInteractive/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pullRebaseInteractive/expected/{.git_keep => origin}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/origin/objects/52/137603da2dccb618dfa0953d1b7df8c0255959 create mode 100644 test/integration/pullRebaseInteractive/expected/origin/objects/7c/0506ec2cd7852818e3e597619ff64af83770c6 create mode 100644 test/integration/pullRebaseInteractive/expected/origin/objects/91/d2303b08e6765e0ec38c401ecbab0cbb126dca rename test/integration/{pullRebaseInteractiveWithDrop/expected/.git_keep => pullRebaseInteractive/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pullRebaseInteractiveWithDrop/expected/.git_keep => pullRebaseInteractive/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pullRebaseInteractiveWithDrop/expected/.git_keep => pullRebaseInteractive/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/origin/objects/d4/3a810e4d47f2c632ea62ae581a8aade6f23b21 rename test/integration/{pullRebaseInteractiveWithDrop/expected/.git_keep => pullRebaseInteractive/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/origin/packed-refs rename test/integration/pullRebaseInteractive/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (61%) create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{pullRebaseInteractiveWithDrop/expected_remote => pullRebaseInteractive/expected/repo/.git_keep}/HEAD (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/ORIG_HEAD rename test/integration/pullRebaseInteractive/expected/{ => repo}/.git_keep/config (93%) rename test/integration/{pullRebaseInteractiveWithDrop/expected_remote => pullRebaseInteractive/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/index rename test/integration/{pullRebaseInteractiveWithDrop/expected_remote => pullRebaseInteractive/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/logs/refs/remotes/origin/master rename test/integration/pullRebaseInteractive/expected/{ => repo}/.git_keep/objects/00/a0b67048be84a6aeaa50b27ad90ab567d65837 (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/objects/03/5fa6a8b921a1d593845c5ce81434b92cc0eccb create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/objects/09/f87d11c514ba0a54e43193aaf9067174e2315e rename test/integration/{pullRebaseInteractiveWithDrop/expected_remote => pullRebaseInteractive/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pullRebaseInteractiveWithDrop/expected_remote => pullRebaseInteractive/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/pullRebaseInteractive/expected/{ => repo}/.git_keep/objects/24/21815f8570a34d9f8c8991df1005150ed3ae99 (100%) rename test/integration/{pullRebaseInteractiveWithDrop/expected_remote => pullRebaseInteractive/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/objects/2e/0409bb60df3c4587245fd01fdeb270bb5a24f3 rename test/integration/pullRebaseInteractive/{expected_remote => expected/repo/.git_keep}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/objects/41/6178fd7462af72f4357dda1241fc66063e467b create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/objects/52/137603da2dccb618dfa0953d1b7df8c0255959 create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/objects/5c/4dd6c94fae2afe48f413f48dc998ae48fcf463 rename test/integration/pullRebaseInteractive/expected/{ => repo}/.git_keep/objects/5d/0d8eb2623180ca95f2634f7e25f40521d5aea2 (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/objects/66/d3639353f039f2b87ea3e0dd3db13a5415c6df create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/objects/7c/0506ec2cd7852818e3e597619ff64af83770c6 rename test/integration/pullRebaseInteractive/expected/{ => repo}/.git_keep/objects/8c/fc761d2799512553e491f7ceb3564a5e994999 (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/objects/91/d2303b08e6765e0ec38c401ecbab0cbb126dca rename test/integration/pullRebaseInteractive/expected/{ => repo}/.git_keep/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae (100%) rename test/integration/pullRebaseInteractive/expected/{ => repo}/.git_keep/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 (100%) rename test/integration/{pullRebaseInteractiveWithDrop/expected_remote => pullRebaseInteractive/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pullRebaseInteractiveWithDrop/expected_remote => pullRebaseInteractive/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/pullRebaseInteractive/expected/{ => repo}/.git_keep/objects/ae/d6c0a012c68a8b615ab0185b64f59c414d4746 (100%) rename test/integration/pullRebaseInteractive/expected/{ => repo}/.git_keep/objects/b2/da3d615a1805f094849247add77d09aee06451 (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/objects/d2/17625c37713436bb6c92ff9d0b3991a8a7dba5 rename test/integration/{pullRebaseInteractiveWithDrop/expected_remote => pullRebaseInteractive/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/objects/d4/3a810e4d47f2c632ea62ae581a8aade6f23b21 rename test/integration/pullRebaseInteractive/expected/{ => repo}/.git_keep/objects/d4/8cf11b7fbbda4199b736bb9e8fadabf773eb9e (100%) rename test/integration/{pullRebaseInteractiveWithDrop/expected_remote => pullRebaseInteractive/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/objects/e9/74f4acf07db6fcaa438df552a8fd44e2d58dcd rename test/integration/pullRebaseInteractive/expected/{ => repo}/.git_keep/objects/f0/bbe52a52883609acdb825c8af32b4b3ccb0607 (100%) create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/objects/ff/0d57cafe9d745264b23450e9268cdb5ddc4edc create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pullRebaseInteractive/expected/repo/.git_keep/refs/remotes/origin/master rename test/integration/{pullRebaseInteractiveWithDrop/expected => pullRebaseInteractive/expected/repo}/myfile1 (100%) rename test/integration/{pullRebaseInteractiveWithDrop/expected => pullRebaseInteractive/expected/repo}/myfile2 (100%) rename test/integration/pullRebaseInteractive/expected/{ => repo}/myfile3 (100%) rename test/integration/pullRebaseInteractive/expected/{ => repo}/myfile4 (100%) rename test/integration/pullRebaseInteractive/expected/{ => repo}/myfile5 (100%) rename test/integration/pullRebaseInteractive/expected/{ => repo}/myfile6 (100%) rename test/integration/pullRebaseInteractive/expected/{ => repo}/myfile7 (100%) delete mode 100644 test/integration/pullRebaseInteractive/expected_remote/config delete mode 100644 test/integration/pullRebaseInteractive/expected_remote/objects/3f/b33027aedae13ab0796292c821a0258f6c2f7b delete mode 100644 test/integration/pullRebaseInteractive/expected_remote/objects/74/ca3dec707dde7c92727d9490517e498360fea8 delete mode 100644 test/integration/pullRebaseInteractive/expected_remote/objects/ca/58e8d47d619ffb625dc021f0ab2bb0f0bcf623 delete mode 100644 test/integration/pullRebaseInteractive/expected_remote/objects/ea/4a99ea801f54f1ec09a88a28c65eb4db5865aa delete mode 100644 test/integration/pullRebaseInteractive/expected_remote/packed-refs delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/ORIG_HEAD delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/index delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/objects/0f/a53867500c0f3a5cca9b2112982795fae51c51 delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/objects/45/89efcaf3024e841825bb289bb88eb0e4f8530a delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/objects/47/6a1939075b60aa47da50a8c40c5b4412a2f18b delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/objects/57/59b6258419271e67a172e51cd90048dd21f9c0 delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/objects/5d/08d9b6315ddb8fb8372d83b54862ba7d7fdc88 delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/objects/65/401620c5230dfa2ad6e0e2dcb6b447fe21262b delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/objects/69/a5c9fb912112305bfe15272855afb50f6acf4b delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/objects/7c/717449332e4a81f7e5643eef9c95f459444e3f delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/objects/90/13b5f12ca8a0fdd44fbe72028500bbac5c89ee delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/objects/ae/4e33d43751b83fbd0b6f0a1796d58462492e47 delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/objects/af/4c4b2b977f8909e590ea5bc3bab59d991e4c28 delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/objects/e0/47462bda495acbe565c85b205d614f38c0a692 delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/.git_keep/refs/remotes/origin/master rename test/integration/{push/expected/.git_keep => pullRebaseInteractiveWithDrop/expected/origin}/HEAD (100%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/origin/config rename test/integration/{push/expected/.git_keep => pullRebaseInteractiveWithDrop/expected/origin}/description (100%) rename test/integration/{push/expected/.git_keep => pullRebaseInteractiveWithDrop/expected/origin}/info/exclude (100%) rename test/integration/{push/expected/.git_keep => pullRebaseInteractiveWithDrop/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{push/expected/.git_keep => pullRebaseInteractiveWithDrop/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{push/expected/.git_keep => pullRebaseInteractiveWithDrop/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pullRebaseInteractiveWithDrop/expected/{.git_keep => origin}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/origin/objects/6e/44f128bc1b25454eeb074e40dd15d02eff5c87 rename test/integration/{push/expected/.git_keep => pullRebaseInteractiveWithDrop/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{push/expected/.git_keep => pullRebaseInteractiveWithDrop/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/origin/objects/a8/88f490faa49a665557b35171f4ce0896414ea2 create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/origin/objects/ce/137eabb7b8df81d4818ac8a16892b1f7327219 rename test/integration/{push/expected/.git_keep => pullRebaseInteractiveWithDrop/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{push/expected/.git_keep => pullRebaseInteractiveWithDrop/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/origin/objects/fe/fea9e2c324080a61d03142554b81e410e9c87f create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/origin/packed-refs rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (61%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{push/expected_remote => pullRebaseInteractiveWithDrop/expected/repo/.git_keep}/HEAD (100%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/ORIG_HEAD rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/.git_keep/config (93%) rename test/integration/{push/expected_remote => pullRebaseInteractiveWithDrop/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/index rename test/integration/{push/expected_remote => pullRebaseInteractiveWithDrop/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/logs/refs/remotes/origin/master rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/.git_keep/objects/00/a0b67048be84a6aeaa50b27ad90ab567d65837 (100%) rename test/integration/{push/expected_remote => pullRebaseInteractiveWithDrop/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{push/expected_remote => pullRebaseInteractiveWithDrop/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/.git_keep/objects/26/02a2a5727666c205fef7f152786e1edb1c5d4b (100%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/objects/28/1c7e805fd7bf133611e701ef01f0a4f362f232 rename test/integration/{push/expected_remote => pullRebaseInteractiveWithDrop/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pullRebaseInteractiveWithDrop/{expected_remote => expected/repo/.git_keep}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/objects/32/2d2d5205fe70df6899f8d58474941de4798aab create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/objects/3c/2846a93bb9c2815e3218ac3c906da26d159068 rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/.git_keep/objects/5d/0d8eb2623180ca95f2634f7e25f40521d5aea2 (100%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/objects/62/26d76652e77aba63c55f4f48344304f4f75879 create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/objects/67/c00631fc73b6b4d61a1dcb0195777f0d832fd7 create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/objects/6b/a64def9b38eb7bcf5aa1a6c513c490967062ad create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/objects/6e/44f128bc1b25454eeb074e40dd15d02eff5c87 create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/objects/72/da3b902dcd9e99b21bdc36891e028b8dbfb219 rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/.git_keep/objects/8c/fc761d2799512553e491f7ceb3564a5e994999 (100%) rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/.git_keep/objects/9b/1719f5cf069568785080a0bbabbe7c377e22ae (100%) rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/.git_keep/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 (100%) rename test/integration/{push/expected_remote => pullRebaseInteractiveWithDrop/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{push/expected_remote => pullRebaseInteractiveWithDrop/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/objects/a8/88f490faa49a665557b35171f4ce0896414ea2 rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/.git_keep/objects/ae/d6c0a012c68a8b615ab0185b64f59c414d4746 (100%) rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/.git_keep/objects/b2/da3d615a1805f094849247add77d09aee06451 (100%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/objects/ce/137eabb7b8df81d4818ac8a16892b1f7327219 create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/objects/d1/3fd4cd73174c7048108d2dc8d277a8e013d1e4 rename test/integration/{push/expected_remote => pullRebaseInteractiveWithDrop/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{push/expected_remote => pullRebaseInteractiveWithDrop/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/.git_keep/objects/f0/bbe52a52883609acdb825c8af32b4b3ccb0607 (100%) create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/objects/fe/fea9e2c324080a61d03142554b81e410e9c87f create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected/repo/.git_keep/refs/remotes/origin/master rename test/integration/{push/expected => pullRebaseInteractiveWithDrop/expected/repo}/myfile1 (100%) rename test/integration/{push/expected => pullRebaseInteractiveWithDrop/expected/repo}/myfile2 (100%) rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/myfile3 (100%) rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/myfile4 (100%) rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/myfile5 (100%) rename test/integration/pullRebaseInteractiveWithDrop/expected/{ => repo}/myfile7 (100%) delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected_remote/config delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected_remote/objects/45/89efcaf3024e841825bb289bb88eb0e4f8530a delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected_remote/objects/47/6a1939075b60aa47da50a8c40c5b4412a2f18b delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected_remote/objects/57/59b6258419271e67a172e51cd90048dd21f9c0 delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected_remote/objects/e0/47462bda495acbe565c85b205d614f38c0a692 delete mode 100644 test/integration/pullRebaseInteractiveWithDrop/expected_remote/packed-refs delete mode 100644 test/integration/push/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/push/expected/.git_keep/index delete mode 100644 test/integration/push/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/push/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/push/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/push/expected/.git_keep/objects/54/7f41a06ebd3bee30fbba3f43631810fa24f1bb delete mode 100644 test/integration/push/expected/.git_keep/objects/a0/9547e07257ed0456f498fde1b8214152427384 delete mode 100644 test/integration/push/expected/.git_keep/objects/a6/e580c7c3c4ea40bc311466d57a946bb3f77541 delete mode 100644 test/integration/push/expected/.git_keep/objects/eb/831bc1251f71f602159d98f4550e380007ca4f delete mode 100644 test/integration/push/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/push/expected/.git_keep/refs/remotes/origin/master rename test/integration/{pushAndSetUpstream/expected_remote => push/expected/origin}/HEAD (100%) rename test/integration/{pullMerge/expected_remote => push/expected/origin}/config (80%) rename test/integration/{pushAndSetUpstream/expected/.git_keep => push/expected/origin}/description (100%) rename test/integration/{pushAndSetUpstream/expected/.git_keep => push/expected/origin}/info/exclude (100%) rename test/integration/{pushAndSetUpstream/expected/.git_keep => push/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) create mode 100644 test/integration/push/expected/origin/objects/14/6ca480a776a466024a08d273987c4b2e71f23b rename test/integration/{pushAndSetUpstream/expected/.git_keep => push/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pushAndSetUpstream/expected/.git_keep => push/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/push/expected/{.git_keep => origin}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/push/expected/origin/objects/69/fef9300b95338821093ec2dfb6e2974d303510 create mode 100644 test/integration/push/expected/origin/objects/71/4500c4933e4316cc9747711829560cc42c2f8e rename test/integration/{pushAndSetUpstream/expected/.git_keep => push/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pushAndSetUpstream/expected/.git_keep => push/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pushAndSetUpstream/expected/.git_keep => push/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pushAndSetUpstream/expected/.git_keep => push/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/push/expected/origin/objects/ee/53190e06796d55bf236a35d45249c90eff8594 create mode 100644 test/integration/push/expected/origin/packed-refs create mode 100644 test/integration/push/expected/origin/refs/heads/master rename test/integration/{pushAndSetUpstream/expected => push/expected/repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/push/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{pushAndSetUpstreamDefault/expected_remote => push/expected/repo/.git_keep}/HEAD (100%) rename test/integration/{pull/expected => push/expected/repo}/.git_keep/config (92%) rename test/integration/{pushAndSetUpstream/expected_remote => push/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/push/expected/repo/.git_keep/index rename test/integration/{pushAndSetUpstream/expected_remote => push/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/push/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/push/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/push/expected/repo/.git_keep/logs/refs/remotes/origin/master rename test/integration/{pushAndSetUpstream/expected_remote => push/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) create mode 100644 test/integration/push/expected/repo/.git_keep/objects/14/6ca480a776a466024a08d273987c4b2e71f23b rename test/integration/{pushAndSetUpstream/expected_remote => push/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pushAndSetUpstream/expected_remote => push/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/push/{expected_remote => expected/repo/.git_keep}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/push/expected/repo/.git_keep/objects/69/fef9300b95338821093ec2dfb6e2974d303510 create mode 100644 test/integration/push/expected/repo/.git_keep/objects/71/4500c4933e4316cc9747711829560cc42c2f8e rename test/integration/{pushAndSetUpstream/expected_remote => push/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pushAndSetUpstream/expected_remote => push/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pushAndSetUpstream/expected_remote => push/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pushAndSetUpstream/expected_remote => push/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/push/expected/repo/.git_keep/objects/ee/53190e06796d55bf236a35d45249c90eff8594 create mode 100644 test/integration/push/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/push/expected/repo/.git_keep/refs/remotes/origin/master rename test/integration/{pushAndSetUpstream/expected => push/expected/repo}/myfile1 (100%) rename test/integration/{pushAndSetUpstream/expected => push/expected/repo}/myfile2 (100%) rename test/integration/push/expected/{ => repo}/myfile3 (100%) rename test/integration/push/expected/{ => repo}/myfile4 (100%) delete mode 100644 test/integration/push/expected_remote/objects/54/7f41a06ebd3bee30fbba3f43631810fa24f1bb delete mode 100644 test/integration/push/expected_remote/objects/a0/9547e07257ed0456f498fde1b8214152427384 delete mode 100644 test/integration/push/expected_remote/objects/a6/e580c7c3c4ea40bc311466d57a946bb3f77541 delete mode 100644 test/integration/push/expected_remote/objects/eb/831bc1251f71f602159d98f4550e380007ca4f delete mode 100644 test/integration/push/expected_remote/packed-refs delete mode 100644 test/integration/push/expected_remote/refs/heads/master delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/index delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/logs/refs/heads/test delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/logs/refs/remotes/origin/test delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/objects/65/c52315dc238c164b914369f49bd70882cc1d85 delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/objects/70/7a2a0835c897496934849bf6e0815593b140b3 delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/objects/da/b77371cf53420955fc9baeb84303414f7e4a60 delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/objects/db/d679941d871665b7ff70fffe6116725e56e270 delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/refs/heads/test delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/refs/remotes/origin/master delete mode 100644 test/integration/pushAndSetUpstream/expected/.git_keep/refs/remotes/origin/test rename test/integration/{pushFollowTags/expected/.git_keep => pushAndSetUpstream/expected/origin}/HEAD (100%) create mode 100644 test/integration/pushAndSetUpstream/expected/origin/config rename test/integration/{pushAndSetUpstreamDefault/expected/.git_keep => pushAndSetUpstream/expected/origin}/description (100%) rename test/integration/{pushAndSetUpstreamDefault/expected/.git_keep => pushAndSetUpstream/expected/origin}/info/exclude (100%) rename test/integration/{pushAndSetUpstreamDefault/expected/.git_keep => pushAndSetUpstream/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pushAndSetUpstreamDefault/expected/.git_keep => pushAndSetUpstream/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pushAndSetUpstreamDefault/expected/.git_keep => pushAndSetUpstream/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pushAndSetUpstream/expected/{.git_keep => origin}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pushAndSetUpstream/expected/origin/objects/97/8360cc5c0a9115bf3db5f10196cd135e1be962 rename test/integration/{pushAndSetUpstreamDefault/expected/.git_keep => pushAndSetUpstream/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pushAndSetUpstreamDefault/expected/.git_keep => pushAndSetUpstream/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pushAndSetUpstreamDefault/expected/.git_keep => pushAndSetUpstream/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) create mode 100644 test/integration/pushAndSetUpstream/expected/origin/objects/d7/7ec09ecf2391f9b76e54de98187095cd2edf9d rename test/integration/{pushAndSetUpstreamDefault/expected/.git_keep => pushAndSetUpstream/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pushAndSetUpstream/expected/origin/objects/e0/c356303c1b9b8fbe6acddb3e58f28b52348c60 create mode 100644 test/integration/pushAndSetUpstream/expected/origin/objects/ef/f34f9e6233e534513bb4b2154da4edd316283f create mode 100644 test/integration/pushAndSetUpstream/expected/origin/packed-refs create mode 100644 test/integration/pushAndSetUpstream/expected/origin/refs/heads/test rename test/integration/{pushAndSetUpstreamDefault/expected => pushAndSetUpstream/expected/repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/FETCH_HEAD rename test/integration/pushAndSetUpstream/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/pushAndSetUpstream/expected/{ => repo}/.git_keep/config (93%) rename test/integration/{pushAndSetUpstreamDefault/expected_remote => pushAndSetUpstream/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/index rename test/integration/{pushAndSetUpstreamDefault/expected_remote => pushAndSetUpstream/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/logs/refs/heads/test create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/logs/refs/remotes/origin/master create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/logs/refs/remotes/origin/test rename test/integration/{pushAndSetUpstreamDefault/expected_remote => pushAndSetUpstream/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pushAndSetUpstreamDefault/expected_remote => pushAndSetUpstream/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pushAndSetUpstreamDefault/expected_remote => pushAndSetUpstream/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pushAndSetUpstream/{expected_remote => expected/repo/.git_keep}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/objects/97/8360cc5c0a9115bf3db5f10196cd135e1be962 rename test/integration/{pushAndSetUpstreamDefault/expected_remote => pushAndSetUpstream/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pushAndSetUpstreamDefault/expected_remote => pushAndSetUpstream/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pushAndSetUpstreamDefault/expected_remote => pushAndSetUpstream/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/objects/d7/7ec09ecf2391f9b76e54de98187095cd2edf9d rename test/integration/{pushAndSetUpstreamDefault/expected_remote => pushAndSetUpstream/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/objects/e0/c356303c1b9b8fbe6acddb3e58f28b52348c60 create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/objects/ef/f34f9e6233e534513bb4b2154da4edd316283f create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/refs/heads/test create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/refs/remotes/origin/master create mode 100644 test/integration/pushAndSetUpstream/expected/repo/.git_keep/refs/remotes/origin/test rename test/integration/{pushAndSetUpstreamDefault/expected => pushAndSetUpstream/expected/repo}/myfile1 (100%) rename test/integration/{pushAndSetUpstreamDefault/expected => pushAndSetUpstream/expected/repo}/myfile2 (100%) rename test/integration/pushAndSetUpstream/expected/{ => repo}/myfile3 (100%) rename test/integration/pushAndSetUpstream/expected/{ => repo}/myfile4 (100%) delete mode 100644 test/integration/pushAndSetUpstream/expected_remote/config delete mode 100644 test/integration/pushAndSetUpstream/expected_remote/objects/65/c52315dc238c164b914369f49bd70882cc1d85 delete mode 100644 test/integration/pushAndSetUpstream/expected_remote/objects/70/7a2a0835c897496934849bf6e0815593b140b3 delete mode 100644 test/integration/pushAndSetUpstream/expected_remote/objects/da/b77371cf53420955fc9baeb84303414f7e4a60 delete mode 100644 test/integration/pushAndSetUpstream/expected_remote/objects/db/d679941d871665b7ff70fffe6116725e56e270 delete mode 100644 test/integration/pushAndSetUpstream/expected_remote/packed-refs delete mode 100644 test/integration/pushAndSetUpstream/expected_remote/refs/heads/test delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/index delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/logs/refs/heads/test delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/logs/refs/remotes/origin/test delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/objects/2d/0011f18dcd00e21fd13ede01792048ccd09e85 delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/objects/65/52acdbb2da7b153b78bbd9f6a564a54fce1ed9 delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/objects/d0/e2575d4cdf78f6845db57439c7b526d02dbc7d delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/objects/dc/7117cc68b23798cabb2c388a45036da33c2f10 delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/refs/heads/test delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/refs/remotes/origin/master delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected/.git_keep/refs/remotes/origin/test rename test/integration/{pushFollowTags/expected_remote => pushAndSetUpstreamDefault/expected/origin}/HEAD (100%) create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/origin/config rename test/integration/{pushFollowTags/expected/.git_keep => pushAndSetUpstreamDefault/expected/origin}/description (100%) rename test/integration/{pushFollowTags/expected/.git_keep => pushAndSetUpstreamDefault/expected/origin}/info/exclude (100%) rename test/integration/{pushFollowTags/expected/.git_keep => pushAndSetUpstreamDefault/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pushFollowTags/expected/.git_keep => pushAndSetUpstreamDefault/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pushFollowTags/expected/.git_keep => pushAndSetUpstreamDefault/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pushAndSetUpstreamDefault/expected/{.git_keep => origin}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/origin/objects/30/9d64f4b30c8a17897642eb8966189d2b054af2 create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/origin/objects/83/d120ae6a09eeef4e082d1c2cc81aac81075988 create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/origin/objects/8d/eea9ab6bed53871b952a62607704ea47d6d50e create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/origin/objects/a1/6265d00b218b3961405fc0c71a5ec2ffff879e rename test/integration/{pushFollowTags/expected/.git_keep => pushAndSetUpstreamDefault/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pushFollowTags/expected/.git_keep => pushAndSetUpstreamDefault/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pushWithCredentials/expected/.git_keep => pushAndSetUpstreamDefault/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pushFollowTags/expected/.git_keep => pushAndSetUpstreamDefault/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/origin/packed-refs create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/origin/refs/heads/test rename test/integration/{pushWithCredentials/expected => pushAndSetUpstreamDefault/expected/repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/FETCH_HEAD rename test/integration/pushAndSetUpstreamDefault/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/pushAndSetUpstreamDefault/expected/{ => repo}/.git_keep/config (93%) rename test/integration/{pushFollowTags/expected_remote => pushAndSetUpstreamDefault/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/index rename test/integration/{pushFollowTags/expected_remote => pushAndSetUpstreamDefault/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/logs/refs/heads/test create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/logs/refs/remotes/origin/master create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/logs/refs/remotes/origin/test rename test/integration/{pushFollowTags/expected_remote => pushAndSetUpstreamDefault/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pushFollowTags/expected_remote => pushAndSetUpstreamDefault/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pushFollowTags/expected_remote => pushAndSetUpstreamDefault/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pushAndSetUpstreamDefault/{expected_remote => expected/repo/.git_keep}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/objects/30/9d64f4b30c8a17897642eb8966189d2b054af2 create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/objects/83/d120ae6a09eeef4e082d1c2cc81aac81075988 create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/objects/8d/eea9ab6bed53871b952a62607704ea47d6d50e create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/objects/a1/6265d00b218b3961405fc0c71a5ec2ffff879e rename test/integration/{pushFollowTags/expected_remote => pushAndSetUpstreamDefault/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pushFollowTags/expected_remote => pushAndSetUpstreamDefault/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pushWithCredentials/expected_remote => pushAndSetUpstreamDefault/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{pushFollowTags/expected_remote => pushAndSetUpstreamDefault/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/refs/heads/test create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/refs/remotes/origin/master create mode 100644 test/integration/pushAndSetUpstreamDefault/expected/repo/.git_keep/refs/remotes/origin/test rename test/integration/{pushFollowTags/expected => pushAndSetUpstreamDefault/expected/repo}/myfile1 (100%) rename test/integration/{pushFollowTags/expected => pushAndSetUpstreamDefault/expected/repo}/myfile2 (100%) rename test/integration/pushAndSetUpstreamDefault/expected/{ => repo}/myfile3 (100%) rename test/integration/pushAndSetUpstreamDefault/expected/{ => repo}/myfile4 (100%) delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected_remote/config delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected_remote/objects/2d/0011f18dcd00e21fd13ede01792048ccd09e85 delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected_remote/objects/65/52acdbb2da7b153b78bbd9f6a564a54fce1ed9 delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected_remote/objects/d0/e2575d4cdf78f6845db57439c7b526d02dbc7d delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected_remote/objects/dc/7117cc68b23798cabb2c388a45036da33c2f10 delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected_remote/packed-refs delete mode 100644 test/integration/pushAndSetUpstreamDefault/expected_remote/refs/heads/test delete mode 100644 test/integration/pushFollowTags/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pushFollowTags/expected/.git_keep/index delete mode 100644 test/integration/pushFollowTags/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pushFollowTags/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pushFollowTags/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pushFollowTags/expected/.git_keep/objects/34/10e6811881ccede9ff762c875f9b99a3e6eaef delete mode 100644 test/integration/pushFollowTags/expected/.git_keep/objects/ae/a6b2960cc3e7a2453ce3490ca09d090d7ce223 delete mode 100644 test/integration/pushFollowTags/expected/.git_keep/objects/d0/d3bfe09c1a5a9631f3041a184d6b9c6d927c83 delete mode 100644 test/integration/pushFollowTags/expected/.git_keep/objects/f2/7af92910b10e6ddf592fae975337355579464b delete mode 100644 test/integration/pushFollowTags/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pushFollowTags/expected/.git_keep/refs/remotes/origin/master delete mode 100644 test/integration/pushFollowTags/expected/.git_keep/refs/tags/v1.0 rename test/integration/{pushNoFollowTags/expected/.git_keep => pushFollowTags/expected/origin}/HEAD (100%) create mode 100644 test/integration/pushFollowTags/expected/origin/config rename test/integration/{pushNoFollowTags/expected/.git_keep => pushFollowTags/expected/origin}/description (100%) rename test/integration/{pushNoFollowTags/expected/.git_keep => pushFollowTags/expected/origin}/info/exclude (100%) create mode 100644 test/integration/pushFollowTags/expected/origin/objects/03/63748fdf3c7a6947886a53d51208c0866f76af rename test/integration/{pushNoFollowTags/expected/.git_keep => pushFollowTags/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pushNoFollowTags/expected/.git_keep => pushFollowTags/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pushNoFollowTags/expected/.git_keep => pushFollowTags/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) create mode 100644 test/integration/pushFollowTags/expected/origin/objects/8a/c21a1d236ab7fb92c8f8082a98399596b59dd5 rename test/integration/{pushNoFollowTags/expected/.git_keep => pushFollowTags/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pushNoFollowTags/expected/.git_keep => pushFollowTags/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/pushFollowTags/expected/origin/objects/bc/1bee0a92515554303f848cbdecb4f7bc219e55 rename test/integration/{pushNoFollowTags/expected/.git_keep => pushFollowTags/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pushFollowTags/expected/origin/objects/f6/19224ae5e8ac2a5fa8e01624df4ca3d1b50d69 create mode 100644 test/integration/pushFollowTags/expected/origin/packed-refs create mode 100644 test/integration/pushFollowTags/expected/origin/refs/heads/master create mode 100644 test/integration/pushFollowTags/expected/origin/refs/tags/v1.0 rename test/integration/pushFollowTags/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/pushFollowTags/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{pushNoFollowTags/expected_remote => pushFollowTags/expected/repo/.git_keep}/HEAD (100%) rename test/integration/pushFollowTags/expected/{ => repo}/.git_keep/config (93%) rename test/integration/{pushNoFollowTags/expected_remote => pushFollowTags/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/pushFollowTags/expected/repo/.git_keep/index rename test/integration/{pushNoFollowTags/expected_remote => pushFollowTags/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/pushFollowTags/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pushFollowTags/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pushFollowTags/expected/repo/.git_keep/logs/refs/remotes/origin/master create mode 100644 test/integration/pushFollowTags/expected/repo/.git_keep/objects/03/63748fdf3c7a6947886a53d51208c0866f76af rename test/integration/{pushNoFollowTags/expected_remote => pushFollowTags/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pushNoFollowTags/expected_remote => pushFollowTags/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pushNoFollowTags/expected_remote => pushFollowTags/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) create mode 100644 test/integration/pushFollowTags/expected/repo/.git_keep/objects/8a/c21a1d236ab7fb92c8f8082a98399596b59dd5 rename test/integration/{pushNoFollowTags/expected_remote => pushFollowTags/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pushNoFollowTags/expected_remote => pushFollowTags/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/pushFollowTags/expected/repo/.git_keep/objects/bc/1bee0a92515554303f848cbdecb4f7bc219e55 rename test/integration/{pushNoFollowTags/expected_remote => pushFollowTags/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pushFollowTags/expected/repo/.git_keep/objects/f6/19224ae5e8ac2a5fa8e01624df4ca3d1b50d69 create mode 100644 test/integration/pushFollowTags/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pushFollowTags/expected/repo/.git_keep/refs/remotes/origin/master create mode 100644 test/integration/pushFollowTags/expected/repo/.git_keep/refs/tags/v1.0 rename test/integration/{pushNoFollowTags/expected => pushFollowTags/expected/repo}/myfile1 (100%) rename test/integration/{pushNoFollowTags/expected => pushFollowTags/expected/repo}/myfile2 (100%) rename test/integration/pushFollowTags/expected/{ => repo}/myfile3 (100%) delete mode 100644 test/integration/pushFollowTags/expected_remote/config delete mode 100644 test/integration/pushFollowTags/expected_remote/objects/34/10e6811881ccede9ff762c875f9b99a3e6eaef delete mode 100644 test/integration/pushFollowTags/expected_remote/objects/ae/a6b2960cc3e7a2453ce3490ca09d090d7ce223 delete mode 100644 test/integration/pushFollowTags/expected_remote/objects/d0/d3bfe09c1a5a9631f3041a184d6b9c6d927c83 delete mode 100644 test/integration/pushFollowTags/expected_remote/objects/f2/7af92910b10e6ddf592fae975337355579464b delete mode 100644 test/integration/pushFollowTags/expected_remote/packed-refs delete mode 100644 test/integration/pushFollowTags/expected_remote/refs/heads/master delete mode 100644 test/integration/pushFollowTags/expected_remote/refs/tags/v1.0 delete mode 100644 test/integration/pushNoFollowTags/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pushNoFollowTags/expected/.git_keep/config delete mode 100644 test/integration/pushNoFollowTags/expected/.git_keep/index delete mode 100644 test/integration/pushNoFollowTags/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pushNoFollowTags/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pushNoFollowTags/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pushNoFollowTags/expected/.git_keep/objects/03/009ca2af4be2a9bb49206974ce9c97eaa2da23 delete mode 100644 test/integration/pushNoFollowTags/expected/.git_keep/objects/8f/99b05bf3462e1a797335475bff5fabe3ae9ec5 delete mode 100644 test/integration/pushNoFollowTags/expected/.git_keep/objects/e1/9bd88e6b3a0d7e4ffc1de39b34d5a312fb9b77 delete mode 100644 test/integration/pushNoFollowTags/expected/.git_keep/objects/fb/20b9e96648c61699f9faf3a4383340fefd5f91 delete mode 100644 test/integration/pushNoFollowTags/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pushNoFollowTags/expected/.git_keep/refs/remotes/origin/master delete mode 100644 test/integration/pushNoFollowTags/expected/.git_keep/refs/tags/v1.0 rename test/integration/{pushTag/expected/.git_keep => pushNoFollowTags/expected/origin}/HEAD (100%) create mode 100644 test/integration/pushNoFollowTags/expected/origin/config rename test/integration/{pushTag/expected/.git_keep => pushNoFollowTags/expected/origin}/description (100%) rename test/integration/{pushTag/expected/.git_keep => pushNoFollowTags/expected/origin}/info/exclude (100%) rename test/integration/{pushTag/expected/.git_keep => pushNoFollowTags/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pushTag/expected/.git_keep => pushNoFollowTags/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pushWithCredentials/expected/.git_keep => pushNoFollowTags/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) create mode 100644 test/integration/pushNoFollowTags/expected/origin/objects/32/a7825dd9144b755bd2bbefa9f0f75047d53aae create mode 100644 test/integration/pushNoFollowTags/expected/origin/objects/4f/7c2bf086a8b6ba8cdb00cf76dbb18543c4ef3b rename test/integration/{pushTag/expected/.git_keep => pushNoFollowTags/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pushTag/expected/.git_keep => pushNoFollowTags/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{pushWithCredentials/expected/.git_keep => pushNoFollowTags/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pushNoFollowTags/expected/origin/objects/f0/ce9150789c4aef204270b5201d22e6f7e8b23b create mode 100644 test/integration/pushNoFollowTags/expected/origin/packed-refs create mode 100644 test/integration/pushNoFollowTags/expected/origin/refs/heads/master rename test/integration/pushNoFollowTags/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/pushNoFollowTags/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{pushTag/expected_remote => pushNoFollowTags/expected/repo/.git_keep}/HEAD (100%) create mode 100644 test/integration/pushNoFollowTags/expected/repo/.git_keep/config rename test/integration/{pushTag/expected_remote => pushNoFollowTags/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/pushNoFollowTags/expected/repo/.git_keep/index rename test/integration/{pushTag/expected_remote => pushNoFollowTags/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/pushNoFollowTags/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pushNoFollowTags/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pushNoFollowTags/expected/repo/.git_keep/logs/refs/remotes/origin/master rename test/integration/{pushTag/expected_remote => pushNoFollowTags/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pushTag/expected_remote => pushNoFollowTags/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{pushWithCredentials/expected_remote => pushNoFollowTags/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) create mode 100644 test/integration/pushNoFollowTags/expected/repo/.git_keep/objects/32/a7825dd9144b755bd2bbefa9f0f75047d53aae create mode 100644 test/integration/pushNoFollowTags/expected/repo/.git_keep/objects/4f/7c2bf086a8b6ba8cdb00cf76dbb18543c4ef3b rename test/integration/{pushTag/expected_remote => pushNoFollowTags/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pushTag/expected_remote => pushNoFollowTags/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/pushNoFollowTags/expected/repo/.git_keep/objects/bc/74fd77b84a00637ff1a30dc835d7d9d48e5e16 rename test/integration/{pushWithCredentials/expected_remote => pushNoFollowTags/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pushNoFollowTags/expected/repo/.git_keep/objects/f0/ce9150789c4aef204270b5201d22e6f7e8b23b create mode 100644 test/integration/pushNoFollowTags/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pushNoFollowTags/expected/repo/.git_keep/refs/remotes/origin/master create mode 100644 test/integration/pushNoFollowTags/expected/repo/.git_keep/refs/tags/v1.0 rename test/integration/{pushTag/expected => pushNoFollowTags/expected/repo}/myfile1 (100%) rename test/integration/{pushTag/expected => pushNoFollowTags/expected/repo}/myfile2 (100%) rename test/integration/pushNoFollowTags/expected/{ => repo}/myfile3 (100%) delete mode 100644 test/integration/pushNoFollowTags/expected_remote/config delete mode 100644 test/integration/pushNoFollowTags/expected_remote/objects/03/009ca2af4be2a9bb49206974ce9c97eaa2da23 delete mode 100644 test/integration/pushNoFollowTags/expected_remote/objects/8f/99b05bf3462e1a797335475bff5fabe3ae9ec5 delete mode 100644 test/integration/pushNoFollowTags/expected_remote/objects/fb/20b9e96648c61699f9faf3a4383340fefd5f91 delete mode 100644 test/integration/pushNoFollowTags/expected_remote/packed-refs delete mode 100644 test/integration/pushNoFollowTags/expected_remote/refs/heads/master delete mode 100644 test/integration/pushTag/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pushTag/expected/.git_keep/config delete mode 100644 test/integration/pushTag/expected/.git_keep/index delete mode 100644 test/integration/pushTag/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pushTag/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pushTag/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pushTag/expected/.git_keep/objects/5e/8100f80934cb3f1530579225107a478afac4ee delete mode 100644 test/integration/pushTag/expected/.git_keep/objects/f5/e0cf8631fc56de2f374ef60e123a2b643381e5 delete mode 100644 test/integration/pushTag/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pushTag/expected/.git_keep/refs/remotes/origin/master delete mode 100644 test/integration/pushTag/expected/.git_keep/refs/tags/v1.0 rename test/integration/{pushWithCredentials/expected/.git_keep => pushTag/expected/origin}/HEAD (100%) rename test/integration/{fetchPrune/expected_remote => pushTag/expected/origin}/config (79%) rename test/integration/{pushWithCredentials/expected/.git_keep => pushTag/expected/origin}/description (100%) rename test/integration/{pushWithCredentials/expected/.git_keep => pushTag/expected/origin}/info/exclude (100%) rename test/integration/{pushWithCredentials/expected/.git_keep => pushTag/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pushWithCredentials/expected/.git_keep => pushTag/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) create mode 100644 test/integration/pushTag/expected/origin/objects/a4/72e4256e0cabe433e1655f13d45f5093f502f3 rename test/integration/{pushWithCredentials/expected/.git_keep => pushTag/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pushWithCredentials/expected/.git_keep => pushTag/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/pushTag/expected/origin/objects/f4/d17a0fe9700c664eb4227b5992a4117c481eb4 create mode 100644 test/integration/pushTag/expected/origin/packed-refs create mode 100644 test/integration/pushTag/expected/origin/refs/tags/v1.0 rename test/integration/pushTag/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/pushTag/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{pushWithCredentials/expected_remote => pushTag/expected/repo/.git_keep}/HEAD (100%) create mode 100644 test/integration/pushTag/expected/repo/.git_keep/config rename test/integration/{pushWithCredentials/expected_remote => pushTag/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/pushTag/expected/repo/.git_keep/index rename test/integration/{pushWithCredentials/expected_remote => pushTag/expected/repo/.git_keep}/info/exclude (100%) create mode 100644 test/integration/pushTag/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pushTag/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pushTag/expected/repo/.git_keep/logs/refs/remotes/origin/master rename test/integration/{pushWithCredentials/expected_remote => pushTag/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{pushWithCredentials/expected_remote => pushTag/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) create mode 100644 test/integration/pushTag/expected/repo/.git_keep/objects/a4/72e4256e0cabe433e1655f13d45f5093f502f3 rename test/integration/{pushWithCredentials/expected_remote => pushTag/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{pushWithCredentials/expected_remote => pushTag/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/pushTag/expected/repo/.git_keep/objects/f4/d17a0fe9700c664eb4227b5992a4117c481eb4 create mode 100644 test/integration/pushTag/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pushTag/expected/repo/.git_keep/refs/remotes/origin/master create mode 100644 test/integration/pushTag/expected/repo/.git_keep/refs/tags/v1.0 rename test/integration/{pushWithCredentials/expected => pushTag/expected/repo}/myfile1 (100%) rename test/integration/{pushWithCredentials/expected => pushTag/expected/repo}/myfile2 (100%) delete mode 100644 test/integration/pushTag/expected_remote/config delete mode 100644 test/integration/pushTag/expected_remote/objects/5e/8100f80934cb3f1530579225107a478afac4ee delete mode 100644 test/integration/pushTag/expected_remote/objects/f5/e0cf8631fc56de2f374ef60e123a2b643381e5 delete mode 100644 test/integration/pushTag/expected_remote/packed-refs delete mode 100644 test/integration/pushTag/expected_remote/refs/tags/v1.0 delete mode 100644 test/integration/pushWithCredentials/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/pushWithCredentials/expected/.git_keep/config delete mode 100644 test/integration/pushWithCredentials/expected/.git_keep/index delete mode 100644 test/integration/pushWithCredentials/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/pushWithCredentials/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/pushWithCredentials/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/pushWithCredentials/expected/.git_keep/objects/75/c50688e5a8e48a00d1a824124221bcc6aad640 delete mode 100644 test/integration/pushWithCredentials/expected/.git_keep/objects/ba/8cb1da2a48c38706b15552877d79e8745c4bff delete mode 100644 test/integration/pushWithCredentials/expected/.git_keep/objects/d9/ea8db22c1655e9861309cc97139357d20e4e64 delete mode 100644 test/integration/pushWithCredentials/expected/.git_keep/objects/ff/7015f162da19450f2eaf0fc24987104df30e15 delete mode 100644 test/integration/pushWithCredentials/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/pushWithCredentials/expected/.git_keep/refs/remotes/origin/master rename test/integration/{rebase/expected/.git_keep => pushWithCredentials/expected/origin}/HEAD (100%) create mode 100644 test/integration/pushWithCredentials/expected/origin/config rename test/integration/{rebase/expected/.git_keep => pushWithCredentials/expected/origin}/description (100%) rename test/integration/{rebase/expected/.git_keep => pushWithCredentials/expected/origin}/info/exclude (100%) rename test/integration/{searching/expected/.git_keep => pushWithCredentials/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{rebase/expected/.git_keep => pushWithCredentials/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{searching/expected/.git_keep => pushWithCredentials/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pushWithCredentials/expected/{.git_keep => origin}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pushWithCredentials/expected/origin/objects/3e/912c74bc7c237df0c521aff7b3f4932d7e8616 create mode 100644 test/integration/pushWithCredentials/expected/origin/objects/5b/85aaf0806d1bc5830bb10291727f773c3402dc create mode 100644 test/integration/pushWithCredentials/expected/origin/objects/5d/98350a913b48a35001ff9b54335f065b25fd7c rename test/integration/{rebase/expected/.git_keep => pushWithCredentials/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{searching/expected/.git_keep => pushWithCredentials/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/pushWithCredentials/expected/origin/objects/d1/08cb97213835c25d44e14d167e7c5b48f94ce2 rename test/integration/{rebase2/expected/.git_keep => pushWithCredentials/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{rebase/expected/.git_keep => pushWithCredentials/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pushWithCredentials/expected/origin/packed-refs create mode 100644 test/integration/pushWithCredentials/expected/origin/refs/heads/master rename test/integration/{setUpstream/expected => pushWithCredentials/expected/repo}/.git_keep/COMMIT_EDITMSG (100%) create mode 100644 test/integration/pushWithCredentials/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{rebase2/expected => pushWithCredentials/expected/repo}/.git_keep/HEAD (100%) create mode 100644 test/integration/pushWithCredentials/expected/repo/.git_keep/config rename test/integration/{rebase2/expected => pushWithCredentials/expected/repo}/.git_keep/description (100%) create mode 100644 test/integration/pushWithCredentials/expected/repo/.git_keep/index rename test/integration/{rebase2/expected => pushWithCredentials/expected/repo}/.git_keep/info/exclude (100%) create mode 100644 test/integration/pushWithCredentials/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/pushWithCredentials/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/pushWithCredentials/expected/repo/.git_keep/logs/refs/remotes/origin/master rename test/integration/{setUpstream/expected => pushWithCredentials/expected/repo}/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{rebase2/expected => pushWithCredentials/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{setUpstream/expected => pushWithCredentials/expected/repo}/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/pushWithCredentials/{expected_remote => expected/repo/.git_keep}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/pushWithCredentials/expected/repo/.git_keep/objects/3e/912c74bc7c237df0c521aff7b3f4932d7e8616 create mode 100644 test/integration/pushWithCredentials/expected/repo/.git_keep/objects/5b/85aaf0806d1bc5830bb10291727f773c3402dc create mode 100644 test/integration/pushWithCredentials/expected/repo/.git_keep/objects/5d/98350a913b48a35001ff9b54335f065b25fd7c rename test/integration/{rebase2/expected => pushWithCredentials/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{setUpstream/expected => pushWithCredentials/expected/repo}/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/pushWithCredentials/expected/repo/.git_keep/objects/d1/08cb97213835c25d44e14d167e7c5b48f94ce2 rename test/integration/{rebase3/expected => pushWithCredentials/expected/repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{rebase2/expected => pushWithCredentials/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/pushWithCredentials/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/pushWithCredentials/expected/repo/.git_keep/refs/remotes/origin/master rename test/integration/{searching/expected => pushWithCredentials/expected/repo}/myfile1 (100%) rename test/integration/{setUpstream/expected => pushWithCredentials/expected/repo}/myfile2 (100%) rename test/integration/pushWithCredentials/expected/{ => repo}/myfile3 (100%) rename test/integration/pushWithCredentials/expected/{ => repo}/myfile4 (100%) delete mode 100644 test/integration/pushWithCredentials/expected_remote/config delete mode 100644 test/integration/pushWithCredentials/expected_remote/objects/75/c50688e5a8e48a00d1a824124221bcc6aad640 delete mode 100644 test/integration/pushWithCredentials/expected_remote/objects/ba/8cb1da2a48c38706b15552877d79e8745c4bff delete mode 100644 test/integration/pushWithCredentials/expected_remote/objects/d9/ea8db22c1655e9861309cc97139357d20e4e64 delete mode 100644 test/integration/pushWithCredentials/expected_remote/objects/ff/7015f162da19450f2eaf0fc24987104df30e15 delete mode 100644 test/integration/pushWithCredentials/expected_remote/packed-refs delete mode 100644 test/integration/pushWithCredentials/expected_remote/refs/heads/master rename test/integration/rebase/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{rebase3/expected => rebase/expected/repo}/.git_keep/HEAD (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{rebase3/expected => rebase/expected/repo}/.git_keep/description (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{rebase3/expected => rebase/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/{rebase3/expected => rebase/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/objects/18/24d7294d6d3524d83510db27086177a6db97bf (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/objects/44/e5064a45438ffa3e6e4a0f1444552e2199be97 (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/objects/47/614f63053804bc596291b8f7cff3b460b1b3ee (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/objects/57/8ebf1736e797b78fb670c718ebf177936eb2ef (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{rebase3/expected => rebase/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/{rebase3/expected => rebase/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/objects/e8/ece6af94d443b67962124243509d8f61a29758 (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/objects/ec/fc5809e3397bbda6bd4c9f47267a8c5f22346c (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/objects/fa/af373a925c1e335894ebf4343a00a917f04edc (100%) rename test/integration/rebase/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/rebase/expected/{ => repo}/file0 (100%) rename test/integration/rebase/expected/{ => repo}/file1 (100%) rename test/integration/rebase/expected/{ => repo}/file2 (100%) rename test/integration/rebase/expected/{ => repo}/file4 (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{rebaseFixupAndSquash/expected => rebase2/expected/repo}/.git_keep/HEAD (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/MERGE_MSG (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/REBASE_HEAD (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{rebaseFixupAndSquash/expected => rebase2/expected/repo}/.git_keep/description (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{rebaseFixupAndSquash/expected => rebase2/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/{rebaseFixupAndSquash/expected => rebase2/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/26/d430fb59900099e9992a3c79f30e42309cdce3 (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/44/e5064a45438ffa3e6e4a0f1444552e2199be97 (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/4a/edafb1a5d371825cbfea5ffcf2692cc786a1bf (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/61/baf480bb5ddfad6d66c785b321d4aadd5367b4 (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/8d/3ce0d821345b25fef1188e48cba4a1d44c30be (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{rebaseFixupAndSquash/expected => rebase2/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/bb/c22338ee174004f5c5fa117688249bc5b7e205 (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/bc/e4745137c540943900ca78e4b31dd1315bf57c (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/c3/6e808d2fa61e16952b7d0ffb8f18d08156cc94 (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/c3/901284a9e7fc063d6fa7f0c5797d031445ba45 (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/cc/01bf15804065932f5e50340902614b3c04c948 (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/{rebaseFixupAndSquash/expected => rebase2/expected/repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{rebaseFixupAndSquash/expected => rebase2/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/f9/4292928d0bc034fe88c753306b1959300e1264 (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/objects/ff/3fb62dafc2fdd0c81ed64bc132b53584e5e1e2 (100%) rename test/integration/rebase2/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/rebase2/expected/{ => repo}/file0 (100%) rename test/integration/rebase2/expected/{ => repo}/file1 (100%) rename test/integration/rebase2/expected/{ => repo}/file2 (100%) rename test/integration/rebase2/expected/{ => repo}/file4 (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{rebaseFixups/expected => rebase3/expected/repo}/.git_keep/HEAD (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{rebaseFixups/expected => rebase3/expected/repo}/.git_keep/description (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{rebaseFixups/expected => rebase3/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/{rebaseFixups/expected => rebase3/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/3c/21f03d819ae34b74084712c3ef1b9b99b2f40e (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/44/e5064a45438ffa3e6e4a0f1444552e2199be97 (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/4b/f6ae41c5ef2186c87f5f39dbb8cadd76c597cc (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/51/a0e4a6635c22a062a48b7134dd556541a1e06c (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/7b/42ba8a9f370bbbf0db85c5aca61f4e8a7b3d26 (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/8f/2acebb8a7a83cfaf3cffc6a9103f633f5cf292 (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/9e/68fbe4291e7416d50587d9b6968aa5ceeccff9 (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{rebaseFixups/expected => rebase3/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/cc/01bf15804065932f5e50340902614b3c04c948 (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/{rebaseFixups/expected => rebase3/expected/repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/d8/ae31faf375fd293cedb0c88c41a9c7a77a2530 (100%) rename test/integration/{rebaseFixups/expected => rebase3/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/f0/6dfb4e9e5a9dfab869590058f2c1ce1c72b2ac (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/fd/ecf9e3e742db4c8690d56b328b2533e67d2866 (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/objects/ff/3fb62dafc2fdd0c81ed64bc132b53584e5e1e2 (100%) rename test/integration/rebase3/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/rebase3/expected/{ => repo}/file0 (100%) rename test/integration/rebase3/expected/{ => repo}/file1 (100%) rename test/integration/rebase3/expected/{ => repo}/file2 (100%) rename test/integration/rebase3/expected/{ => repo}/file4 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{rebaseRewordLastCommit/expected => rebaseFixupAndSquash/expected/repo}/.git_keep/HEAD (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{rebaseRewordLastCommit/expected => rebaseFixupAndSquash/expected/repo}/.git_keep/description (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{rebaseRewordLastCommit/expected => rebaseFixupAndSquash/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/0d/633de5bd380e6b42e03ec1e7a055ba4f3c860d (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/12/ed10a6439eadfdb8877e39b7c6547591a0a91c (100%) rename test/integration/{rebaseRewordLastCommit/expected => rebaseFixupAndSquash/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/1d/197a4c509a5e71bad9b0b439c8fd26323ff218 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/44/e5064a45438ffa3e6e4a0f1444552e2199be97 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/4a/e4346ad59bf70d5ba07184af5a138b6a65c224 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/4d/c7f318f68fe1890dba6fb595009c4652c0a861 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/74/d431c56eac1e359f6f5736978347af68af5702 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/76/79fc004a4a40da12907d72ccef14991976aaff (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/7b/01314ccdeccc57cee454feca6369237410e786 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/8a/db7457de59c3945566ce7675a31bbf048b38ee (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{rebaseRewordLastCommit/expected => rebaseFixupAndSquash/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/cc/01bf15804065932f5e50340902614b3c04c948 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/{rebaseSwapping/expected => rebaseFixupAndSquash/expected/repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/db/ab7e62cd7517f73425d46120a931a59c8eda6e (100%) rename test/integration/{rebaseRewordLastCommit/expected => rebaseFixupAndSquash/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/objects/ff/3fb62dafc2fdd0c81ed64bc132b53584e5e1e2 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/file0 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/file1 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/file2 (100%) rename test/integration/rebaseFixupAndSquash/expected/{ => repo}/file4 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{rebaseRewordOldCommit/expected => rebaseFixups/expected/repo}/.git_keep/HEAD (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{rebaseRewordOldCommit/expected => rebaseFixups/expected/repo}/.git_keep/description (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{rebaseRewordOldCommit/expected => rebaseFixups/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/10/56fd624d61daad06a8726c0ea5626820cafe59 (100%) rename test/integration/{rebaseRewordOldCommit/expected => rebaseFixups/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/1d/7ab21ab5322589052cf9d2d62ca58677f454cc (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/2a/627747a92ce8c274f7df0da3329616f69b9856 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/2b/d4d58d29b60b5868c19437ff4467d84ed270aa (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/30/a685cfa43930aadd5b56b2ec0746564d1a1d22 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/33/1be377b5889b19b5900bc4bed98b1c9cc40095 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/44/e5064a45438ffa3e6e4a0f1444552e2199be97 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/4d/7b35df7f8ced30495fc0f62b91a270bad7076b (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/69/ebe8bf01f728a9bc787e8553694e36127b48c0 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/77/741cf500de50347e9f4e5a091515e4568ddad3 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{rebaseRewordOldCommit/expected => rebaseFixups/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/ac/e527b9737b6c554963361f50ce98a0509c2344 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/ad/46c1683d660e21b4f13ad808420a4de18326b7 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/b8/c4d6287efcb68cdffbac00ec15ffc25f575cc5 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/ba/860ef885ce294ade006af8afda01a8cc584a12 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/c8/07dfd74adc1e1b732025cab46cf56b4d193e74 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/c8/738908c85292494dba61be9c050ad95ff0e182 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/cc/01bf15804065932f5e50340902614b3c04c948 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/d1/3e563982268d8ab77ad47793a2b501dfe6a0dc (100%) rename test/integration/{searching/expected => rebaseFixups/expected/repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/dc/bade3308277dabb66de476c1cce03bd840d22a (100%) rename test/integration/{rebaseRewordOldCommit/expected => rebaseFixups/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/e3/ad04c1fd3c9137b052ecb422855052f044d88f (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/objects/ff/3fb62dafc2fdd0c81ed64bc132b53584e5e1e2 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/rebaseFixups/expected/{ => repo}/file0 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/file1 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/file2 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/file4 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/file5 (100%) rename test/integration/rebaseFixups/expected/{ => repo}/file6 (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{rebaseSwapping/expected => rebaseRewordLastCommit/expected/repo}/.git_keep/HEAD (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{rebaseSwapping/expected => rebaseRewordLastCommit/expected/repo}/.git_keep/description (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{rebaseSwapping/expected => rebaseRewordLastCommit/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/{rebaseSwapping/expected => rebaseRewordLastCommit/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/objects/59/f4e88de812c15bf0fa7b224cdb361f7ede8931 (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/objects/74/abc9e0d0ec8dd0f5ea872a851364206008ea2b (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/objects/97/066d3866b8e5ead0b68fc746a02222408f28a3 (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{rebaseSwapping/expected => rebaseRewordLastCommit/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/objects/d4/83ea1d742e44d9191f3e31e926d7621c513042 (100%) rename test/integration/{rebaseSwapping/expected => rebaseRewordLastCommit/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/objects/e2/98537fd470f70bbb174d78f610fe49539cfe66 (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/file0 (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/file1 (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/file2 (100%) rename test/integration/rebaseRewordLastCommit/expected/{ => repo}/file3 (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{reflogCherryPick/expected => rebaseRewordOldCommit/expected/repo}/.git_keep/HEAD (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{reflogCheckout/expected => rebaseRewordOldCommit/expected/repo}/.git_keep/description (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{reflogCheckout/expected => rebaseRewordOldCommit/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/{reflogCheckout/expected => rebaseRewordOldCommit/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/objects/1b/cb7e30b3a5a5ae64397dcfe6b74cc18fc55784 (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/objects/3c/3125afd7a6475dcdd4c4a6b20cc920b31eb96f (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/objects/44/79c0a1c7e43a55a3a6909be88a810dbad3fc42 (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/objects/64/7b9df53752363ecdc1d4c5cebe7d66e6132bfe (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/objects/7c/5b8c907caad01842aa84e91b7d4724d57de4fd (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/objects/9d/793e4fc04a0583eed7670d52fbb16b402f7499 (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{reflogCheckout/expected => rebaseRewordOldCommit/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/objects/c0/793b482cdf9ca48686dbf56fc0a46e982003e1 (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/objects/d4/83ea1d742e44d9191f3e31e926d7621c513042 (100%) rename test/integration/{searching/expected => rebaseRewordOldCommit/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/file0 (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/file1 (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/file2 (100%) rename test/integration/rebaseRewordOldCommit/expected/{ => repo}/file3 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{rememberCommitMessageAfterFail/expected => rebaseSwapping/expected/repo}/.git_keep/HEAD (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/REBASE_HEAD (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{reflogCherryPick/expected => rebaseSwapping/expected/repo}/.git_keep/description (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{reflogCherryPick/expected => rebaseSwapping/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/0e/45fe2fb8b21adfe348ec5419bd87e4c796c02a (100%) rename test/integration/{reflogCherryPick/expected => rebaseSwapping/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/41/eefd8a741d391640c4e0528e0b6fff31f90a18 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/44/e5064a45438ffa3e6e4a0f1444552e2199be97 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/5e/6e75233f7d0501f030400c0b55d4c778b72b73 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/61/3c1bfa180babe5e67317d1ef42d566718a7d8f (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/84/c7a918e6bd704aaf4f789ecaea479ab31d4741 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{reflogCherryPick/expected => rebaseSwapping/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/ac/32b36c1b300cc79ad3f16dfb3c8a77ea7f4965 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/b2/18d34eec545f29156411f24ab609b970082e1c (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/cc/01bf15804065932f5e50340902614b3c04c948 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/ce/ada384bff8df54abb8acbf497b751aa9220f00 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/{setUpstream/expected => rebaseSwapping/expected/repo}/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/d2/3bcf26566cbf601e766d12ea206cb7827d6630 (100%) rename test/integration/{setUpstream/expected => rebaseSwapping/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/ff/3fb62dafc2fdd0c81ed64bc132b53584e5e1e2 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/objects/ff/8d9889fccee3b361f37c46c9f0de3f5ef6d70f (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/file0 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/file1 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/file2 (100%) rename test/integration/rebaseSwapping/expected/{ => repo}/file4 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{reflogCommitFiles/expected => reflogCheckout/expected/repo}/.git_keep/description (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{reflogCommitFiles/expected => reflogCheckout/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/logs/refs/heads/branch2 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/logs/refs/heads/ma (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/10/e005e1fa2db07721aa63cb048b87b7a2830b64 (100%) rename test/integration/{reflogCommitFiles/expected => reflogCheckout/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/2b/16e862b7fc2a6ce1e711e5e174bc2f08c0e001 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/37/661793a793e075730b85b9c3b300195738fc63 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/40/e3ff58efe2f50bc70ab084aba687ffd56dcd38 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/9a/cb41da3b683497b3966135ccd64411b8ef698f (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{reflogCommitFiles/expected => reflogCheckout/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/ce/d0c7ee1af3cd078a0bd940fa45e973dfd0f226 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/objects/fd/c461cdae46cbcd0e8b6f33898b25a17ab36f32 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/refs/heads/branch2 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/refs/heads/ma (100%) rename test/integration/reflogCheckout/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/reflogCheckout/expected/{ => repo}/file0 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/file1 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/file2 (100%) rename test/integration/reflogCheckout/expected/{ => repo}/file4 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{searching/expected => reflogCherryPick/expected/repo}/.git_keep/HEAD (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{reflogHardReset/expected => reflogCherryPick/expected/repo}/.git_keep/description (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{reflogHardReset/expected => reflogCherryPick/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/logs/refs/heads/branch2 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 (100%) rename test/integration/{reflogHardReset/expected => reflogCherryPick/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/35/bedc872b1ca9e026e51c4017416acba4b3d64b (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/43/12f3a59c644c52ad89254be43d7a7987e56bed (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/5a/5a519752ffd367bbd85dfbc19e5b18d44d6223 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/71/3ec49844ebad06a5c98fd3c5ce1445f664c3c6 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{reflogHardReset/expected => reflogCherryPick/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/a9/55e641b00e7e896842122a3537c70476d7b4e0 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/ac/7b38400c8aed050f379f9643b953b9d428fda1 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/af/eb127e4579981e4b852e8aabb44b07f2ea4e09 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/bc/8891320172f4cfa3efd7bb8767a46daa200d79 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/e2/3253d1f81331e1c94a5a5f68e2d4cc1cbee2fd (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/refs/heads/branch2 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/file0 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/file1 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/file2 (100%) rename test/integration/reflogCherryPick/expected/{ => repo}/file4 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{rememberCommitMessageAfterFail/expected => reflogCommitFiles/expected/repo}/.git_keep/description (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{searching/expected => reflogCommitFiles/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/logs/refs/heads/branch2 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/07/e795700fa240713f5577867a45eb6f2071d856 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 (100%) rename test/integration/{searching/expected => reflogCommitFiles/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/44/5557afd2775df735bc53b891678e6bd9072638 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/53/26459d9a0c196b18cc31dc95f05c9a4e4462de (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/75/6e436bdd05b965c967edc1929432917e3864cd (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/7d/61d1707885895d92f021111196df4466347327 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/86/3cae3fe21db864bc92b74ae4820e628e5eaf8b (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{searching/expected => reflogCommitFiles/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/a6/cc56fedc3f0fc234dcacef1f1de2706c32c44b (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/b0/bf1c26d59a724c767948a6de15664bfc0c292f (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/c5/4d82926c7b673499d675aec8732cfe08aed761 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/refs/heads/branch2 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/file0 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/file1 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/file2 (100%) rename test/integration/reflogCommitFiles/expected/{ => repo}/file4 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{searching/expected => reflogHardReset/expected/repo}/.git_keep/description (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{searchingInStagingPanel/expected => reflogHardReset/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/logs/refs/heads/branch2 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/16/fc0fdb6ae48d0bdffbfa7013410227e5fac6f3 (100%) rename test/integration/{setUpstream/expected => reflogHardReset/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/18/83828474eb5bac8cb27c8a7a3614f9ea3137a0 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/1f/d818af9eb65653e98def81168002cabc353b6a (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/3e/0b28f0bcdd445c5f6d6b80b7a42f6fa8a536d2 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/49/6408d5ed7b1edff760bf2ce56a43b9fab737e0 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/7c/03a659737f2cc728a2a572cedee98019bbd04b (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/94/0576e482f2193afad72ea2205c05fd01507e1a (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{setUpstream/expected => reflogHardReset/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/refs/heads/branch2 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/reflogHardReset/expected/{ => repo}/file0 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/file1 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/file2 (100%) rename test/integration/reflogHardReset/expected/{ => repo}/file4 (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{searchingInStagingPanel/expected => rememberCommitMessageAfterFail/expected/repo}/.git_keep/HEAD (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{searchingInStagingPanel/expected => rememberCommitMessageAfterFail/expected/repo}/.git_keep/description (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/index (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/objects/6c/493ff740f9380390d5c9ddef4af18697ac9375 (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/objects/ae/ac8b060acee50f309eb1f6698a981c50bdf493 (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/objects/c2/bf9b666a310383fd7095bc5bd993bba11b040e (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/objects/c9/62a96f68e65b4dc8e0fea12db5f9006091efdf (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/objects/d0/ce4cb10cd926f646a08889b077a6d7eddd3534 (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/objects/e2/129701f1a4d54dc44f03c93bca0a2aec7c5449 (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/file1 (100%) rename test/integration/rememberCommitMessageAfterFail/expected/{ => repo}/file2 (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{setUpstream/expected => searching/expected/repo}/.git_keep/HEAD (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{setUpstream/expected => searching/expected/repo}/.git_keep/description (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{setUpstream/expected => searching/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/{setUpstream/expected_remote => searching/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{setUpstream/expected_remote => searching/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{setUpstream/expected_remote => searching/expected/repo/.git_keep}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/objects/33/f3da8081c87015eb5b43b148362af87ce6011c (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/objects/3e/c60bb22aa39d08428e57e3251563f797b40fc8 (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/objects/5f/b9c54526790a11246b733354bf896da8ffc09d (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/objects/6b/94b71598d5aa96357ab261599cfd99a4c2c9d0 (100%) rename test/integration/{setUpstream/expected_remote => searching/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{setUpstream/expected_remote => searching/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/{setUpstream/expected_remote => searching/expected/repo/.git_keep}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{setUpstream/expected_remote => searching/expected/repo/.git_keep}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/objects/f0/5f4d92d7babb2f40ebd2829dccee0afff44c70 (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/objects/fc/759ce6e48e0012eab3f02ec3524a55be938dd5 (100%) rename test/integration/searching/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/{setUpstream/expected => searching/expected/repo}/myfile1 (100%) rename test/integration/searching/expected/{ => repo}/myfile3 (100%) rename test/integration/searching/expected/{ => repo}/myfile4 (100%) rename test/integration/searching/expected/{ => repo}/myfile5 (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{setUpstream/expected_remote => searchingInStagingPanel/expected/repo/.git_keep}/HEAD (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{setUpstream/expected_remote => searchingInStagingPanel/expected/repo/.git_keep}/description (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{setUpstream/expected_remote => searchingInStagingPanel/expected/repo/.git_keep}/info/exclude (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/objects/16/4d8eaeabbb4b1082fdfb6735be0134535340b2 (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/objects/36/4e6307f708c6f17d83c7309aaf9a3034210236 (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/objects/4e/a1f9142dd3ced7ae2180752f770ce203fb8ac3 (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/objects/70/dcf03faa734af0278690e1b0f8e767b733d88a (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/objects/88/4971c742724377080ba3d75d4b4d6bceee4e4b (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/objects/89/b24ecec50c07aef0d6640a2a9f6dc354a33125 (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/objects/9c/2a7090627d0fffa9ed001bf7be98f86c2c8068 (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/objects/a9/2d664bc20a04b1621b1fc893d1196b41182fdf (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/objects/cb/f7f40f0ffe31d36ddc23bc6ce251c66f6f4e87 (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/searchingInStagingPanel/expected/{ => repo}/myfile1 (100%) delete mode 100644 test/integration/setUpstream/expected/.git_keep/FETCH_HEAD delete mode 100644 test/integration/setUpstream/expected/.git_keep/ORIG_HEAD delete mode 100644 test/integration/setUpstream/expected/.git_keep/config delete mode 100644 test/integration/setUpstream/expected/.git_keep/index delete mode 100644 test/integration/setUpstream/expected/.git_keep/logs/HEAD delete mode 100644 test/integration/setUpstream/expected/.git_keep/logs/refs/heads/master delete mode 100644 test/integration/setUpstream/expected/.git_keep/logs/refs/remotes/origin/master delete mode 100644 test/integration/setUpstream/expected/.git_keep/objects/05/8c8904c25889dd77ee3e817325fd1a28134037 delete mode 100644 test/integration/setUpstream/expected/.git_keep/objects/14/8a38f7ce513079d6cd40e4a02f11e46ea2ba6b delete mode 100644 test/integration/setUpstream/expected/.git_keep/objects/40/9dd039b9ec270067678ae23b710c8e4c49c458 delete mode 100644 test/integration/setUpstream/expected/.git_keep/objects/7d/7da1f440cca8d28eaf4b46e63f207993562b84 delete mode 100644 test/integration/setUpstream/expected/.git_keep/refs/heads/master delete mode 100644 test/integration/setUpstream/expected/.git_keep/refs/remotes/origin/master rename test/integration/{squash/expected/.git_keep => setUpstream/expected/origin}/HEAD (100%) create mode 100644 test/integration/setUpstream/expected/origin/config rename test/integration/{squash/expected/.git_keep => setUpstream/expected/origin}/description (100%) rename test/integration/{squash/expected/.git_keep => setUpstream/expected/origin}/info/exclude (100%) rename test/integration/{squash/expected/.git_keep => setUpstream/expected/origin}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{squash/expected/.git_keep => setUpstream/expected/origin}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{squash/expected/.git_keep => setUpstream/expected/origin}/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce (100%) rename test/integration/setUpstream/expected/{.git_keep => origin}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/setUpstream/expected/origin/objects/30/ef3df33d31f0b98298881be4dbe69c54758ba2 create mode 100644 test/integration/setUpstream/expected/origin/objects/63/05259d1908bee46b3b686702ed55b6f12e9ba2 create mode 100644 test/integration/setUpstream/expected/origin/objects/a2/6a9d22097eb77a8cf2fbb18512aa44c0c536a2 rename test/integration/{squash/expected/.git_keep => setUpstream/expected/origin}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{squash/expected/.git_keep => setUpstream/expected/origin}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/setUpstream/expected/origin/objects/c6/ffcbed8902934d462722ff6ef471813b9a4df5 rename test/integration/{squash/expected/.git_keep => setUpstream/expected/origin}/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 (100%) rename test/integration/{squash/expected/.git_keep => setUpstream/expected/origin}/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/setUpstream/expected/origin/packed-refs create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/COMMIT_EDITMSG create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/FETCH_HEAD rename test/integration/{staginWithDiffContextChange/expected => setUpstream/expected/repo}/.git_keep/HEAD (100%) create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/ORIG_HEAD create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/config rename test/integration/{staginWithDiffContextChange/expected => setUpstream/expected/repo}/.git_keep/description (100%) create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/index rename test/integration/{staginWithDiffContextChange/expected => setUpstream/expected/repo}/.git_keep/info/exclude (100%) create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/logs/refs/remotes/origin/master rename test/integration/{submoduleAdd/expected/.git_keep/modules/blah => setUpstream/expected/repo/.git_keep}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{stash/expected => setUpstream/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce rename test/integration/setUpstream/{expected_remote => expected/repo/.git_keep}/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/objects/30/ef3df33d31f0b98298881be4dbe69c54758ba2 create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/objects/63/05259d1908bee46b3b686702ed55b6f12e9ba2 create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/objects/a2/6a9d22097eb77a8cf2fbb18512aa44c0c536a2 rename test/integration/{stash/expected => setUpstream/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{submoduleAdd/expected/.git_keep/modules/blah => setUpstream/expected/repo/.git_keep}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/objects/c6/ffcbed8902934d462722ff6ef471813b9a4df5 create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename test/integration/{tags2/expected => setUpstream/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/setUpstream/expected/repo/.git_keep/refs/remotes/origin/master rename test/integration/{squash/expected => setUpstream/expected/repo}/myfile1 (100%) rename test/integration/{squash/expected => setUpstream/expected/repo}/myfile2 (100%) rename test/integration/setUpstream/expected/{ => repo}/myfile3 (100%) rename test/integration/setUpstream/expected/{ => repo}/myfile4 (100%) delete mode 100644 test/integration/setUpstream/expected_remote/config delete mode 100644 test/integration/setUpstream/expected_remote/objects/05/8c8904c25889dd77ee3e817325fd1a28134037 delete mode 100644 test/integration/setUpstream/expected_remote/objects/14/8a38f7ce513079d6cd40e4a02f11e46ea2ba6b delete mode 100644 test/integration/setUpstream/expected_remote/objects/40/9dd039b9ec270067678ae23b710c8e4c49c458 delete mode 100644 test/integration/setUpstream/expected_remote/objects/7d/7da1f440cca8d28eaf4b46e63f207993562b84 delete mode 100644 test/integration/setUpstream/expected_remote/packed-refs rename test/integration/squash/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{staging/expected => squash/expected/repo}/.git_keep/HEAD (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{staging/expected => squash/expected/repo}/.git_keep/description (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{staging/expected => squash/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/objects/07/5bd21694c75fd12e11cbd487eb64d831362e8c (100%) rename test/integration/{submoduleAdd/expected => squash/expected/repo}/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{stashDrop/expected => squash/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/objects/1b/838df93e188ddacfce91d03dfcf1386ca57714 (100%) create mode 100644 test/integration/squash/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce rename test/integration/squash/expected/{ => repo}/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/objects/3c/752371dc0c58af7ff63f7a6c252da9f4d96251 (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/objects/88/fb48b35f6ece4da3ad62dd3426bca0240d63a5 (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/objects/9f/83377e9068d956fe3085934bb32ce22aeb4bf7 (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/objects/a1/cf7798606057d592f8ef1bee884165b6f629f1 (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/objects/a5/9b3d4800dcbf39ab31887402dc178e7b7f82a5 (100%) rename test/integration/{stashDrop/expected => squash/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{submoduleAdd/expected => squash/expected/repo}/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/objects/c5/9791a0d43d3e0a7ed0a40a62b7929acf675bf0 (100%) create mode 100644 test/integration/squash/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename test/integration/{tags3/expected => squash/expected/repo}/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b (100%) rename test/integration/squash/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/{submoduleAdd/expected/haha => squash/expected/repo}/myfile1 (100%) rename test/integration/{submoduleAdd/expected/haha => squash/expected/repo}/myfile2 (100%) rename test/integration/squash/expected/{ => repo}/myfile3 (100%) rename test/integration/squash/expected/{ => repo}/myfile5 (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{stagingTwo/expected => staginWithDiffContextChange/expected/repo}/.git_keep/HEAD (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{stagingTwo/expected => staginWithDiffContextChange/expected/repo}/.git_keep/description (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{stagingTwo/expected => staginWithDiffContextChange/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/.git_keep/objects/15/8e9a9c1a9627ea0ef4de8b00a503ed0f80a09e (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/.git_keep/objects/18/54ab416d299cda0227d62b9ab0765e5551ef57 (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/.git_keep/objects/2c/484c0a45f3726375600319f73978221a74b783 (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/.git_keep/objects/7b/9c2149f16c706cea79b03234cb67fde7e9b68f (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/.git_keep/objects/8a/af931e5367e5af9d2e2c014800d22190352b14 (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/.git_keep/objects/fd/c28832bb15c80146150a24a018088c9df4f8cd (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/staginWithDiffContextChange/expected/{ => repo}/one.txt (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{stash/expected => staging/expected/repo}/.git_keep/HEAD (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{stash/expected => staging/expected/repo}/.git_keep/description (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{stash/expected => staging/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/05/9586b468b89bf98e3b62126f455ab15bea4a5f (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/0b/6860367a6e7794985007cadf0aaf04c801e59e (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/12/c4186053ecd4056526743060a8fe87429b7306 (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/3e/95c983db9349a26b20fccbdaa933e805ff817e (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/40/ce5b93f72e04cb876afaaf91398c2821260b95 (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/63/5b45efaba0c2415658bc121de201ec43a47920 (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/6f/7e9e66f080162af7ebab016d02550145cfda66 (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/79/8369253f104fe8cdc91db6f7d3525be532218e (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/a0/425534134de68284a0a7250b83b0e6303f0ed7 (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/a4/7182dc057408b3c6b1749cb46db0e0c5fd626b (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/a4/8a7caa799e7859b8f21d373e3f01b06002d42f (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/b6/77e3e5777e122a22ebb001532c5017b199b0c0 (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/dc/02541428fdc15b30bd2174fcbcd43d388eab82 (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/e8/aaa2f356eb341c693e239467fd200d0117b487 (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/objects/fb/e09a11933b44ea60b46bd0f3d44142cb6189a4 (100%) rename test/integration/staging/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/staging/expected/{ => repo}/one.txt (100%) rename test/integration/staging/expected/{ => repo}/three.txt (100%) rename test/integration/staging/expected/{ => repo}/two.txt (100%) rename test/integration/stagingTwo/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/stagingTwo/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{stashDrop/expected => stagingTwo/expected/repo}/.git_keep/HEAD (100%) rename test/integration/stagingTwo/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{stashDrop/expected => stagingTwo/expected/repo}/.git_keep/description (100%) rename test/integration/stagingTwo/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{stashDrop/expected => stagingTwo/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/stagingTwo/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/stagingTwo/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/stagingTwo/expected/{ => repo}/.git_keep/objects/15/8e9a9c1a9627ea0ef4de8b00a503ed0f80a09e (100%) rename test/integration/stagingTwo/expected/{ => repo}/.git_keep/objects/7b/9c2149f16c706cea79b03234cb67fde7e9b68f (100%) rename test/integration/stagingTwo/expected/{ => repo}/.git_keep/objects/f7/93cf3fd99464dbd3499093e95197229b771b11 (100%) rename test/integration/stagingTwo/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/stagingTwo/expected/{ => repo}/one.txt (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{stashPop/expected => stash/expected/repo}/.git_keep/HEAD (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{stashNewBranch/expected => stash/expected/repo}/.git_keep/description (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{stashNewBranch/expected => stash/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/logs/refs/stash (100%) rename test/integration/{stashNewBranch/expected => stash/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/25/abc3e66a6aa505fb0a2ceb6ad5cda0cc89ecbc (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/2e/fac8148440778cbddcd80ac7477981277dcffe (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/3b/29b35d4357f8e64cafd95140a70d7c9b25138a (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/4c/c838ea1466afc5be1d3bc3e7a937641ec84d7d (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/56/52247b638d1516506790d6648b864ba3447f68 (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/5c/ef9afea6a37d89f925e24ebf71adecb63d1f07 (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/66/bbc809cdafd867cf9320bfb7484bb8fa898448 (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/9f/2757166809c291c65f09778abb46cfcc4e4a0c (100%) rename test/integration/{stashNewBranch/expected => stash/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/a6/ada9f3d895e751ec289c69913a02146c0ca844 (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/a7/dde526f2e93ffa08897fbfca2c98ce40a8fa5b (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/c7/c7da3c64e86c3270f2639a1379e67e14891b6a (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/e0/9b4dfcd66bfa1c81feeaf67e04d55368a2b065 (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/objects/f3/48ff60bdbb3695f2f519db6bc115b1b8d50886 (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/stash/expected/{ => repo}/.git_keep/refs/stash (100%) rename test/integration/stash/expected/{ => repo}/file0 (100%) rename test/integration/stash/expected/{ => repo}/file1 (100%) rename test/integration/stash/expected/{ => repo}/file2 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{stash_Copy/expected => stashDrop/expected/repo}/.git_keep/HEAD (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{stashPop/expected => stashDrop/expected/repo}/.git_keep/description (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{stashPop/expected => stashDrop/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/logs/refs/stash (100%) rename test/integration/{stashPop/expected => stashDrop/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/1e/6f4a55f3dd26848238337763f249681ef9397b (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/56/52247b638d1516506790d6648b864ba3447f68 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/5c/ef9afea6a37d89f925e24ebf71adecb63d1f07 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/66/bbc809cdafd867cf9320bfb7484bb8fa898448 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/6d/c07da80aed51d01a56a89ef37f4411adbd75c5 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/76/05fecac5dee01fb9df55ca984dcc7a72810f48 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/9f/2757166809c291c65f09778abb46cfcc4e4a0c (100%) rename test/integration/{stashPop/expected => stashDrop/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/a6/ed180e13649885eed39866051ca0e25c0ad6ac (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/c0/0c9eb1ae239494475772c3f3dbae5ea4169575 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/c7/c7da3c64e86c3270f2639a1379e67e14891b6a (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/d2/2496528fe3c076a668c496ae7ba1f8136f1614 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/e0/61c8716830532562f919dcb125ea804f87ca2b (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/e5/cef1a548f3613b3e538bd0fc2b4ec88043fc25 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/objects/f4/f81b6542e98a2f80269449674b0f8f454b74b0 (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/stashDrop/expected/{ => repo}/.git_keep/refs/stash (100%) rename test/integration/stashDrop/expected/{ => repo}/file0 (100%) rename test/integration/stashDrop/expected/{ => repo}/file1 (100%) rename test/integration/stashDrop/expected/{ => repo}/file2 (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{stash_Copy/expected => stashNewBranch/expected/repo}/.git_keep/description (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{stash_Copy/expected => stashNewBranch/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/logs/refs/heads/hello (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/logs/refs/stash (100%) rename test/integration/{stash_Copy/expected => stashNewBranch/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/objects/28/59c9a5f343c80929844d6e49d3792b9169c4da (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/objects/2a/b31642272ef6607700326d4ddb78f35e609d2b (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/objects/5b/9d4ea51af3db649ff3ae4d92b9eacb84218368 (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/objects/71/890c9b458697fbb4a6a9dde41614bea569aac8 (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/objects/79/7c030ec107d77fa39a1e453ad620235cb26725 (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{stash_Copy/expected => stashNewBranch/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/objects/ac/b6fb50a77cf7bb6fb9cd5e45bc98010012d7c6 (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/objects/c7/c7da3c64e86c3270f2639a1379e67e14891b6a (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/refs/heads/hello (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/stashNewBranch/expected/{ => repo}/.git_keep/refs/stash (100%) rename test/integration/stashNewBranch/expected/{ => repo}/file0 (100%) rename test/integration/stashNewBranch/expected/{ => repo}/file1 (100%) rename test/integration/stashNewBranch/expected/{ => repo}/file2 (100%) rename test/integration/stashNewBranch/expected/{ => repo}/file3 (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{submoduleAdd/expected => stashPop/expected/repo}/.git_keep/HEAD (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{submoduleAdd/expected => stashPop/expected/repo}/.git_keep/description (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{submoduleAdd/expected => stashPop/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/logs/refs/stash (100%) rename test/integration/{submoduleAdd/expected/.git_keep/modules/blah => stashPop/expected/repo/.git_keep}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/3a/e4e5d4920afbb1bac23426afb237524c8dbe41 (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/43/7b9b0ca941f1e12c8b45958f5d6ebd11cdd41a (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/5c/ef9afea6a37d89f925e24ebf71adecb63d1f07 (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/66/bbc809cdafd867cf9320bfb7484bb8fa898448 (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/82/cc524693ae9fb40af0ed8ab7e22581084dcd17 (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/86/34432ef171aa4b8d8e688fc1e5645245bf36ac (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/8b/081dcb0e1fd5e9862d1aa6891b805b101abe7b (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/8b/d86c566a91e9f8ace9883f7017f562c971b3f7 (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/8e/b0f6c64dea2004a684ea55f9589b71b45d76a6 (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/{submoduleAdd/expected/.git_keep/modules/blah => stashPop/expected/repo/.git_keep}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/b0/00623a052b4d2226c43ba396b830738799740e (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/c6/a8d49b926afc9ff2b4c64398ee678c50c2c953 (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/c7/c7da3c64e86c3270f2639a1379e67e14891b6a (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/objects/e0/0e994a4acb98bcbe93ad478e09dcb3bed6b26c (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/stashPop/expected/{ => repo}/.git_keep/refs/stash (100%) rename test/integration/stashPop/expected/{ => repo}/file0 (100%) rename test/integration/stashPop/expected/{ => repo}/file1 (100%) rename test/integration/stashPop/expected/{ => repo}/file2 (100%) rename test/integration/stashPop/expected/{ => repo}/file3 (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{submoduleAdd/expected/.git_keep/modules/blah => stash_Copy/expected/repo/.git_keep}/HEAD (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{submoduleAdd/expected/.git_keep/modules/blah => stash_Copy/expected/repo/.git_keep}/description (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/index (100%) rename test/integration/{submoduleAdd/expected/.git_keep/modules/blah => stash_Copy/expected/repo/.git_keep}/info/exclude (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/logs/refs/stash (100%) rename test/integration/{submoduleAdd/expected => stash_Copy/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/25/abc3e66a6aa505fb0a2ceb6ad5cda0cc89ecbc (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/2e/fac8148440778cbddcd80ac7477981277dcffe (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/3b/29b35d4357f8e64cafd95140a70d7c9b25138a (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/4c/c838ea1466afc5be1d3bc3e7a937641ec84d7d (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/56/52247b638d1516506790d6648b864ba3447f68 (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/5c/ef9afea6a37d89f925e24ebf71adecb63d1f07 (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/66/bbc809cdafd867cf9320bfb7484bb8fa898448 (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/9f/2757166809c291c65f09778abb46cfcc4e4a0c (100%) rename test/integration/{submoduleAdd/expected => stash_Copy/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/a6/ada9f3d895e751ec289c69913a02146c0ca844 (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/a7/dde526f2e93ffa08897fbfca2c98ce40a8fa5b (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/c7/c7da3c64e86c3270f2639a1379e67e14891b6a (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/e0/9b4dfcd66bfa1c81feeaf67e04d55368a2b065 (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/objects/f3/48ff60bdbb3695f2f519db6bc115b1b8d50886 (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/stash_Copy/expected/{ => repo}/.git_keep/refs/stash (100%) rename test/integration/stash_Copy/expected/{ => repo}/file0 (100%) rename test/integration/stash_Copy/expected/{ => repo}/file1 (100%) rename test/integration/stash_Copy/expected/{ => repo}/file2 (100%) delete mode 100644 test/integration/submoduleAdd/expected/.git_keep/index delete mode 100644 test/integration/submoduleAdd/expected/.git_keep/modules/blah/index delete mode 100644 test/integration/submoduleAdd/expected/.git_keep/modules/blah/logs/HEAD delete mode 100644 test/integration/submoduleAdd/expected/.git_keep/modules/blah/logs/refs/heads/master delete mode 100644 test/integration/submoduleAdd/expected/.git_keep/modules/blah/logs/refs/remotes/origin/HEAD delete mode 100644 test/integration/submoduleAdd/expected/.git_keep/objects/6d/e70e35394a99cc437d1bc70b0852b70c5bb03d delete mode 100644 test/integration/submoduleAdd/expected/.git_keep/refs/heads/master rename test/integration/{submoduleEnter/expected/.git_keep => submoduleAdd/expected/other_repo}/HEAD (100%) rename test/integration/{forcePushMultiple/expected_remote => submoduleAdd/expected/other_repo}/config (77%) rename test/integration/{submoduleEnter/expected/.git_keep => submoduleAdd/expected/other_repo}/description (100%) rename test/integration/{submoduleEnter/expected/.git_keep => submoduleAdd/expected/other_repo}/info/exclude (100%) rename test/integration/{submoduleEnter/expected/.git_keep/modules => submoduleAdd/expected}/other_repo/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{submoduleEnter/expected/.git_keep/modules => submoduleAdd/expected}/other_repo/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/submoduleAdd/expected/{.git_keep/modules/blah => other_repo}/objects/42/530e986dbb65877ed8d61ca0c816e425e5c62e (100%) rename test/integration/submoduleAdd/expected/{.git_keep/modules/blah => other_repo}/objects/a5/0a5125768001a3ea263ffb7cafbc421a508153 (100%) rename test/integration/{submoduleEnter/expected/.git_keep/modules => submoduleAdd/expected}/other_repo/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{submoduleEnter/expected/.git_keep/modules => submoduleAdd/expected}/other_repo/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) create mode 100644 test/integration/submoduleAdd/expected/other_repo/packed-refs rename test/integration/submoduleAdd/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/submoduleAdd/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{submoduleEnter/expected/.git_keep/modules/other_repo => submoduleAdd/expected/repo/.git_keep}/HEAD (100%) rename test/integration/submoduleAdd/expected/{ => repo}/.git_keep/config (82%) rename test/integration/{submoduleEnter/expected/.git_keep/modules/other_repo => submoduleAdd/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/submoduleAdd/expected/repo/.git_keep/index rename test/integration/{submoduleEnter/expected/.git_keep/modules/other_repo => submoduleAdd/expected/repo/.git_keep}/info/exclude (100%) rename test/integration/submoduleAdd/expected/{ => repo}/.git_keep/logs/HEAD (68%) rename test/integration/submoduleAdd/expected/{ => repo}/.git_keep/logs/refs/heads/master (68%) rename test/integration/{submoduleRemove/expected/.git_keep => submoduleAdd/expected/repo/.git_keep/modules/blah}/HEAD (100%) rename test/integration/submoduleAdd/expected/{ => repo}/.git_keep/modules/blah/config (85%) rename test/integration/{submoduleRemove/expected/.git_keep => submoduleAdd/expected/repo/.git_keep/modules/blah}/description (100%) create mode 100644 test/integration/submoduleAdd/expected/repo/.git_keep/modules/blah/index rename test/integration/{submoduleRemove/expected/.git_keep => submoduleAdd/expected/repo/.git_keep/modules/blah}/info/exclude (100%) create mode 100644 test/integration/submoduleAdd/expected/repo/.git_keep/modules/blah/logs/HEAD create mode 100644 test/integration/submoduleAdd/expected/repo/.git_keep/modules/blah/logs/refs/heads/master create mode 100644 test/integration/submoduleAdd/expected/repo/.git_keep/modules/blah/logs/refs/remotes/origin/HEAD rename test/integration/{submoduleEnter/expected/.git_keep => submoduleAdd/expected/repo/.git_keep/modules/blah}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{submoduleEnter/expected/.git_keep => submoduleAdd/expected/repo/.git_keep/modules/blah}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/submoduleAdd/expected/{.git_keep => repo/.git_keep/modules/blah}/objects/42/530e986dbb65877ed8d61ca0c816e425e5c62e (100%) rename test/integration/submoduleAdd/expected/{.git_keep => repo/.git_keep/modules/blah}/objects/a5/0a5125768001a3ea263ffb7cafbc421a508153 (100%) rename test/integration/{submoduleEnter/expected/.git_keep => submoduleAdd/expected/repo/.git_keep/modules/blah}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{submoduleEnter/expected/.git_keep => submoduleAdd/expected/repo/.git_keep/modules/blah}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/submoduleAdd/expected/{ => repo}/.git_keep/modules/blah/packed-refs (100%) rename test/integration/submoduleAdd/expected/{ => repo}/.git_keep/modules/blah/refs/heads/master (100%) rename test/integration/submoduleAdd/expected/{ => repo}/.git_keep/modules/blah/refs/remotes/origin/HEAD (100%) rename test/integration/{submoduleRemove/expected => submoduleAdd/expected/repo}/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{submoduleRemove/expected => submoduleAdd/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{submoduleEnter/expected/.git_keep/modules/other_repo => submoduleAdd/expected/repo/.git_keep}/objects/42/530e986dbb65877ed8d61ca0c816e425e5c62e (100%) rename test/integration/submoduleAdd/expected/{ => repo}/.git_keep/objects/5f/77fb3622a1035782a7dacc0cca12e674066b9e (100%) rename test/integration/{submoduleEnter/expected/.git_keep/modules/other_repo => submoduleAdd/expected/repo/.git_keep}/objects/a5/0a5125768001a3ea263ffb7cafbc421a508153 (100%) rename test/integration/{submoduleRemove/expected => submoduleAdd/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{submoduleRemove/expected => submoduleAdd/expected/repo}/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/submoduleAdd/expected/{ => repo}/.git_keep/objects/b9/7660affc790464b00ad45c7186a882238d77fb (100%) create mode 100644 test/integration/submoduleAdd/expected/repo/.git_keep/objects/dc/5bde4a09968b0819f34d193f6780df295d71cf create mode 100644 test/integration/submoduleAdd/expected/repo/.git_keep/refs/heads/master rename test/integration/submoduleAdd/expected/{ => repo}/.gitmodules_keep (100%) rename test/integration/submoduleAdd/expected/{ => repo}/haha/.git_keep (100%) rename test/integration/submoduleAdd/expected/{ => repo/haha}/myfile1 (100%) rename test/integration/submoduleAdd/expected/{ => repo/haha}/myfile2 (100%) rename test/integration/{submoduleEnter/expected => submoduleAdd/expected/repo}/myfile1 (100%) rename test/integration/{submoduleEnter/expected => submoduleAdd/expected/repo}/myfile2 (100%) delete mode 100644 test/integration/submoduleEnter/expected/.git_keep/index delete mode 100644 test/integration/submoduleEnter/expected/.git_keep/modules/other_repo/index delete mode 100644 test/integration/submoduleEnter/expected/.git_keep/modules/other_repo/logs/HEAD delete mode 100644 test/integration/submoduleEnter/expected/.git_keep/objects/c8/3cc777cf98a8c0f3c0995d7c1b21db92a71c66 delete mode 100644 test/integration/submoduleEnter/expected/.git_keep/refs/heads/master rename test/integration/{submoduleReset/expected/.git_keep => submoduleEnter/expected/other_repo}/HEAD (100%) create mode 100644 test/integration/submoduleEnter/expected/other_repo/config rename test/integration/{submoduleReset/expected/.git_keep => submoduleEnter/expected/other_repo}/description (100%) rename test/integration/{submoduleReset/expected/.git_keep => submoduleEnter/expected/other_repo}/info/exclude (100%) rename test/integration/{submoduleReset/expected/.git_keep/modules => submoduleEnter/expected}/other_repo/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{submoduleReset/expected/.git_keep/modules => submoduleEnter/expected}/other_repo/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/submoduleEnter/expected/{.git_keep => other_repo}/objects/42/530e986dbb65877ed8d61ca0c816e425e5c62e (100%) rename test/integration/submoduleEnter/expected/{.git_keep/modules => }/other_repo/objects/96/c588f28aac5a8ebd6430526697e82e46b3180c (100%) rename test/integration/submoduleEnter/expected/{.git_keep => other_repo}/objects/a5/0a5125768001a3ea263ffb7cafbc421a508153 (100%) rename test/integration/{submoduleReset/expected/.git_keep/modules => submoduleEnter/expected}/other_repo/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{submoduleReset/expected/.git_keep/modules => submoduleEnter/expected}/other_repo/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/submoduleEnter/expected/{.git_keep/modules => }/other_repo/objects/fc/4712e93d74ad4fb68e2fd219ac253ae03e19a4 (100%) create mode 100644 test/integration/submoduleEnter/expected/other_repo/packed-refs rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/{tags/expected => submoduleEnter/expected/repo}/.git_keep/HEAD (100%) rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/config (82%) rename test/integration/{submoduleReset/expected/.git_keep/modules/other_repo => submoduleEnter/expected/repo/.git_keep}/description (100%) create mode 100644 test/integration/submoduleEnter/expected/repo/.git_keep/index rename test/integration/{submoduleReset/expected/.git_keep/modules/other_repo => submoduleEnter/expected/repo/.git_keep}/info/exclude (100%) rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/logs/HEAD (81%) rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/logs/refs/heads/master (81%) rename test/integration/{tags4/expected/.git_keep => submoduleEnter/expected/repo/.git_keep/modules/other_repo}/HEAD (100%) rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/modules/other_repo/ORIG_HEAD (100%) rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/modules/other_repo/config (85%) rename test/integration/{switchTabFromMenu/expected/.git_keep => submoduleEnter/expected/repo/.git_keep/modules/other_repo}/description (100%) create mode 100644 test/integration/submoduleEnter/expected/repo/.git_keep/modules/other_repo/index rename test/integration/{tags/expected/.git_keep => submoduleEnter/expected/repo/.git_keep/modules/other_repo}/info/exclude (100%) create mode 100644 test/integration/submoduleEnter/expected/repo/.git_keep/modules/other_repo/logs/HEAD rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/modules/other_repo/logs/refs/heads/master (53%) rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/modules/other_repo/logs/refs/remotes/origin/HEAD (70%) rename test/integration/{submoduleReset/expected/.git_keep => submoduleEnter/expected/repo/.git_keep/modules/other_repo}/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 (100%) rename test/integration/{submoduleReset/expected/.git_keep => submoduleEnter/expected/repo/.git_keep/modules/other_repo}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{submoduleRemove/expected/.git_keep => submoduleEnter/expected/repo/.git_keep/modules/other_repo}/objects/42/530e986dbb65877ed8d61ca0c816e425e5c62e (100%) rename test/integration/submoduleEnter/expected/{.git_keep => repo/.git_keep/modules/other_repo}/objects/96/c588f28aac5a8ebd6430526697e82e46b3180c (100%) rename test/integration/{submoduleRemove/expected/.git_keep => submoduleEnter/expected/repo/.git_keep/modules/other_repo}/objects/a5/0a5125768001a3ea263ffb7cafbc421a508153 (100%) rename test/integration/{submoduleReset/expected/.git_keep => submoduleEnter/expected/repo/.git_keep/modules/other_repo}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) rename test/integration/{submoduleReset/expected/.git_keep => submoduleEnter/expected/repo/.git_keep/modules/other_repo}/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 (100%) rename test/integration/submoduleEnter/expected/{.git_keep => repo/.git_keep/modules/other_repo}/objects/fc/4712e93d74ad4fb68e2fd219ac253ae03e19a4 (100%) rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/modules/other_repo/packed-refs (100%) rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/modules/other_repo/refs/heads/master (100%) rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/modules/other_repo/refs/remotes/origin/HEAD (100%) create mode 100644 test/integration/submoduleEnter/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/objects/10/7f435787895be1068f01326df55c355a9d29b1 (100%) rename test/integration/{tags2/expected => submoduleEnter/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/objects/2b/864257bf2d49adbad8785540d85030a60852ff (100%) rename test/integration/{submoduleReset/expected/.git_keep/modules/other_repo => submoduleEnter/expected/repo/.git_keep}/objects/42/530e986dbb65877ed8d61ca0c816e425e5c62e (100%) rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/objects/59/a9aee220657762e2d1c60799a0f5b03137d906 (100%) create mode 100644 test/integration/submoduleEnter/expected/repo/.git_keep/objects/96/c588f28aac5a8ebd6430526697e82e46b3180c rename test/integration/{submoduleReset/expected/.git_keep/modules/other_repo => submoduleEnter/expected/repo/.git_keep}/objects/a5/0a5125768001a3ea263ffb7cafbc421a508153 (100%) rename test/integration/{tags/expected => submoduleEnter/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) create mode 100644 test/integration/submoduleEnter/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 rename test/integration/submoduleEnter/expected/{ => repo}/.git_keep/objects/e1/eb418c0ff98940d4ea817eebcff5dcdde645ce (100%) create mode 100644 test/integration/submoduleEnter/expected/repo/.git_keep/objects/fc/4712e93d74ad4fb68e2fd219ac253ae03e19a4 create mode 100644 test/integration/submoduleEnter/expected/repo/.git_keep/objects/fd/65a5c96edfc884a78bfe3d0240cb8a7ea0a31a create mode 100644 test/integration/submoduleEnter/expected/repo/.git_keep/refs/heads/master rename test/integration/submoduleEnter/expected/{ => repo}/.gitmodules_keep (100%) rename test/integration/submoduleEnter/expected/{other_repo => repo}/myfile1 (100%) rename test/integration/{submoduleRemove/expected => submoduleEnter/expected/repo}/myfile2 (100%) rename test/integration/submoduleEnter/expected/{ => repo}/myfile3 (100%) rename test/integration/submoduleEnter/expected/{ => repo}/other_repo/.git_keep (100%) rename test/integration/{submoduleRemove/expected => submoduleEnter/expected/repo/other_repo}/myfile1 (100%) delete mode 100644 test/integration/submoduleRemove/expected/.git_keep/index delete mode 100644 test/integration/submoduleRemove/expected/.git_keep/objects/40/f121d7563ed318d461996b8d84e2ec8632687e delete mode 100644 test/integration/submoduleRemove/expected/.git_keep/refs/heads/master rename test/integration/{undo2/expected/.git_keep => submoduleRemove/expected/other_repo}/HEAD (100%) create mode 100644 test/integration/submoduleRemove/expected/other_repo/config rename test/integration/{tags/expected/.git_keep => submoduleRemove/expected/other_repo}/description (100%) rename test/integration/{tags2/expected/.git_keep => submoduleRemove/expected/other_repo}/info/exclude (100%) create mode 100644 test/integration/submoduleRemove/expected/other_repo/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename test/integration/{tags3/expected/.git_keep => submoduleRemove/expected/other_repo}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/{submoduleReset/expected/.git_keep => submoduleRemove/expected/other_repo}/objects/42/530e986dbb65877ed8d61ca0c816e425e5c62e (100%) rename test/integration/{submoduleReset/expected/.git_keep => submoduleRemove/expected/other_repo}/objects/a5/0a5125768001a3ea263ffb7cafbc421a508153 (100%) rename test/integration/{tags2/expected/.git_keep => submoduleRemove/expected/other_repo}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) create mode 100644 test/integration/submoduleRemove/expected/other_repo/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 create mode 100644 test/integration/submoduleRemove/expected/other_repo/packed-refs rename test/integration/submoduleRemove/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/submoduleRemove/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) create mode 100644 test/integration/submoduleRemove/expected/repo/.git_keep/HEAD rename test/integration/submoduleRemove/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{tags2/expected => submoduleRemove/expected/repo}/.git_keep/description (100%) create mode 100644 test/integration/submoduleRemove/expected/repo/.git_keep/index rename test/integration/{tags3/expected => submoduleRemove/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/submoduleRemove/expected/{ => repo}/.git_keep/logs/HEAD (77%) rename test/integration/submoduleRemove/expected/{ => repo}/.git_keep/logs/refs/heads/master (77%) create mode 100644 test/integration/submoduleRemove/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename test/integration/{undo/expected => submoduleRemove/expected/repo}/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) rename test/integration/submoduleRemove/expected/{ => repo}/.git_keep/objects/2b/864257bf2d49adbad8785540d85030a60852ff (100%) rename test/integration/submoduleRemove/expected/{ => repo}/.git_keep/objects/2e/eb2c1e6451d1318b506eecddf936b59a5f32b8 (100%) create mode 100644 test/integration/submoduleRemove/expected/repo/.git_keep/objects/42/530e986dbb65877ed8d61ca0c816e425e5c62e create mode 100644 test/integration/submoduleRemove/expected/repo/.git_keep/objects/61/1cac756ef1944ab56d12f4ea3ae4623724c8cf rename test/integration/submoduleRemove/expected/{ => repo}/.git_keep/objects/9d/10a5a0a21eb2cfdb6206f474ed57fd5cd51440 (100%) create mode 100644 test/integration/submoduleRemove/expected/repo/.git_keep/objects/a5/0a5125768001a3ea263ffb7cafbc421a508153 rename test/integration/{tags3/expected => submoduleRemove/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) create mode 100644 test/integration/submoduleRemove/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 rename test/integration/submoduleRemove/expected/{ => repo}/.git_keep/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 (100%) rename test/integration/submoduleRemove/expected/{ => repo}/.git_keep/objects/f1/43043bb53b17b5727a43b6cfbb1a8d1f5a222d (100%) create mode 100644 test/integration/submoduleRemove/expected/repo/.git_keep/refs/heads/master rename test/integration/submoduleRemove/expected/{ => repo}/.gitmodules_keep (100%) rename test/integration/{submoduleReset/expected => submoduleRemove/expected/repo}/myfile1 (100%) rename test/integration/{submoduleReset/expected => submoduleRemove/expected/repo}/myfile2 (100%) delete mode 100644 test/integration/submoduleReset/expected/.git_keep/index delete mode 100644 test/integration/submoduleReset/expected/.git_keep/modules/other_repo/index delete mode 100644 test/integration/submoduleReset/expected/.git_keep/modules/other_repo/logs/HEAD delete mode 100644 test/integration/submoduleReset/expected/.git_keep/modules/other_repo/logs/refs/stash delete mode 100644 test/integration/submoduleReset/expected/.git_keep/modules/other_repo/objects/84/69b6d9b0a33be075f9e0df61c5a3ebba3ecfd2 delete mode 100644 test/integration/submoduleReset/expected/.git_keep/modules/other_repo/objects/9d/13001fc1d98cd178f9e604f6f2c2e52794079e delete mode 100644 test/integration/submoduleReset/expected/.git_keep/modules/other_repo/objects/f3/5aba17e85e3fe18f7b01c0f65306c9289c482e delete mode 100644 test/integration/submoduleReset/expected/.git_keep/modules/other_repo/refs/stash create mode 100644 test/integration/submoduleReset/expected/other_repo/HEAD create mode 100644 test/integration/submoduleReset/expected/other_repo/config rename test/integration/{tags3/expected/.git_keep => submoduleReset/expected/other_repo}/description (100%) rename test/integration/{undo/expected/.git_keep => submoduleReset/expected/other_repo}/info/exclude (100%) create mode 100644 test/integration/submoduleReset/expected/other_repo/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename test/integration/{undo2/expected/.git_keep => submoduleReset/expected/other_repo}/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 (100%) create mode 100644 test/integration/submoduleReset/expected/other_repo/objects/42/530e986dbb65877ed8d61ca0c816e425e5c62e create mode 100644 test/integration/submoduleReset/expected/other_repo/objects/a5/0a5125768001a3ea263ffb7cafbc421a508153 rename test/integration/{tags4/expected/.git_keep => submoduleReset/expected/other_repo}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) create mode 100644 test/integration/submoduleReset/expected/other_repo/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 create mode 100644 test/integration/submoduleReset/expected/other_repo/packed-refs rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/HEAD rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/config (82%) rename test/integration/{tags4/expected => submoduleReset/expected/repo}/.git_keep/description (100%) create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/index rename test/integration/{undo2/expected => submoduleReset/expected/repo}/.git_keep/info/exclude (100%) rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/modules/other_repo/HEAD (100%) rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/modules/other_repo/ORIG_HEAD (100%) rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/modules/other_repo/config (85%) rename test/integration/{undo/expected/.git_keep => submoduleReset/expected/repo/.git_keep/modules/other_repo}/description (100%) create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/modules/other_repo/index create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/modules/other_repo/info/exclude create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/modules/other_repo/logs/HEAD rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/modules/other_repo/logs/refs/heads/master (58%) rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/modules/other_repo/logs/refs/remotes/origin/HEAD (70%) create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/modules/other_repo/logs/refs/stash create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/modules/other_repo/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/modules/other_repo/objects/17/a177705e91137f8c55965c9c8818dd55e97c89 rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/modules/other_repo/objects/17/defcd0e1f9ad96542aa66845e53cb46c91c30d (100%) create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/modules/other_repo/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/modules/other_repo/objects/42/530e986dbb65877ed8d61ca0c816e425e5c62e rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/modules/other_repo/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 (100%) rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/modules/other_repo/objects/5a/d28e22767f979da2c198dc6c1003b25964e3da (100%) create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/modules/other_repo/objects/87/4e570cb4ea7387ba59054b315aa584038cacea create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/modules/other_repo/objects/a5/0a5125768001a3ea263ffb7cafbc421a508153 rename test/integration/{undo/expected/.git_keep => submoduleReset/expected/repo/.git_keep/modules/other_repo}/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/modules/other_repo/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/modules/other_repo/objects/d2/2afbf8d80bbd74bcd87cae8a17a0315cfc915b rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/modules/other_repo/packed-refs (100%) rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/modules/other_repo/refs/heads/master (100%) rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/modules/other_repo/refs/remotes/origin/HEAD (100%) create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/modules/other_repo/refs/stash create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/objects/2b/864257bf2d49adbad8785540d85030a60852ff (100%) rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/objects/2e/eb2c1e6451d1318b506eecddf936b59a5f32b8 (100%) create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/objects/42/530e986dbb65877ed8d61ca0c816e425e5c62e rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/objects/9d/10a5a0a21eb2cfdb6206f474ed57fd5cd51440 (100%) create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/objects/a5/0a5125768001a3ea263ffb7cafbc421a508153 rename test/integration/{undo2/expected => submoduleReset/expected/repo}/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 (100%) create mode 100644 test/integration/submoduleReset/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 rename test/integration/submoduleReset/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/submoduleReset/expected/{ => repo}/.gitmodules_keep (100%) rename test/integration/submoduleReset/expected/{other_repo => repo}/myfile1 (100%) rename test/integration/submoduleReset/expected/{other_repo => repo}/myfile2 (100%) rename test/integration/submoduleReset/expected/{ => repo}/other_repo/.git_keep (100%) rename test/integration/{tags/expected/file1 => submoduleReset/expected/repo/other_repo/myfile1} (100%) rename test/integration/{tags2/expected/file2 => submoduleReset/expected/repo/other_repo/myfile2} (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/config (100%) rename test/integration/{undo2/expected => switchTabFromMenu/expected/repo}/.git_keep/description (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/index (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/objects/09/767bd3484e22b41138116992cc1cb5bc45fb7f (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/objects/72/068e9a852a790a9b867e8b5d21cb4ede3ba4d7 (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/objects/c4/534c51b41b7c85f4fad4657885792d95797e8c (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/objects/e0/aeb3ba0b32392aaf7d88a5190aca76be967225 (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/refs/tags/0.0.1 (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/.git_keep/refs/tags/0.0.2 (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/file0 (100%) rename test/integration/switchTabFromMenu/expected/{ => repo}/file1 (100%) rename test/integration/tags/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/tags/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) create mode 100644 test/integration/tags/expected/repo/.git_keep/HEAD rename test/integration/tags/expected/{ => repo}/.git_keep/config (100%) create mode 100644 test/integration/tags/expected/repo/.git_keep/description rename test/integration/tags/expected/{ => repo}/.git_keep/index (100%) create mode 100644 test/integration/tags/expected/repo/.git_keep/info/exclude rename test/integration/tags/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/tags/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/tags/expected/{ => repo}/.git_keep/objects/07/b4cadb018ce914237e3f31ee264c9555acc1d1 (100%) rename test/integration/tags/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/tags/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/tags/expected/{ => repo}/.git_keep/objects/3e/46e87f3ca37fad40d7dd6aca00223d7f49e424 (100%) create mode 100644 test/integration/tags/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename test/integration/tags/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/tags/expected/{ => repo}/.git_keep/packed-refs (100%) rename test/integration/tags/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/tags/expected/{ => repo}/.git_keep/refs/tags/tag1 (100%) rename test/integration/tags/expected/{ => repo}/.git_keep/refs/tags/tag3 (100%) rename test/integration/tags/expected/{ => repo}/.git_keep/refs/tags/tag4 (100%) rename test/integration/tags/expected/{ => repo}/file0 (100%) rename test/integration/{tags2/expected => tags/expected/repo}/file1 (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/config (100%) create mode 100644 test/integration/tags2/expected/repo/.git_keep/description rename test/integration/tags2/expected/{ => repo}/.git_keep/index (100%) create mode 100644 test/integration/tags2/expected/repo/.git_keep/info/exclude rename test/integration/tags2/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/objects/17/50e9a4016c985ef97d002ae40ed554e3db6c87 (100%) create mode 100644 test/integration/tags2/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename test/integration/tags2/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/objects/44/e5064a45438ffa3e6e4a0f1444552e2199be97 (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/objects/56/a89d6aebdfa4f2d717efc0d115656cc9b602e7 (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) create mode 100644 test/integration/tags2/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename test/integration/tags2/expected/{ => repo}/.git_keep/objects/ae/fe968910ad84a58bfac631b56eb422968766fb (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/objects/dc/b11a2a23383bd5f4a1085bf3a64e73e5bd963a (100%) create mode 100644 test/integration/tags2/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename test/integration/tags2/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/refs/tags/one (100%) rename test/integration/tags2/expected/{ => repo}/.git_keep/refs/tags/two (100%) rename test/integration/tags2/expected/{ => repo}/file0 (100%) rename test/integration/{tags3/expected => tags2/expected/repo}/file1 (100%) rename test/integration/{undo/expected => tags2/expected/repo}/file2 (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/config (100%) create mode 100644 test/integration/tags3/expected/repo/.git_keep/description rename test/integration/tags3/expected/{ => repo}/.git_keep/index (100%) create mode 100644 test/integration/tags3/expected/repo/.git_keep/info/exclude rename test/integration/tags3/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/logs/refs/heads/test (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/objects/08/c28e4e15f3de3b024524894d9235dfcdb48c19 (100%) create mode 100644 test/integration/tags3/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename test/integration/tags3/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/objects/25/15eabac6791725f4a3326676a1491f09664afc (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/objects/44/e5064a45438ffa3e6e4a0f1444552e2199be97 (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/objects/46/b4990797fac897fb135dd639a4cad3b0269f2d (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/objects/88/d7a40883abd57297127b3777a2a7ec3696c33a (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) create mode 100644 test/integration/tags3/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename test/integration/tags3/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) create mode 100644 test/integration/tags3/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename test/integration/tags3/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/refs/heads/test (100%) rename test/integration/tags3/expected/{ => repo}/.git_keep/refs/tags/one (100%) rename test/integration/tags3/expected/{ => repo}/file0 (100%) rename test/integration/{tags4/expected => tags3/expected/repo}/file1 (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) create mode 100644 test/integration/tags4/expected/repo/.git_keep/HEAD rename test/integration/tags4/expected/{ => repo}/.git_keep/config (100%) create mode 100644 test/integration/tags4/expected/repo/.git_keep/description rename test/integration/tags4/expected/{ => repo}/.git_keep/index (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/info/exclude (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/objects/3a/64c1649510c0dcaca3815291e3d43980f1bb99 (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/objects/56/18f31c7550111a878fb63f6079e8462ae94c42 (100%) create mode 100644 test/integration/tags4/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename test/integration/tags4/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/objects/db/03048dbacea165536b49c030c9aaca108cc571 (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/objects/f0/4e94a59e6159acf554fc1268742df10fe6b0d3 (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/packed-refs (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/tags4/expected/{ => repo}/.git_keep/refs/tags/atag2 (100%) rename test/integration/tags4/expected/{ => repo}/file0 (100%) rename test/integration/{undo/expected => tags4/expected/repo}/file1 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/HEAD (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/config (100%) create mode 100644 test/integration/undo/expected/repo/.git_keep/description rename test/integration/undo/expected/{ => repo}/.git_keep/index (100%) create mode 100644 test/integration/undo/expected/repo/.git_keep/info/exclude rename test/integration/undo/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/logs/refs/heads/branch2 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 (100%) create mode 100644 test/integration/undo/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename test/integration/undo/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/3e/4f2b1aeb076cff592279f94b1f495442690521 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/4f/77a25a15ccca0273baa522f7281727f31ceeb8 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/5d/2b236ff0e8342ef1e531506f6f99070d53cf25 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/68/ac4e416c01408d37c59465852aa1856a4abdb1 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/6d/95d7a7842625152ba887482879dfdaf247f591 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/7c/e8eac65e3ae50cb50a570dc775b745464f3a3e (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/99/36b8f380c2937bb457ade468bfc7dc850293f9 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/9d/187b7f4819a69996dd27e3d66a5224e05d9f41 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) create mode 100644 test/integration/undo/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename test/integration/undo/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/objects/fc/f46511d7819220e0cc310ae6d891fadfdb79aa (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/refs/heads/branch2 (100%) rename test/integration/undo/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/undo/expected/{ => repo}/file0 (100%) rename test/integration/{undo2/expected => undo/expected/repo}/file1 (100%) rename test/integration/{undo2/expected => undo/expected/repo}/file2 (100%) rename test/integration/undo/expected/{ => repo}/file4 (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/COMMIT_EDITMSG (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/FETCH_HEAD (100%) create mode 100644 test/integration/undo2/expected/repo/.git_keep/HEAD rename test/integration/undo2/expected/{ => repo}/.git_keep/ORIG_HEAD (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/config (100%) create mode 100644 test/integration/undo2/expected/repo/.git_keep/description rename test/integration/undo2/expected/{ => repo}/.git_keep/index (100%) create mode 100644 test/integration/undo2/expected/repo/.git_keep/info/exclude rename test/integration/undo2/expected/{ => repo}/.git_keep/logs/HEAD (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/logs/refs/heads/branch2 (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/logs/refs/heads/master (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/0e/2680a41392859e5159716b50525850017c6a59 (100%) create mode 100644 test/integration/undo2/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/48/1ce2cf9d037b83acb1d452973695764bf7b95e (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/8d/31a10ce1a1a1606ab02e8a2a59a6c56808f7c5 (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/a3/bf51bf610771f997de1d3f313ab7c43e20bef5 (100%) create mode 100644 test/integration/undo2/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/bc/e6c0c795a3d37c0a2c382a6d9c146b1889f86c (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/df/1876c035ade1ba199afadd399a6d4273190cd8 (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/e5/1d8e24ead991fdd7fd9b9d90924c2e24576981 (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/refs/heads/branch2 (100%) rename test/integration/undo2/expected/{ => repo}/.git_keep/refs/heads/master (100%) rename test/integration/undo2/expected/{ => repo}/file0 (100%) create mode 100644 test/integration/undo2/expected/repo/file1 create mode 100644 test/integration/undo2/expected/repo/file2 rename test/integration/undo2/expected/{ => repo}/file4 (100%) diff --git a/.gitignore b/.gitignore index ea0475b55..f20638ef9 100644 --- a/.gitignore +++ b/.gitignore @@ -33,7 +33,6 @@ lazygit.exe test/git_server/data test/integration/*/actual/ -test/integration/*/actual_remote/ test/integration/*/used_config/ # these sample hooks waste too much space test/integration/*/expected/**/hooks/ diff --git a/pkg/integration/integration.go b/pkg/integration/integration.go index ed1c0fe42..3edc44939 100644 --- a/pkg/integration/integration.go +++ b/pkg/integration/integration.go @@ -13,6 +13,7 @@ import ( "strings" "testing" + "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/secureexec" ) @@ -97,11 +98,9 @@ func RunTests( speeds := getTestSpeeds(test.Speed, mode, speedEnv) testPath := filepath.Join(testDir, test.Name) - actualRepoDir := filepath.Join(testPath, "actual") - expectedRepoDir := filepath.Join(testPath, "expected") - actualRemoteDir := filepath.Join(testPath, "actual_remote") - expectedRemoteDir := filepath.Join(testPath, "expected_remote") - otherRepoDir := filepath.Join(testPath, "other_repo") + actualDir := filepath.Join(testPath, "actual") + expectedDir := filepath.Join(testPath, "expected") + actualRepoDir := filepath.Join(actualDir, "repo") logf("path: %s", testPath) for i, speed := range speeds { @@ -110,9 +109,8 @@ func RunTests( } findOrCreateDir(testPath) - prepareIntegrationTestDir(actualRepoDir) - removeDir(otherRepoDir) - removeDir(actualRemoteDir) + prepareIntegrationTestDir(actualDir) + findOrCreateDir(actualRepoDir) err := createFixture(testPath, actualRepoDir) if err != nil { return err @@ -130,72 +128,66 @@ func RunTests( return err } - // submodule tests currently make use of a repo called 'other_repo' but we don't want that - // to stick around. Long-term we should have an 'actual' folder which itself contains - // repos, and there we can put the 'repo' repo which is the main one, alongside - // any others that we use as part of the test (including remotes). Then we'll do snapshots for - // each of them. - removeDir(otherRepoDir) - if mode == UPDATE_SNAPSHOT || mode == RECORD { // create/update snapshot - err = oscommands.CopyDir(actualRepoDir, expectedRepoDir) + err = oscommands.CopyDir(actualDir, expectedDir) if err != nil { return err } - if err := renameGitDirs(expectedRepoDir); err != nil { + if err := renameGitDirs(expectedDir); err != nil { return err } - // see if we have a remote dir and if so, copy it over. Otherwise, delete the expected dir because we have no remote folder. - if folderExists(actualRemoteDir) { - err = oscommands.CopyDir(actualRemoteDir, expectedRemoteDir) - if err != nil { - return err - } - } else { - removeDir(expectedRemoteDir) - } - logf("%s", "updated snapshot") } else { - // compare result to snapshot - actualRepo, expectedRepo, err := generateSnapshots(actualRepoDir, expectedRepoDir) + if err := validateSameRepos(expectedDir, actualDir); err != nil { + return err + } + + // iterate through each repo in the expected dir and comparet to the corresponding repo in the actual dir + expectedFiles, err := ioutil.ReadDir(expectedDir) if err != nil { return err } - actualRemote := "remote folder does not exist" - expectedRemote := "remote folder does not exist" - if folderExists(expectedRemoteDir) { - actualRemote, expectedRemote, err = generateSnapshotsForRemote(actualRemoteDir, expectedRemoteDir) + success := true + for _, f := range expectedFiles { + if !f.IsDir() { + return errors.New("unexpected file (as opposed to directory) in integration test 'expected' directory") + } + + // get corresponding file name from actual dir + actualRepoPath := filepath.Join(actualDir, f.Name()) + expectedRepoPath := filepath.Join(expectedDir, f.Name()) + + actualRepo, expectedRepo, err := generateSnapshots(actualRepoPath, expectedRepoPath) if err != nil { return err } - } else if folderExists(actualRemoteDir) { - actualRemote = "remote folder exists" + + if expectedRepo != actualRepo { + success = false + // if the snapshot doesn't match and we haven't tried all playback speeds different we'll retry at a slower speed + if i < len(speeds)-1 { + break + } + + // get the log file and print it + bytes, err := ioutil.ReadFile(filepath.Join(configDir, "development.log")) + if err != nil { + return err + } + logf("%s", string(bytes)) + + onFail(t, expectedRepo, actualRepo, f.Name()) + } } - if expectedRepo == actualRepo && expectedRemote == actualRemote { + if success { logf("%s: success at speed %f\n", test.Name, speed) break } - - // if the snapshot doesn't match and we haven't tried all playback speeds different we'll retry at a slower speed - if i == len(speeds)-1 { - // get the log file and print that - bytes, err := ioutil.ReadFile(filepath.Join(configDir, "development.log")) - if err != nil { - return err - } - logf("%s", string(bytes)) - if expectedRepo != actualRepo { - onFail(t, expectedRepo, actualRepo, "repo") - } else { - onFail(t, expectedRemote, actualRemote, "remote") - } - } } } @@ -206,11 +198,31 @@ func RunTests( return nil } -func removeDir(dir string) { - err := os.RemoveAll(dir) +// validates that the actual and expected dirs have the same repo names (doesn't actually check the contents of the repos) +func validateSameRepos(expectedDir string, actualDir string) error { + // iterate through each repo in the expected dir and comparet to the corresponding repo in the actual dir + expectedFiles, err := ioutil.ReadDir(expectedDir) if err != nil { - panic(err) + return err } + + var actualFiles []os.FileInfo + actualFiles, err = ioutil.ReadDir(actualDir) + if err != nil { + return err + } + + expectedFileNames := slices.Map(expectedFiles, getFileName) + actualFileNames := slices.Map(actualFiles, getFileName) + if !slices.Equal(expectedFileNames, actualFileNames) { + return fmt.Errorf("expected and actual repo dirs do not match: expected: %s, actual: %s", expectedFileNames, actualFileNames) + } + + return nil +} + +func getFileName(f os.FileInfo) string { + return f.Name() } func prepareIntegrationTestDir(actualDir string) { @@ -357,7 +369,9 @@ func generateSnapshot(dir string) (string, error) { snapshot := "" cmdStrs := []string{ - `remote show -n origin`, // remote branches + `remote show -n origin`, // remote branches + // TOOD: find a way to bring this back without breaking tests + // `ls-remote origin`, `status`, // file tree `log --pretty=%B -p -1`, // log `tag -n`, // tags @@ -493,26 +507,12 @@ func restoreGitDirs(dir string) error { return nil } -func generateSnapshotsForRemote(actualDir string, expectedDir string) (string, string, error) { - actual, err := generateSnapshot(actualDir) - if err != nil { - return "", "", err - } - - expected, err := generateSnapshot(expectedDir) - if err != nil { - return "", "", err - } - - return actual, expected, nil -} - func getLazygitCommand(testPath string, rootDir string, mode Mode, speed float64, extraCmdArgs string) (*exec.Cmd, error) { osCommand := oscommands.NewDummyOSCommand() replayPath := filepath.Join(testPath, "recording.json") templateConfigDir := filepath.Join(rootDir, "test", "default_test_config") - actualDir := filepath.Join(testPath, "actual") + actualRepoDir := filepath.Join(testPath, "actual", "repo") exists, err := osCommand.FileExists(filepath.Join(testPath, "config")) if err != nil { @@ -534,7 +534,7 @@ func getLazygitCommand(testPath string, rootDir string, mode Mode, speed float64 return nil, err } - cmdStr := fmt.Sprintf("%s -debug --use-config-dir=%s --path=%s %s", tempLazygitPath(), configDir, actualDir, extraCmdArgs) + cmdStr := fmt.Sprintf("%s -debug --use-config-dir=%s --path=%s %s", tempLazygitPath(), configDir, actualRepoDir, extraCmdArgs) cmdObj := osCommand.Cmd.New(cmdStr) cmdObj.AddEnvVars(fmt.Sprintf("SPEED=%f", speed)) @@ -548,8 +548,3 @@ func getLazygitCommand(testPath string, rootDir string, mode Mode, speed float64 return cmdObj.GetCmd(), nil } - -func folderExists(path string) bool { - _, err := os.Stat(path) - return err == nil -} diff --git a/test/hooks/pre-push b/test/hooks/pre-push index b7cb2e87b..3b758c1b1 100644 --- a/test/hooks/pre-push +++ b/test/hooks/pre-push @@ -14,6 +14,8 @@ echo -n "Username for 'github': " read username echo -n "Password for 'github': " +# this will print the password to the log view but real git won't do that. +# We could use read -s but that's not POSIX compliant. read password if [ "$username" = "username" -a "$password" = "password" ]; then diff --git a/test/integration/bisect/expected/.git_keep/BISECT_ANCESTORS_OK b/test/integration/bisect/expected/repo/.git_keep/BISECT_ANCESTORS_OK similarity index 100% rename from test/integration/bisect/expected/.git_keep/BISECT_ANCESTORS_OK rename to test/integration/bisect/expected/repo/.git_keep/BISECT_ANCESTORS_OK diff --git a/test/integration/bisect/expected/.git_keep/BISECT_EXPECTED_REV b/test/integration/bisect/expected/repo/.git_keep/BISECT_EXPECTED_REV similarity index 100% rename from test/integration/bisect/expected/.git_keep/BISECT_EXPECTED_REV rename to test/integration/bisect/expected/repo/.git_keep/BISECT_EXPECTED_REV diff --git a/test/integration/bisect/expected/.git_keep/BISECT_LOG b/test/integration/bisect/expected/repo/.git_keep/BISECT_LOG similarity index 100% rename from test/integration/bisect/expected/.git_keep/BISECT_LOG rename to test/integration/bisect/expected/repo/.git_keep/BISECT_LOG diff --git a/test/integration/bisect/expected/.git_keep/BISECT_NAMES b/test/integration/bisect/expected/repo/.git_keep/BISECT_NAMES similarity index 100% rename from test/integration/bisect/expected/.git_keep/BISECT_NAMES rename to test/integration/bisect/expected/repo/.git_keep/BISECT_NAMES diff --git a/test/integration/bisect/expected/.git_keep/BISECT_START b/test/integration/bisect/expected/repo/.git_keep/BISECT_START similarity index 100% rename from test/integration/bisect/expected/.git_keep/BISECT_START rename to test/integration/bisect/expected/repo/.git_keep/BISECT_START diff --git a/test/integration/bisect/expected/.git_keep/BISECT_TERMS b/test/integration/bisect/expected/repo/.git_keep/BISECT_TERMS similarity index 100% rename from test/integration/bisect/expected/.git_keep/BISECT_TERMS rename to test/integration/bisect/expected/repo/.git_keep/BISECT_TERMS diff --git a/test/integration/bisect/expected/.git_keep/COMMIT_EDITMSG b/test/integration/bisect/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/bisect/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/bisect/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/bisect/expected/.git_keep/FETCH_HEAD b/test/integration/bisect/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/bisect/expected/.git_keep/FETCH_HEAD rename to test/integration/bisect/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/bisect/expected/.git_keep/HEAD b/test/integration/bisect/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/bisect/expected/.git_keep/HEAD rename to test/integration/bisect/expected/repo/.git_keep/HEAD diff --git a/test/integration/bisect/expected/.git_keep/config b/test/integration/bisect/expected/repo/.git_keep/config similarity index 100% rename from test/integration/bisect/expected/.git_keep/config rename to test/integration/bisect/expected/repo/.git_keep/config diff --git a/test/integration/bisect/expected/.git_keep/description b/test/integration/bisect/expected/repo/.git_keep/description similarity index 100% rename from test/integration/bisect/expected/.git_keep/description rename to test/integration/bisect/expected/repo/.git_keep/description diff --git a/test/integration/bisect/expected/.git_keep/index b/test/integration/bisect/expected/repo/.git_keep/index similarity index 100% rename from test/integration/bisect/expected/.git_keep/index rename to test/integration/bisect/expected/repo/.git_keep/index diff --git a/test/integration/bisect/expected/.git_keep/info/exclude b/test/integration/bisect/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/bisect/expected/.git_keep/info/exclude rename to test/integration/bisect/expected/repo/.git_keep/info/exclude diff --git a/test/integration/bisect/expected/.git_keep/logs/HEAD b/test/integration/bisect/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/bisect/expected/.git_keep/logs/HEAD rename to test/integration/bisect/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/bisect/expected/.git_keep/logs/refs/heads/master b/test/integration/bisect/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/bisect/expected/.git_keep/logs/refs/heads/master rename to test/integration/bisect/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/bisect/expected/.git_keep/logs/refs/heads/test b/test/integration/bisect/expected/repo/.git_keep/logs/refs/heads/test similarity index 100% rename from test/integration/bisect/expected/.git_keep/logs/refs/heads/test rename to test/integration/bisect/expected/repo/.git_keep/logs/refs/heads/test diff --git a/test/integration/bisect/expected/.git_keep/objects/00/5ca78c7fb8157683fa61158235b250d2316004 b/test/integration/bisect/expected/repo/.git_keep/objects/00/5ca78c7fb8157683fa61158235b250d2316004 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/00/5ca78c7fb8157683fa61158235b250d2316004 rename to test/integration/bisect/expected/repo/.git_keep/objects/00/5ca78c7fb8157683fa61158235b250d2316004 diff --git a/test/integration/bisect/expected/.git_keep/objects/00/750edc07d6415dcc07ae0351e9397b0222b7ba b/test/integration/bisect/expected/repo/.git_keep/objects/00/750edc07d6415dcc07ae0351e9397b0222b7ba similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/00/750edc07d6415dcc07ae0351e9397b0222b7ba rename to test/integration/bisect/expected/repo/.git_keep/objects/00/750edc07d6415dcc07ae0351e9397b0222b7ba diff --git a/test/integration/bisect/expected/.git_keep/objects/05/4bdf969fdcf1f90f1998666f628d40f72fde4f b/test/integration/bisect/expected/repo/.git_keep/objects/05/4bdf969fdcf1f90f1998666f628d40f72fde4f similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/05/4bdf969fdcf1f90f1998666f628d40f72fde4f rename to test/integration/bisect/expected/repo/.git_keep/objects/05/4bdf969fdcf1f90f1998666f628d40f72fde4f diff --git a/test/integration/bisect/expected/.git_keep/objects/07/552205114379b7c1abd7cb39575cb7a30a2e8c b/test/integration/bisect/expected/repo/.git_keep/objects/07/552205114379b7c1abd7cb39575cb7a30a2e8c similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/07/552205114379b7c1abd7cb39575cb7a30a2e8c rename to test/integration/bisect/expected/repo/.git_keep/objects/07/552205114379b7c1abd7cb39575cb7a30a2e8c diff --git a/test/integration/bisect/expected/.git_keep/objects/0c/fbf08886fca9a91cb753ec8734c84fcbe52c9f b/test/integration/bisect/expected/repo/.git_keep/objects/0c/fbf08886fca9a91cb753ec8734c84fcbe52c9f similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/0c/fbf08886fca9a91cb753ec8734c84fcbe52c9f rename to test/integration/bisect/expected/repo/.git_keep/objects/0c/fbf08886fca9a91cb753ec8734c84fcbe52c9f diff --git a/test/integration/bisect/expected/.git_keep/objects/11/0046b8d92b877def6cda61639cf8f37bc2829c b/test/integration/bisect/expected/repo/.git_keep/objects/11/0046b8d92b877def6cda61639cf8f37bc2829c similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/11/0046b8d92b877def6cda61639cf8f37bc2829c rename to test/integration/bisect/expected/repo/.git_keep/objects/11/0046b8d92b877def6cda61639cf8f37bc2829c diff --git a/test/integration/bisect/expected/.git_keep/objects/12/e46e3c37d1a43a26b909a346ecd2d97677c641 b/test/integration/bisect/expected/repo/.git_keep/objects/12/e46e3c37d1a43a26b909a346ecd2d97677c641 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/12/e46e3c37d1a43a26b909a346ecd2d97677c641 rename to test/integration/bisect/expected/repo/.git_keep/objects/12/e46e3c37d1a43a26b909a346ecd2d97677c641 diff --git a/test/integration/bisect/expected/.git_keep/objects/1b/01733c2b372c7b5544c7f2293c3b7341824112 b/test/integration/bisect/expected/repo/.git_keep/objects/1b/01733c2b372c7b5544c7f2293c3b7341824112 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/1b/01733c2b372c7b5544c7f2293c3b7341824112 rename to test/integration/bisect/expected/repo/.git_keep/objects/1b/01733c2b372c7b5544c7f2293c3b7341824112 diff --git a/test/integration/bisect/expected/.git_keep/objects/1e/8b314962144c26d5e0e50fd29d2ca327864913 b/test/integration/bisect/expected/repo/.git_keep/objects/1e/8b314962144c26d5e0e50fd29d2ca327864913 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/1e/8b314962144c26d5e0e50fd29d2ca327864913 rename to test/integration/bisect/expected/repo/.git_keep/objects/1e/8b314962144c26d5e0e50fd29d2ca327864913 diff --git a/test/integration/bisect/expected/.git_keep/objects/20/9e3ef4b6247ce746048d5711befda46206d235 b/test/integration/bisect/expected/repo/.git_keep/objects/20/9e3ef4b6247ce746048d5711befda46206d235 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/20/9e3ef4b6247ce746048d5711befda46206d235 rename to test/integration/bisect/expected/repo/.git_keep/objects/20/9e3ef4b6247ce746048d5711befda46206d235 diff --git a/test/integration/bisect/expected/.git_keep/objects/26/7465454f74736bbe5b493c7f69dd3d024e26e5 b/test/integration/bisect/expected/repo/.git_keep/objects/26/7465454f74736bbe5b493c7f69dd3d024e26e5 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/26/7465454f74736bbe5b493c7f69dd3d024e26e5 rename to test/integration/bisect/expected/repo/.git_keep/objects/26/7465454f74736bbe5b493c7f69dd3d024e26e5 diff --git a/test/integration/bisect/expected/.git_keep/objects/32/e7b0308424a817ed5aa5bba94b06b72a1b8ce5 b/test/integration/bisect/expected/repo/.git_keep/objects/32/e7b0308424a817ed5aa5bba94b06b72a1b8ce5 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/32/e7b0308424a817ed5aa5bba94b06b72a1b8ce5 rename to test/integration/bisect/expected/repo/.git_keep/objects/32/e7b0308424a817ed5aa5bba94b06b72a1b8ce5 diff --git a/test/integration/bisect/expected/.git_keep/objects/39/983ea412adebe6c5a3d4451a7673cf0962c472 b/test/integration/bisect/expected/repo/.git_keep/objects/39/983ea412adebe6c5a3d4451a7673cf0962c472 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/39/983ea412adebe6c5a3d4451a7673cf0962c472 rename to test/integration/bisect/expected/repo/.git_keep/objects/39/983ea412adebe6c5a3d4451a7673cf0962c472 diff --git a/test/integration/bisect/expected/.git_keep/objects/3c/032078a4a21c5c51d3c93d91717c1dabbb8cd0 b/test/integration/bisect/expected/repo/.git_keep/objects/3c/032078a4a21c5c51d3c93d91717c1dabbb8cd0 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/3c/032078a4a21c5c51d3c93d91717c1dabbb8cd0 rename to test/integration/bisect/expected/repo/.git_keep/objects/3c/032078a4a21c5c51d3c93d91717c1dabbb8cd0 diff --git a/test/integration/bisect/expected/.git_keep/objects/3e/02ce90348f3386128ebb2972515fb1a3788818 b/test/integration/bisect/expected/repo/.git_keep/objects/3e/02ce90348f3386128ebb2972515fb1a3788818 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/3e/02ce90348f3386128ebb2972515fb1a3788818 rename to test/integration/bisect/expected/repo/.git_keep/objects/3e/02ce90348f3386128ebb2972515fb1a3788818 diff --git a/test/integration/bisect/expected/.git_keep/objects/3f/f8b0f3820fd2eb3da53a5b803f94caf30dc2ab b/test/integration/bisect/expected/repo/.git_keep/objects/3f/f8b0f3820fd2eb3da53a5b803f94caf30dc2ab similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/3f/f8b0f3820fd2eb3da53a5b803f94caf30dc2ab rename to test/integration/bisect/expected/repo/.git_keep/objects/3f/f8b0f3820fd2eb3da53a5b803f94caf30dc2ab diff --git a/test/integration/bisect/expected/.git_keep/objects/43/78c740dfa0de7a973216b54b99c45a3c03f83c b/test/integration/bisect/expected/repo/.git_keep/objects/43/78c740dfa0de7a973216b54b99c45a3c03f83c similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/43/78c740dfa0de7a973216b54b99c45a3c03f83c rename to test/integration/bisect/expected/repo/.git_keep/objects/43/78c740dfa0de7a973216b54b99c45a3c03f83c diff --git a/test/integration/bisect/expected/.git_keep/objects/45/a4fb75db864000d01701c0f7a51864bd4daabf b/test/integration/bisect/expected/repo/.git_keep/objects/45/a4fb75db864000d01701c0f7a51864bd4daabf similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/45/a4fb75db864000d01701c0f7a51864bd4daabf rename to test/integration/bisect/expected/repo/.git_keep/objects/45/a4fb75db864000d01701c0f7a51864bd4daabf diff --git a/test/integration/bisect/expected/.git_keep/objects/47/8a007451b33c7a234c60f0d13b164561b29094 b/test/integration/bisect/expected/repo/.git_keep/objects/47/8a007451b33c7a234c60f0d13b164561b29094 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/47/8a007451b33c7a234c60f0d13b164561b29094 rename to test/integration/bisect/expected/repo/.git_keep/objects/47/8a007451b33c7a234c60f0d13b164561b29094 diff --git a/test/integration/bisect/expected/.git_keep/objects/48/082f72f087ce7e6fa75b9c41d7387daecd447b b/test/integration/bisect/expected/repo/.git_keep/objects/48/082f72f087ce7e6fa75b9c41d7387daecd447b similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/48/082f72f087ce7e6fa75b9c41d7387daecd447b rename to test/integration/bisect/expected/repo/.git_keep/objects/48/082f72f087ce7e6fa75b9c41d7387daecd447b diff --git a/test/integration/bisect/expected/.git_keep/objects/4b/65d66c089cd4f6bfa69dff2d7ba4c27337cd23 b/test/integration/bisect/expected/repo/.git_keep/objects/4b/65d66c089cd4f6bfa69dff2d7ba4c27337cd23 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/4b/65d66c089cd4f6bfa69dff2d7ba4c27337cd23 rename to test/integration/bisect/expected/repo/.git_keep/objects/4b/65d66c089cd4f6bfa69dff2d7ba4c27337cd23 diff --git a/test/integration/bisect/expected/.git_keep/objects/54/3c0ef66d928051f16f8b9d7d33d6c4ea1f4e4f b/test/integration/bisect/expected/repo/.git_keep/objects/54/3c0ef66d928051f16f8b9d7d33d6c4ea1f4e4f similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/54/3c0ef66d928051f16f8b9d7d33d6c4ea1f4e4f rename to test/integration/bisect/expected/repo/.git_keep/objects/54/3c0ef66d928051f16f8b9d7d33d6c4ea1f4e4f diff --git a/test/integration/bisect/expected/.git_keep/objects/5f/9397e5bcee1ac2a3fe6d834d42e36b74ef4ca8 b/test/integration/bisect/expected/repo/.git_keep/objects/5f/9397e5bcee1ac2a3fe6d834d42e36b74ef4ca8 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/5f/9397e5bcee1ac2a3fe6d834d42e36b74ef4ca8 rename to test/integration/bisect/expected/repo/.git_keep/objects/5f/9397e5bcee1ac2a3fe6d834d42e36b74ef4ca8 diff --git a/test/integration/bisect/expected/.git_keep/objects/60/d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 b/test/integration/bisect/expected/repo/.git_keep/objects/60/d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/60/d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 rename to test/integration/bisect/expected/repo/.git_keep/objects/60/d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 diff --git a/test/integration/bisect/expected/.git_keep/objects/66/19c0a1a3eb6449eb15ce6cd0916fec0e410c10 b/test/integration/bisect/expected/repo/.git_keep/objects/66/19c0a1a3eb6449eb15ce6cd0916fec0e410c10 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/66/19c0a1a3eb6449eb15ce6cd0916fec0e410c10 rename to test/integration/bisect/expected/repo/.git_keep/objects/66/19c0a1a3eb6449eb15ce6cd0916fec0e410c10 diff --git a/test/integration/bisect/expected/.git_keep/objects/67/fbfb3b74c2381ad1e058949231f2b4f0c8921f b/test/integration/bisect/expected/repo/.git_keep/objects/67/fbfb3b74c2381ad1e058949231f2b4f0c8921f similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/67/fbfb3b74c2381ad1e058949231f2b4f0c8921f rename to test/integration/bisect/expected/repo/.git_keep/objects/67/fbfb3b74c2381ad1e058949231f2b4f0c8921f diff --git a/test/integration/bisect/expected/.git_keep/objects/78/d41b2abbd2f52c1ebf2f496268a915d59eb27b b/test/integration/bisect/expected/repo/.git_keep/objects/78/d41b2abbd2f52c1ebf2f496268a915d59eb27b similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/78/d41b2abbd2f52c1ebf2f496268a915d59eb27b rename to test/integration/bisect/expected/repo/.git_keep/objects/78/d41b2abbd2f52c1ebf2f496268a915d59eb27b diff --git a/test/integration/bisect/expected/.git_keep/objects/7e/d6ff82de6bcc2a78243fc9c54d3ef5ac14da69 b/test/integration/bisect/expected/repo/.git_keep/objects/7e/d6ff82de6bcc2a78243fc9c54d3ef5ac14da69 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/7e/d6ff82de6bcc2a78243fc9c54d3ef5ac14da69 rename to test/integration/bisect/expected/repo/.git_keep/objects/7e/d6ff82de6bcc2a78243fc9c54d3ef5ac14da69 diff --git a/test/integration/bisect/expected/.git_keep/objects/7f/8f011eb73d6043d2e6db9d2c101195ae2801f2 b/test/integration/bisect/expected/repo/.git_keep/objects/7f/8f011eb73d6043d2e6db9d2c101195ae2801f2 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/7f/8f011eb73d6043d2e6db9d2c101195ae2801f2 rename to test/integration/bisect/expected/repo/.git_keep/objects/7f/8f011eb73d6043d2e6db9d2c101195ae2801f2 diff --git a/test/integration/bisect/expected/.git_keep/objects/80/eeef1a7c49b376f3373ea26c6ba44d69d90d9c b/test/integration/bisect/expected/repo/.git_keep/objects/80/eeef1a7c49b376f3373ea26c6ba44d69d90d9c similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/80/eeef1a7c49b376f3373ea26c6ba44d69d90d9c rename to test/integration/bisect/expected/repo/.git_keep/objects/80/eeef1a7c49b376f3373ea26c6ba44d69d90d9c diff --git a/test/integration/bisect/expected/.git_keep/objects/82/d721eb037f7045056023d0904989781ce1f526 b/test/integration/bisect/expected/repo/.git_keep/objects/82/d721eb037f7045056023d0904989781ce1f526 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/82/d721eb037f7045056023d0904989781ce1f526 rename to test/integration/bisect/expected/repo/.git_keep/objects/82/d721eb037f7045056023d0904989781ce1f526 diff --git a/test/integration/bisect/expected/.git_keep/objects/83/51c19397f4fcd5238d10034fa7fa384f14d580 b/test/integration/bisect/expected/repo/.git_keep/objects/83/51c19397f4fcd5238d10034fa7fa384f14d580 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/83/51c19397f4fcd5238d10034fa7fa384f14d580 rename to test/integration/bisect/expected/repo/.git_keep/objects/83/51c19397f4fcd5238d10034fa7fa384f14d580 diff --git a/test/integration/bisect/expected/.git_keep/objects/91/36f315e5952043f1e7ecdc0d28c208eaeaed71 b/test/integration/bisect/expected/repo/.git_keep/objects/91/36f315e5952043f1e7ecdc0d28c208eaeaed71 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/91/36f315e5952043f1e7ecdc0d28c208eaeaed71 rename to test/integration/bisect/expected/repo/.git_keep/objects/91/36f315e5952043f1e7ecdc0d28c208eaeaed71 diff --git a/test/integration/bisect/expected/.git_keep/objects/96/202a92c1d3bde1b20d6f3dec8e742d09732b4d b/test/integration/bisect/expected/repo/.git_keep/objects/96/202a92c1d3bde1b20d6f3dec8e742d09732b4d similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/96/202a92c1d3bde1b20d6f3dec8e742d09732b4d rename to test/integration/bisect/expected/repo/.git_keep/objects/96/202a92c1d3bde1b20d6f3dec8e742d09732b4d diff --git a/test/integration/bisect/expected/.git_keep/objects/98/d9bcb75a685dfbfd60f611c309410152935b3d b/test/integration/bisect/expected/repo/.git_keep/objects/98/d9bcb75a685dfbfd60f611c309410152935b3d similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/98/d9bcb75a685dfbfd60f611c309410152935b3d rename to test/integration/bisect/expected/repo/.git_keep/objects/98/d9bcb75a685dfbfd60f611c309410152935b3d diff --git a/test/integration/bisect/expected/.git_keep/objects/ae/95e9aa3b8881aedb7a526c86ec5d60f371ca6c b/test/integration/bisect/expected/repo/.git_keep/objects/ae/95e9aa3b8881aedb7a526c86ec5d60f371ca6c similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/ae/95e9aa3b8881aedb7a526c86ec5d60f371ca6c rename to test/integration/bisect/expected/repo/.git_keep/objects/ae/95e9aa3b8881aedb7a526c86ec5d60f371ca6c diff --git a/test/integration/bisect/expected/.git_keep/objects/af/f6316148f1524977997c486bcfe624c9094c4e b/test/integration/bisect/expected/repo/.git_keep/objects/af/f6316148f1524977997c486bcfe624c9094c4e similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/af/f6316148f1524977997c486bcfe624c9094c4e rename to test/integration/bisect/expected/repo/.git_keep/objects/af/f6316148f1524977997c486bcfe624c9094c4e diff --git a/test/integration/bisect/expected/.git_keep/objects/b1/bd38b62a0800a4f6a80c34e21c5acffae52c7e b/test/integration/bisect/expected/repo/.git_keep/objects/b1/bd38b62a0800a4f6a80c34e21c5acffae52c7e similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/b1/bd38b62a0800a4f6a80c34e21c5acffae52c7e rename to test/integration/bisect/expected/repo/.git_keep/objects/b1/bd38b62a0800a4f6a80c34e21c5acffae52c7e diff --git a/test/integration/bisect/expected/.git_keep/objects/b4/de3947675361a7770d29b8982c407b0ec6b2a0 b/test/integration/bisect/expected/repo/.git_keep/objects/b4/de3947675361a7770d29b8982c407b0ec6b2a0 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/b4/de3947675361a7770d29b8982c407b0ec6b2a0 rename to test/integration/bisect/expected/repo/.git_keep/objects/b4/de3947675361a7770d29b8982c407b0ec6b2a0 diff --git a/test/integration/bisect/expected/.git_keep/objects/b5/31696093a6482eca9ad4bcab63407172225b93 b/test/integration/bisect/expected/repo/.git_keep/objects/b5/31696093a6482eca9ad4bcab63407172225b93 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/b5/31696093a6482eca9ad4bcab63407172225b93 rename to test/integration/bisect/expected/repo/.git_keep/objects/b5/31696093a6482eca9ad4bcab63407172225b93 diff --git a/test/integration/bisect/expected/.git_keep/objects/b6/a7d89c68e0ca66e96a9a51892cc33db66fb8a3 b/test/integration/bisect/expected/repo/.git_keep/objects/b6/a7d89c68e0ca66e96a9a51892cc33db66fb8a3 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/b6/a7d89c68e0ca66e96a9a51892cc33db66fb8a3 rename to test/integration/bisect/expected/repo/.git_keep/objects/b6/a7d89c68e0ca66e96a9a51892cc33db66fb8a3 diff --git a/test/integration/bisect/expected/.git_keep/objects/b8/626c4cff2849624fb67f87cd0ad72b163671ad b/test/integration/bisect/expected/repo/.git_keep/objects/b8/626c4cff2849624fb67f87cd0ad72b163671ad similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/b8/626c4cff2849624fb67f87cd0ad72b163671ad rename to test/integration/bisect/expected/repo/.git_keep/objects/b8/626c4cff2849624fb67f87cd0ad72b163671ad diff --git a/test/integration/bisect/expected/.git_keep/objects/b9/7844c9437a4ab69c8165cadd97bc597b43135b b/test/integration/bisect/expected/repo/.git_keep/objects/b9/7844c9437a4ab69c8165cadd97bc597b43135b similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/b9/7844c9437a4ab69c8165cadd97bc597b43135b rename to test/integration/bisect/expected/repo/.git_keep/objects/b9/7844c9437a4ab69c8165cadd97bc597b43135b diff --git a/test/integration/bisect/expected/.git_keep/objects/ba/8e7277a0ee7cdf84cd5c6138057adb85947a90 b/test/integration/bisect/expected/repo/.git_keep/objects/ba/8e7277a0ee7cdf84cd5c6138057adb85947a90 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/ba/8e7277a0ee7cdf84cd5c6138057adb85947a90 rename to test/integration/bisect/expected/repo/.git_keep/objects/ba/8e7277a0ee7cdf84cd5c6138057adb85947a90 diff --git a/test/integration/bisect/expected/.git_keep/objects/bc/21c8fabc28201fab6c60503168ecda25ad8626 b/test/integration/bisect/expected/repo/.git_keep/objects/bc/21c8fabc28201fab6c60503168ecda25ad8626 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/bc/21c8fabc28201fab6c60503168ecda25ad8626 rename to test/integration/bisect/expected/repo/.git_keep/objects/bc/21c8fabc28201fab6c60503168ecda25ad8626 diff --git a/test/integration/bisect/expected/.git_keep/objects/d0/0491fd7e5bb6fa28c517a0bb32b8b506539d4d b/test/integration/bisect/expected/repo/.git_keep/objects/d0/0491fd7e5bb6fa28c517a0bb32b8b506539d4d similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/d0/0491fd7e5bb6fa28c517a0bb32b8b506539d4d rename to test/integration/bisect/expected/repo/.git_keep/objects/d0/0491fd7e5bb6fa28c517a0bb32b8b506539d4d diff --git a/test/integration/bisect/expected/.git_keep/objects/d1/f7a85555fe6f10dd44754d35459ae741cb107c b/test/integration/bisect/expected/repo/.git_keep/objects/d1/f7a85555fe6f10dd44754d35459ae741cb107c similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/d1/f7a85555fe6f10dd44754d35459ae741cb107c rename to test/integration/bisect/expected/repo/.git_keep/objects/d1/f7a85555fe6f10dd44754d35459ae741cb107c diff --git a/test/integration/bisect/expected/.git_keep/objects/d5/42aa84743f8ba1380358d4009408f03dbfb247 b/test/integration/bisect/expected/repo/.git_keep/objects/d5/42aa84743f8ba1380358d4009408f03dbfb247 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/d5/42aa84743f8ba1380358d4009408f03dbfb247 rename to test/integration/bisect/expected/repo/.git_keep/objects/d5/42aa84743f8ba1380358d4009408f03dbfb247 diff --git a/test/integration/bisect/expected/.git_keep/objects/d6/b24041cf04154f8f902651969675021f4d93a5 b/test/integration/bisect/expected/repo/.git_keep/objects/d6/b24041cf04154f8f902651969675021f4d93a5 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/d6/b24041cf04154f8f902651969675021f4d93a5 rename to test/integration/bisect/expected/repo/.git_keep/objects/d6/b24041cf04154f8f902651969675021f4d93a5 diff --git a/test/integration/bisect/expected/.git_keep/objects/d9/328d9b2c9536fdf01641dd03f4a254d2c86601 b/test/integration/bisect/expected/repo/.git_keep/objects/d9/328d9b2c9536fdf01641dd03f4a254d2c86601 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/d9/328d9b2c9536fdf01641dd03f4a254d2c86601 rename to test/integration/bisect/expected/repo/.git_keep/objects/d9/328d9b2c9536fdf01641dd03f4a254d2c86601 diff --git a/test/integration/bisect/expected/.git_keep/objects/d9/cc608eedd5d2cc63c262272b7a0f6ab6aed5dd b/test/integration/bisect/expected/repo/.git_keep/objects/d9/cc608eedd5d2cc63c262272b7a0f6ab6aed5dd similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/d9/cc608eedd5d2cc63c262272b7a0f6ab6aed5dd rename to test/integration/bisect/expected/repo/.git_keep/objects/d9/cc608eedd5d2cc63c262272b7a0f6ab6aed5dd diff --git a/test/integration/bisect/expected/.git_keep/objects/db/b21289ee21b2ff0f3de2bc7d00038b30c4e353 b/test/integration/bisect/expected/repo/.git_keep/objects/db/b21289ee21b2ff0f3de2bc7d00038b30c4e353 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/db/b21289ee21b2ff0f3de2bc7d00038b30c4e353 rename to test/integration/bisect/expected/repo/.git_keep/objects/db/b21289ee21b2ff0f3de2bc7d00038b30c4e353 diff --git a/test/integration/bisect/expected/.git_keep/objects/e5/9bbaffe94b06acaadab4245f30ff3e11c66e5b b/test/integration/bisect/expected/repo/.git_keep/objects/e5/9bbaffe94b06acaadab4245f30ff3e11c66e5b similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/e5/9bbaffe94b06acaadab4245f30ff3e11c66e5b rename to test/integration/bisect/expected/repo/.git_keep/objects/e5/9bbaffe94b06acaadab4245f30ff3e11c66e5b diff --git a/test/integration/bisect/expected/.git_keep/objects/e9/27f0f9467e772eea36f24053c9b534303b106a b/test/integration/bisect/expected/repo/.git_keep/objects/e9/27f0f9467e772eea36f24053c9b534303b106a similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/e9/27f0f9467e772eea36f24053c9b534303b106a rename to test/integration/bisect/expected/repo/.git_keep/objects/e9/27f0f9467e772eea36f24053c9b534303b106a diff --git a/test/integration/bisect/expected/.git_keep/objects/e9/d2f825e793bc9ac2be698348dbe669bad34cad b/test/integration/bisect/expected/repo/.git_keep/objects/e9/d2f825e793bc9ac2be698348dbe669bad34cad similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/e9/d2f825e793bc9ac2be698348dbe669bad34cad rename to test/integration/bisect/expected/repo/.git_keep/objects/e9/d2f825e793bc9ac2be698348dbe669bad34cad diff --git a/test/integration/bisect/expected/.git_keep/objects/ea/684d3f868c358400465f2ec16a640c319ea6a3 b/test/integration/bisect/expected/repo/.git_keep/objects/ea/684d3f868c358400465f2ec16a640c319ea6a3 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/ea/684d3f868c358400465f2ec16a640c319ea6a3 rename to test/integration/bisect/expected/repo/.git_keep/objects/ea/684d3f868c358400465f2ec16a640c319ea6a3 diff --git a/test/integration/bisect/expected/.git_keep/objects/eb/e59a71e9750e75fb983f241687cdf7f0c8ce94 b/test/integration/bisect/expected/repo/.git_keep/objects/eb/e59a71e9750e75fb983f241687cdf7f0c8ce94 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/eb/e59a71e9750e75fb983f241687cdf7f0c8ce94 rename to test/integration/bisect/expected/repo/.git_keep/objects/eb/e59a71e9750e75fb983f241687cdf7f0c8ce94 diff --git a/test/integration/bisect/expected/.git_keep/objects/ec/635144f60048986bc560c5576355344005e6e7 b/test/integration/bisect/expected/repo/.git_keep/objects/ec/635144f60048986bc560c5576355344005e6e7 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/ec/635144f60048986bc560c5576355344005e6e7 rename to test/integration/bisect/expected/repo/.git_keep/objects/ec/635144f60048986bc560c5576355344005e6e7 diff --git a/test/integration/bisect/expected/.git_keep/objects/f2/7c6ae26adb8396d3861976ba268f87ad8afa0b b/test/integration/bisect/expected/repo/.git_keep/objects/f2/7c6ae26adb8396d3861976ba268f87ad8afa0b similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/f2/7c6ae26adb8396d3861976ba268f87ad8afa0b rename to test/integration/bisect/expected/repo/.git_keep/objects/f2/7c6ae26adb8396d3861976ba268f87ad8afa0b diff --git a/test/integration/bisect/expected/.git_keep/objects/f5/99e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 b/test/integration/bisect/expected/repo/.git_keep/objects/f5/99e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 similarity index 100% rename from test/integration/bisect/expected/.git_keep/objects/f5/99e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 rename to test/integration/bisect/expected/repo/.git_keep/objects/f5/99e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 diff --git a/test/integration/bisect/expected/.git_keep/packed-refs b/test/integration/bisect/expected/repo/.git_keep/packed-refs similarity index 100% rename from test/integration/bisect/expected/.git_keep/packed-refs rename to test/integration/bisect/expected/repo/.git_keep/packed-refs diff --git a/test/integration/bisect/expected/.git_keep/refs/bisect/bad b/test/integration/bisect/expected/repo/.git_keep/refs/bisect/bad similarity index 100% rename from test/integration/bisect/expected/.git_keep/refs/bisect/bad rename to test/integration/bisect/expected/repo/.git_keep/refs/bisect/bad diff --git a/test/integration/bisect/expected/.git_keep/refs/bisect/good-39983ea412adebe6c5a3d4451a7673cf0962c472 b/test/integration/bisect/expected/repo/.git_keep/refs/bisect/good-39983ea412adebe6c5a3d4451a7673cf0962c472 similarity index 100% rename from test/integration/bisect/expected/.git_keep/refs/bisect/good-39983ea412adebe6c5a3d4451a7673cf0962c472 rename to test/integration/bisect/expected/repo/.git_keep/refs/bisect/good-39983ea412adebe6c5a3d4451a7673cf0962c472 diff --git a/test/integration/bisect/expected/.git_keep/refs/bisect/good-67fbfb3b74c2381ad1e058949231f2b4f0c8921f b/test/integration/bisect/expected/repo/.git_keep/refs/bisect/good-67fbfb3b74c2381ad1e058949231f2b4f0c8921f similarity index 100% rename from test/integration/bisect/expected/.git_keep/refs/bisect/good-67fbfb3b74c2381ad1e058949231f2b4f0c8921f rename to test/integration/bisect/expected/repo/.git_keep/refs/bisect/good-67fbfb3b74c2381ad1e058949231f2b4f0c8921f diff --git a/test/integration/bisect/expected/.git_keep/refs/bisect/good-e927f0f9467e772eea36f24053c9b534303b106a b/test/integration/bisect/expected/repo/.git_keep/refs/bisect/good-e927f0f9467e772eea36f24053c9b534303b106a similarity index 100% rename from test/integration/bisect/expected/.git_keep/refs/bisect/good-e927f0f9467e772eea36f24053c9b534303b106a rename to test/integration/bisect/expected/repo/.git_keep/refs/bisect/good-e927f0f9467e772eea36f24053c9b534303b106a diff --git a/test/integration/bisect/expected/.git_keep/refs/bisect/good-e9d2f825e793bc9ac2be698348dbe669bad34cad b/test/integration/bisect/expected/repo/.git_keep/refs/bisect/good-e9d2f825e793bc9ac2be698348dbe669bad34cad similarity index 100% rename from test/integration/bisect/expected/.git_keep/refs/bisect/good-e9d2f825e793bc9ac2be698348dbe669bad34cad rename to test/integration/bisect/expected/repo/.git_keep/refs/bisect/good-e9d2f825e793bc9ac2be698348dbe669bad34cad diff --git a/test/integration/bisect/expected/.git_keep/refs/bisect/skip-bc21c8fabc28201fab6c60503168ecda25ad8626 b/test/integration/bisect/expected/repo/.git_keep/refs/bisect/skip-bc21c8fabc28201fab6c60503168ecda25ad8626 similarity index 100% rename from test/integration/bisect/expected/.git_keep/refs/bisect/skip-bc21c8fabc28201fab6c60503168ecda25ad8626 rename to test/integration/bisect/expected/repo/.git_keep/refs/bisect/skip-bc21c8fabc28201fab6c60503168ecda25ad8626 diff --git a/test/integration/bisect/expected/.git_keep/refs/bisect/skip-d1f7a85555fe6f10dd44754d35459ae741cb107c b/test/integration/bisect/expected/repo/.git_keep/refs/bisect/skip-d1f7a85555fe6f10dd44754d35459ae741cb107c similarity index 100% rename from test/integration/bisect/expected/.git_keep/refs/bisect/skip-d1f7a85555fe6f10dd44754d35459ae741cb107c rename to test/integration/bisect/expected/repo/.git_keep/refs/bisect/skip-d1f7a85555fe6f10dd44754d35459ae741cb107c diff --git a/test/integration/bisect/expected/.git_keep/refs/heads/master b/test/integration/bisect/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/bisect/expected/.git_keep/refs/heads/master rename to test/integration/bisect/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/bisect/expected/.git_keep/refs/heads/test b/test/integration/bisect/expected/repo/.git_keep/refs/heads/test similarity index 100% rename from test/integration/bisect/expected/.git_keep/refs/heads/test rename to test/integration/bisect/expected/repo/.git_keep/refs/heads/test diff --git a/test/integration/bisect/expected/file b/test/integration/bisect/expected/repo/file similarity index 100% rename from test/integration/bisect/expected/file rename to test/integration/bisect/expected/repo/file diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/BISECT_ANCESTORS_OK b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/BISECT_ANCESTORS_OK similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/BISECT_ANCESTORS_OK rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/BISECT_ANCESTORS_OK diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/BISECT_EXPECTED_REV b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/BISECT_EXPECTED_REV similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/BISECT_EXPECTED_REV rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/BISECT_EXPECTED_REV diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/BISECT_LOG b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/BISECT_LOG similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/BISECT_LOG rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/BISECT_LOG diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/BISECT_NAMES b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/BISECT_NAMES similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/BISECT_NAMES rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/BISECT_NAMES diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/BISECT_START b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/BISECT_START similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/BISECT_START rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/BISECT_START diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/BISECT_TERMS b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/BISECT_TERMS similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/BISECT_TERMS rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/BISECT_TERMS diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/COMMIT_EDITMSG b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/FETCH_HEAD b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/FETCH_HEAD rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/HEAD b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/HEAD rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/HEAD diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/config b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/config similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/config rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/config diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/description b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/description similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/description rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/description diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/index b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/index similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/index rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/index diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/info/exclude b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/info/exclude rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/info/exclude diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/logs/HEAD b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/logs/HEAD rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/logs/refs/heads/master b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/logs/refs/heads/master rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/logs/refs/heads/other b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/logs/refs/heads/other similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/logs/refs/heads/other rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/logs/refs/heads/other diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/logs/refs/heads/test b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/logs/refs/heads/test similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/logs/refs/heads/test rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/logs/refs/heads/test diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/00/750edc07d6415dcc07ae0351e9397b0222b7ba b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/00/750edc07d6415dcc07ae0351e9397b0222b7ba similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/00/750edc07d6415dcc07ae0351e9397b0222b7ba rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/00/750edc07d6415dcc07ae0351e9397b0222b7ba diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/03/ecdaa424af1fdaeab1bd1852319652b9518f11 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/03/ecdaa424af1fdaeab1bd1852319652b9518f11 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/03/ecdaa424af1fdaeab1bd1852319652b9518f11 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/03/ecdaa424af1fdaeab1bd1852319652b9518f11 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/04/a577be2858b8024716876aefe6b665a98e1e4f b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/04/a577be2858b8024716876aefe6b665a98e1e4f similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/04/a577be2858b8024716876aefe6b665a98e1e4f rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/04/a577be2858b8024716876aefe6b665a98e1e4f diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/05/57fc43da38567eae00831e9b385fd2cad22643 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/05/57fc43da38567eae00831e9b385fd2cad22643 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/05/57fc43da38567eae00831e9b385fd2cad22643 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/05/57fc43da38567eae00831e9b385fd2cad22643 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/0c/fbf08886fca9a91cb753ec8734c84fcbe52c9f b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/0c/fbf08886fca9a91cb753ec8734c84fcbe52c9f similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/0c/fbf08886fca9a91cb753ec8734c84fcbe52c9f rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/0c/fbf08886fca9a91cb753ec8734c84fcbe52c9f diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/0d/1bbe8d012c8c070167a006a4898b525cfbd930 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/0d/1bbe8d012c8c070167a006a4898b525cfbd930 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/0d/1bbe8d012c8c070167a006a4898b525cfbd930 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/0d/1bbe8d012c8c070167a006a4898b525cfbd930 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/0f/373801691c466240bd131d28b2168712b045ba b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/0f/373801691c466240bd131d28b2168712b045ba similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/0f/373801691c466240bd131d28b2168712b045ba rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/0f/373801691c466240bd131d28b2168712b045ba diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/10/e171beacb963e4f8a4dc1d80fd291c135902bb b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/10/e171beacb963e4f8a4dc1d80fd291c135902bb similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/10/e171beacb963e4f8a4dc1d80fd291c135902bb rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/10/e171beacb963e4f8a4dc1d80fd291c135902bb diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/11/e4fd4011c9ed3800bb33b85580dd1d09f6aefd b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/11/e4fd4011c9ed3800bb33b85580dd1d09f6aefd similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/11/e4fd4011c9ed3800bb33b85580dd1d09f6aefd rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/11/e4fd4011c9ed3800bb33b85580dd1d09f6aefd diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/15/d4c5b8608fe472fd224333e60d44ea826cc80e b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/15/d4c5b8608fe472fd224333e60d44ea826cc80e similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/15/d4c5b8608fe472fd224333e60d44ea826cc80e rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/15/d4c5b8608fe472fd224333e60d44ea826cc80e diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/1a/35564b85e24c96e647b477aaf8d35dcf0de84d b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/1a/35564b85e24c96e647b477aaf8d35dcf0de84d similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/1a/35564b85e24c96e647b477aaf8d35dcf0de84d rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/1a/35564b85e24c96e647b477aaf8d35dcf0de84d diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/1a/b342c03b4226cca1c751dba71fa2df0e7d82ee b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/1a/b342c03b4226cca1c751dba71fa2df0e7d82ee similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/1a/b342c03b4226cca1c751dba71fa2df0e7d82ee rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/1a/b342c03b4226cca1c751dba71fa2df0e7d82ee diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/1e/8b314962144c26d5e0e50fd29d2ca327864913 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/1e/8b314962144c26d5e0e50fd29d2ca327864913 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/1e/8b314962144c26d5e0e50fd29d2ca327864913 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/1e/8b314962144c26d5e0e50fd29d2ca327864913 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/20/9e3ef4b6247ce746048d5711befda46206d235 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/20/9e3ef4b6247ce746048d5711befda46206d235 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/20/9e3ef4b6247ce746048d5711befda46206d235 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/20/9e3ef4b6247ce746048d5711befda46206d235 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/26/661287266e53bda69d8daa3aac1f714650f13c b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/26/661287266e53bda69d8daa3aac1f714650f13c similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/26/661287266e53bda69d8daa3aac1f714650f13c rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/26/661287266e53bda69d8daa3aac1f714650f13c diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/30/68d0d730547aaa5b86dbfe638db83133ae1421 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/30/68d0d730547aaa5b86dbfe638db83133ae1421 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/30/68d0d730547aaa5b86dbfe638db83133ae1421 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/30/68d0d730547aaa5b86dbfe638db83133ae1421 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/31/df6c951dc82b75b11bc48836e780134a16e6ad b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/31/df6c951dc82b75b11bc48836e780134a16e6ad similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/31/df6c951dc82b75b11bc48836e780134a16e6ad rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/31/df6c951dc82b75b11bc48836e780134a16e6ad diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/33/3ff293caf2d3216edf22e3f1df64d43a7e1311 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/33/3ff293caf2d3216edf22e3f1df64d43a7e1311 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/33/3ff293caf2d3216edf22e3f1df64d43a7e1311 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/33/3ff293caf2d3216edf22e3f1df64d43a7e1311 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/36/903784186b1b8b4a150dc656eccd49f94e114e b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/36/903784186b1b8b4a150dc656eccd49f94e114e similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/36/903784186b1b8b4a150dc656eccd49f94e114e rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/36/903784186b1b8b4a150dc656eccd49f94e114e diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/38/242e5215bc35b3e418c1d6d63fd0291001e10b b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/38/242e5215bc35b3e418c1d6d63fd0291001e10b similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/38/242e5215bc35b3e418c1d6d63fd0291001e10b rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/38/242e5215bc35b3e418c1d6d63fd0291001e10b diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/3a/05ed1ca9671bc362c7197eb09bddff040c9110 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/3a/05ed1ca9671bc362c7197eb09bddff040c9110 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/3a/05ed1ca9671bc362c7197eb09bddff040c9110 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/3a/05ed1ca9671bc362c7197eb09bddff040c9110 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/3b/e94d6b1b1b3b63db9e412b2e788d08979bc176 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/3b/e94d6b1b1b3b63db9e412b2e788d08979bc176 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/3b/e94d6b1b1b3b63db9e412b2e788d08979bc176 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/3b/e94d6b1b1b3b63db9e412b2e788d08979bc176 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/3c/032078a4a21c5c51d3c93d91717c1dabbb8cd0 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/3c/032078a4a21c5c51d3c93d91717c1dabbb8cd0 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/3c/032078a4a21c5c51d3c93d91717c1dabbb8cd0 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/3c/032078a4a21c5c51d3c93d91717c1dabbb8cd0 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/3f/bb9e626d4b7d30e58346b3eefaa342b15ab776 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/3f/bb9e626d4b7d30e58346b3eefaa342b15ab776 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/3f/bb9e626d4b7d30e58346b3eefaa342b15ab776 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/3f/bb9e626d4b7d30e58346b3eefaa342b15ab776 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/3f/d9ad29c185eac6106cfa005a3aa594e21b9e06 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/3f/d9ad29c185eac6106cfa005a3aa594e21b9e06 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/3f/d9ad29c185eac6106cfa005a3aa594e21b9e06 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/3f/d9ad29c185eac6106cfa005a3aa594e21b9e06 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/43/99b07bd31d1f58a0ff10b5434d5ff4f36e38fb b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/43/99b07bd31d1f58a0ff10b5434d5ff4f36e38fb similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/43/99b07bd31d1f58a0ff10b5434d5ff4f36e38fb rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/43/99b07bd31d1f58a0ff10b5434d5ff4f36e38fb diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/45/a4fb75db864000d01701c0f7a51864bd4daabf b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/45/a4fb75db864000d01701c0f7a51864bd4daabf similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/45/a4fb75db864000d01701c0f7a51864bd4daabf rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/45/a4fb75db864000d01701c0f7a51864bd4daabf diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/48/082f72f087ce7e6fa75b9c41d7387daecd447b b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/48/082f72f087ce7e6fa75b9c41d7387daecd447b similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/48/082f72f087ce7e6fa75b9c41d7387daecd447b rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/48/082f72f087ce7e6fa75b9c41d7387daecd447b diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/4a/9e01012c736e5e0998b7184d9a54e8c610ed02 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/4a/9e01012c736e5e0998b7184d9a54e8c610ed02 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/4a/9e01012c736e5e0998b7184d9a54e8c610ed02 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/4a/9e01012c736e5e0998b7184d9a54e8c610ed02 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/54/93d27d38b9902cf28b1035c644bf470df76060 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/54/93d27d38b9902cf28b1035c644bf470df76060 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/54/93d27d38b9902cf28b1035c644bf470df76060 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/54/93d27d38b9902cf28b1035c644bf470df76060 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/60/d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/60/d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/60/d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/60/d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/6f/a769bf11bd9dc4ff4e85f4951950b0bc34326f b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/6f/a769bf11bd9dc4ff4e85f4951950b0bc34326f similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/6f/a769bf11bd9dc4ff4e85f4951950b0bc34326f rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/6f/a769bf11bd9dc4ff4e85f4951950b0bc34326f diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/74/cd0e856d938eb6b665284c5485c00f87e20dc5 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/74/cd0e856d938eb6b665284c5485c00f87e20dc5 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/74/cd0e856d938eb6b665284c5485c00f87e20dc5 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/74/cd0e856d938eb6b665284c5485c00f87e20dc5 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/7c/fd51ebd06287effcfdab241235305cb6439d40 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/7c/fd51ebd06287effcfdab241235305cb6439d40 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/7c/fd51ebd06287effcfdab241235305cb6439d40 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/7c/fd51ebd06287effcfdab241235305cb6439d40 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/7e/d6ff82de6bcc2a78243fc9c54d3ef5ac14da69 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/7e/d6ff82de6bcc2a78243fc9c54d3ef5ac14da69 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/7e/d6ff82de6bcc2a78243fc9c54d3ef5ac14da69 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/7e/d6ff82de6bcc2a78243fc9c54d3ef5ac14da69 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/7f/8f011eb73d6043d2e6db9d2c101195ae2801f2 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/7f/8f011eb73d6043d2e6db9d2c101195ae2801f2 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/7f/8f011eb73d6043d2e6db9d2c101195ae2801f2 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/7f/8f011eb73d6043d2e6db9d2c101195ae2801f2 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/83/51c19397f4fcd5238d10034fa7fa384f14d580 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/83/51c19397f4fcd5238d10034fa7fa384f14d580 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/83/51c19397f4fcd5238d10034fa7fa384f14d580 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/83/51c19397f4fcd5238d10034fa7fa384f14d580 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/88/8633a131a49f1b8981d70c13d666defed6ba15 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/88/8633a131a49f1b8981d70c13d666defed6ba15 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/88/8633a131a49f1b8981d70c13d666defed6ba15 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/88/8633a131a49f1b8981d70c13d666defed6ba15 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/8b/0156bd25a1ecd82ef7c4c53e9d6d312bb6d403 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/8b/0156bd25a1ecd82ef7c4c53e9d6d312bb6d403 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/8b/0156bd25a1ecd82ef7c4c53e9d6d312bb6d403 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/8b/0156bd25a1ecd82ef7c4c53e9d6d312bb6d403 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/90/dfebd90b0a89766c39928f22901b8c02b51fda b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/90/dfebd90b0a89766c39928f22901b8c02b51fda similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/90/dfebd90b0a89766c39928f22901b8c02b51fda rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/90/dfebd90b0a89766c39928f22901b8c02b51fda diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/98/d9bcb75a685dfbfd60f611c309410152935b3d b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/98/d9bcb75a685dfbfd60f611c309410152935b3d similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/98/d9bcb75a685dfbfd60f611c309410152935b3d rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/98/d9bcb75a685dfbfd60f611c309410152935b3d diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/9c/836a5c3f513818d300b410f8cb3a2e3bbd42a1 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/9c/836a5c3f513818d300b410f8cb3a2e3bbd42a1 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/9c/836a5c3f513818d300b410f8cb3a2e3bbd42a1 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/9c/836a5c3f513818d300b410f8cb3a2e3bbd42a1 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/9d/33ec0915534bf6401be9412203697791e40a04 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/9d/33ec0915534bf6401be9412203697791e40a04 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/9d/33ec0915534bf6401be9412203697791e40a04 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/9d/33ec0915534bf6401be9412203697791e40a04 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/b1/bd38b62a0800a4f6a80c34e21c5acffae52c7e b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/b1/bd38b62a0800a4f6a80c34e21c5acffae52c7e similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/b1/bd38b62a0800a4f6a80c34e21c5acffae52c7e rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/b1/bd38b62a0800a4f6a80c34e21c5acffae52c7e diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/b2/970eba9fd8dba8655094dc38fb4ee50b9bf23e b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/b2/970eba9fd8dba8655094dc38fb4ee50b9bf23e similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/b2/970eba9fd8dba8655094dc38fb4ee50b9bf23e rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/b2/970eba9fd8dba8655094dc38fb4ee50b9bf23e diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/b4/de3947675361a7770d29b8982c407b0ec6b2a0 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/b4/de3947675361a7770d29b8982c407b0ec6b2a0 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/b4/de3947675361a7770d29b8982c407b0ec6b2a0 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/b4/de3947675361a7770d29b8982c407b0ec6b2a0 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/b6/14152a335aabd8b5daa2c6abccc9425eb14177 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/b6/14152a335aabd8b5daa2c6abccc9425eb14177 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/b6/14152a335aabd8b5daa2c6abccc9425eb14177 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/b6/14152a335aabd8b5daa2c6abccc9425eb14177 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/b6/a7d89c68e0ca66e96a9a51892cc33db66fb8a3 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/b6/a7d89c68e0ca66e96a9a51892cc33db66fb8a3 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/b6/a7d89c68e0ca66e96a9a51892cc33db66fb8a3 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/b6/a7d89c68e0ca66e96a9a51892cc33db66fb8a3 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/b8/626c4cff2849624fb67f87cd0ad72b163671ad b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/b8/626c4cff2849624fb67f87cd0ad72b163671ad similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/b8/626c4cff2849624fb67f87cd0ad72b163671ad rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/b8/626c4cff2849624fb67f87cd0ad72b163671ad diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/cd/c58c0f95a2313ded9185e102bc35253f6a1bed b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/cd/c58c0f95a2313ded9185e102bc35253f6a1bed similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/cd/c58c0f95a2313ded9185e102bc35253f6a1bed rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/cd/c58c0f95a2313ded9185e102bc35253f6a1bed diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/d0/0491fd7e5bb6fa28c517a0bb32b8b506539d4d b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/d0/0491fd7e5bb6fa28c517a0bb32b8b506539d4d similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/d0/0491fd7e5bb6fa28c517a0bb32b8b506539d4d rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/d0/0491fd7e5bb6fa28c517a0bb32b8b506539d4d diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/d2/7a997859219951ecc95c351174c70ea0cf9d37 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/d2/7a997859219951ecc95c351174c70ea0cf9d37 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/d2/7a997859219951ecc95c351174c70ea0cf9d37 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/d2/7a997859219951ecc95c351174c70ea0cf9d37 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/d3/6e09d97bf2c1527118bde353ad64b157f8b269 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/d3/6e09d97bf2c1527118bde353ad64b157f8b269 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/d3/6e09d97bf2c1527118bde353ad64b157f8b269 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/d3/6e09d97bf2c1527118bde353ad64b157f8b269 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/d4/e982570808a24722649e852a92bda5cf54c9dd b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/d4/e982570808a24722649e852a92bda5cf54c9dd similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/d4/e982570808a24722649e852a92bda5cf54c9dd rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/d4/e982570808a24722649e852a92bda5cf54c9dd diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/d6/b24041cf04154f8f902651969675021f4d93a5 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/d6/b24041cf04154f8f902651969675021f4d93a5 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/d6/b24041cf04154f8f902651969675021f4d93a5 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/d6/b24041cf04154f8f902651969675021f4d93a5 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/d8/4e0684b1038552d5c8d86e67398d634f77ad3b b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/d8/4e0684b1038552d5c8d86e67398d634f77ad3b similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/d8/4e0684b1038552d5c8d86e67398d634f77ad3b rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/d8/4e0684b1038552d5c8d86e67398d634f77ad3b diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/da/8dacb2a073ebc2adeddceb3cc2b39b6c95c858 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/da/8dacb2a073ebc2adeddceb3cc2b39b6c95c858 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/da/8dacb2a073ebc2adeddceb3cc2b39b6c95c858 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/da/8dacb2a073ebc2adeddceb3cc2b39b6c95c858 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/db/76c03074879025735b647b825786a7b3fcfe7c b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/db/76c03074879025735b647b825786a7b3fcfe7c similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/db/76c03074879025735b647b825786a7b3fcfe7c rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/db/76c03074879025735b647b825786a7b3fcfe7c diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/e5/59f83c6e8dd11680de70b487725e37ff2e283f b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/e5/59f83c6e8dd11680de70b487725e37ff2e283f similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/e5/59f83c6e8dd11680de70b487725e37ff2e283f rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/e5/59f83c6e8dd11680de70b487725e37ff2e283f diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/ec/635144f60048986bc560c5576355344005e6e7 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/ec/635144f60048986bc560c5576355344005e6e7 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/ec/635144f60048986bc560c5576355344005e6e7 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/ec/635144f60048986bc560c5576355344005e6e7 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/f5/99e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/f5/99e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/f5/99e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/f5/99e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/objects/ff/231021500c7beb87de0d6d5edc29b6f9c000b1 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/ff/231021500c7beb87de0d6d5edc29b6f9c000b1 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/objects/ff/231021500c7beb87de0d6d5edc29b6f9c000b1 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/objects/ff/231021500c7beb87de0d6d5edc29b6f9c000b1 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/packed-refs b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/packed-refs similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/packed-refs rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/packed-refs diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/refs/bisect/bad b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/refs/bisect/bad similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/refs/bisect/bad rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/refs/bisect/bad diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/refs/bisect/good-38242e5215bc35b3e418c1d6d63fd0291001e10b b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/refs/bisect/good-38242e5215bc35b3e418c1d6d63fd0291001e10b similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/refs/bisect/good-38242e5215bc35b3e418c1d6d63fd0291001e10b rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/refs/bisect/good-38242e5215bc35b3e418c1d6d63fd0291001e10b diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/refs/bisect/good-3fbb9e626d4b7d30e58346b3eefaa342b15ab776 b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/refs/bisect/good-3fbb9e626d4b7d30e58346b3eefaa342b15ab776 similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/refs/bisect/good-3fbb9e626d4b7d30e58346b3eefaa342b15ab776 rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/refs/bisect/good-3fbb9e626d4b7d30e58346b3eefaa342b15ab776 diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/refs/heads/master b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/refs/heads/master rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/refs/heads/other b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/refs/heads/other similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/refs/heads/other rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/refs/heads/other diff --git a/test/integration/bisectFromOtherBranch/expected/.git_keep/refs/heads/test b/test/integration/bisectFromOtherBranch/expected/repo/.git_keep/refs/heads/test similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/.git_keep/refs/heads/test rename to test/integration/bisectFromOtherBranch/expected/repo/.git_keep/refs/heads/test diff --git a/test/integration/bisectFromOtherBranch/expected/myfile b/test/integration/bisectFromOtherBranch/expected/repo/myfile similarity index 100% rename from test/integration/bisectFromOtherBranch/expected/myfile rename to test/integration/bisectFromOtherBranch/expected/repo/myfile diff --git a/test/integration/branchAutocomplete/expected/.git_keep/COMMIT_EDITMSG b/test/integration/branchAutocomplete/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/branchAutocomplete/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/branchAutocomplete/expected/.git_keep/FETCH_HEAD b/test/integration/branchAutocomplete/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/FETCH_HEAD rename to test/integration/branchAutocomplete/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/branchAutocomplete/expected/.git_keep/HEAD b/test/integration/branchAutocomplete/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/HEAD rename to test/integration/branchAutocomplete/expected/repo/.git_keep/HEAD diff --git a/test/integration/branchAutocomplete/expected/.git_keep/config b/test/integration/branchAutocomplete/expected/repo/.git_keep/config similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/config rename to test/integration/branchAutocomplete/expected/repo/.git_keep/config diff --git a/test/integration/branchAutocomplete/expected/.git_keep/description b/test/integration/branchAutocomplete/expected/repo/.git_keep/description similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/description rename to test/integration/branchAutocomplete/expected/repo/.git_keep/description diff --git a/test/integration/branchAutocomplete/expected/.git_keep/index b/test/integration/branchAutocomplete/expected/repo/.git_keep/index similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/index rename to test/integration/branchAutocomplete/expected/repo/.git_keep/index diff --git a/test/integration/branchAutocomplete/expected/.git_keep/info/exclude b/test/integration/branchAutocomplete/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/info/exclude rename to test/integration/branchAutocomplete/expected/repo/.git_keep/info/exclude diff --git a/test/integration/branchAutocomplete/expected/.git_keep/logs/HEAD b/test/integration/branchAutocomplete/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/logs/HEAD rename to test/integration/branchAutocomplete/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/branchAutocomplete/expected/.git_keep/logs/refs/heads/four b/test/integration/branchAutocomplete/expected/repo/.git_keep/logs/refs/heads/four similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/logs/refs/heads/four rename to test/integration/branchAutocomplete/expected/repo/.git_keep/logs/refs/heads/four diff --git a/test/integration/branchAutocomplete/expected/.git_keep/logs/refs/heads/master b/test/integration/branchAutocomplete/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/logs/refs/heads/master rename to test/integration/branchAutocomplete/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/branchAutocomplete/expected/.git_keep/logs/refs/heads/one b/test/integration/branchAutocomplete/expected/repo/.git_keep/logs/refs/heads/one similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/logs/refs/heads/one rename to test/integration/branchAutocomplete/expected/repo/.git_keep/logs/refs/heads/one diff --git a/test/integration/branchAutocomplete/expected/.git_keep/logs/refs/heads/three b/test/integration/branchAutocomplete/expected/repo/.git_keep/logs/refs/heads/three similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/logs/refs/heads/three rename to test/integration/branchAutocomplete/expected/repo/.git_keep/logs/refs/heads/three diff --git a/test/integration/branchAutocomplete/expected/.git_keep/logs/refs/heads/two b/test/integration/branchAutocomplete/expected/repo/.git_keep/logs/refs/heads/two similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/logs/refs/heads/two rename to test/integration/branchAutocomplete/expected/repo/.git_keep/logs/refs/heads/two diff --git a/test/integration/branchAutocomplete/expected/.git_keep/objects/b4/9fda1c7a9af6a4f0b6b07a2cb31aecb8c01a6c b/test/integration/branchAutocomplete/expected/repo/.git_keep/objects/b4/9fda1c7a9af6a4f0b6b07a2cb31aecb8c01a6c similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/objects/b4/9fda1c7a9af6a4f0b6b07a2cb31aecb8c01a6c rename to test/integration/branchAutocomplete/expected/repo/.git_keep/objects/b4/9fda1c7a9af6a4f0b6b07a2cb31aecb8c01a6c diff --git a/test/integration/branchAutocomplete/expected/.git_keep/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/test/integration/branchAutocomplete/expected/repo/.git_keep/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 rename to test/integration/branchAutocomplete/expected/repo/.git_keep/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/integration/branchAutocomplete/expected/.git_keep/objects/f7/53f4dfc98d148a7e685c46c8d148bcac56707d b/test/integration/branchAutocomplete/expected/repo/.git_keep/objects/f7/53f4dfc98d148a7e685c46c8d148bcac56707d similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/objects/f7/53f4dfc98d148a7e685c46c8d148bcac56707d rename to test/integration/branchAutocomplete/expected/repo/.git_keep/objects/f7/53f4dfc98d148a7e685c46c8d148bcac56707d diff --git a/test/integration/branchAutocomplete/expected/.git_keep/refs/heads/four b/test/integration/branchAutocomplete/expected/repo/.git_keep/refs/heads/four similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/refs/heads/four rename to test/integration/branchAutocomplete/expected/repo/.git_keep/refs/heads/four diff --git a/test/integration/branchAutocomplete/expected/.git_keep/refs/heads/master b/test/integration/branchAutocomplete/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/refs/heads/master rename to test/integration/branchAutocomplete/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/branchAutocomplete/expected/.git_keep/refs/heads/one b/test/integration/branchAutocomplete/expected/repo/.git_keep/refs/heads/one similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/refs/heads/one rename to test/integration/branchAutocomplete/expected/repo/.git_keep/refs/heads/one diff --git a/test/integration/branchAutocomplete/expected/.git_keep/refs/heads/three b/test/integration/branchAutocomplete/expected/repo/.git_keep/refs/heads/three similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/refs/heads/three rename to test/integration/branchAutocomplete/expected/repo/.git_keep/refs/heads/three diff --git a/test/integration/branchAutocomplete/expected/.git_keep/refs/heads/two b/test/integration/branchAutocomplete/expected/repo/.git_keep/refs/heads/two similarity index 100% rename from test/integration/branchAutocomplete/expected/.git_keep/refs/heads/two rename to test/integration/branchAutocomplete/expected/repo/.git_keep/refs/heads/two diff --git a/test/integration/branchAutocomplete/expected/myfile.txt b/test/integration/branchAutocomplete/expected/repo/myfile.txt similarity index 100% rename from test/integration/branchAutocomplete/expected/myfile.txt rename to test/integration/branchAutocomplete/expected/repo/myfile.txt diff --git a/test/integration/branchDelete/expected/.git_keep/COMMIT_EDITMSG b/test/integration/branchDelete/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/branchDelete/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/branchDelete/expected/.git_keep/FETCH_HEAD b/test/integration/branchDelete/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/FETCH_HEAD rename to test/integration/branchDelete/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/branchDelete/expected/.git_keep/HEAD b/test/integration/branchDelete/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/HEAD rename to test/integration/branchDelete/expected/repo/.git_keep/HEAD diff --git a/test/integration/branchDelete/expected/.git_keep/config b/test/integration/branchDelete/expected/repo/.git_keep/config similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/config rename to test/integration/branchDelete/expected/repo/.git_keep/config diff --git a/test/integration/branchDelete/expected/.git_keep/description b/test/integration/branchDelete/expected/repo/.git_keep/description similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/description rename to test/integration/branchDelete/expected/repo/.git_keep/description diff --git a/test/integration/branchDelete/expected/.git_keep/index b/test/integration/branchDelete/expected/repo/.git_keep/index similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/index rename to test/integration/branchDelete/expected/repo/.git_keep/index diff --git a/test/integration/branchDelete/expected/.git_keep/info/exclude b/test/integration/branchDelete/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/info/exclude rename to test/integration/branchDelete/expected/repo/.git_keep/info/exclude diff --git a/test/integration/branchDelete/expected/.git_keep/logs/HEAD b/test/integration/branchDelete/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/logs/HEAD rename to test/integration/branchDelete/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/branchDelete/expected/.git_keep/logs/refs/heads/master b/test/integration/branchDelete/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/logs/refs/heads/master rename to test/integration/branchDelete/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/branchDelete/expected/.git_keep/logs/refs/heads/new-branch b/test/integration/branchDelete/expected/repo/.git_keep/logs/refs/heads/new-branch similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/logs/refs/heads/new-branch rename to test/integration/branchDelete/expected/repo/.git_keep/logs/refs/heads/new-branch diff --git a/test/integration/branchDelete/expected/.git_keep/logs/refs/heads/new-branch-2 b/test/integration/branchDelete/expected/repo/.git_keep/logs/refs/heads/new-branch-2 similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/logs/refs/heads/new-branch-2 rename to test/integration/branchDelete/expected/repo/.git_keep/logs/refs/heads/new-branch-2 diff --git a/test/integration/branchDelete/expected/.git_keep/logs/refs/heads/new-branch-3 b/test/integration/branchDelete/expected/repo/.git_keep/logs/refs/heads/new-branch-3 similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/logs/refs/heads/new-branch-3 rename to test/integration/branchDelete/expected/repo/.git_keep/logs/refs/heads/new-branch-3 diff --git a/test/integration/branchDelete/expected/.git_keep/logs/refs/heads/old-branch b/test/integration/branchDelete/expected/repo/.git_keep/logs/refs/heads/old-branch similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/logs/refs/heads/old-branch rename to test/integration/branchDelete/expected/repo/.git_keep/logs/refs/heads/old-branch diff --git a/test/integration/branchDelete/expected/.git_keep/logs/refs/heads/old-branch-3 b/test/integration/branchDelete/expected/repo/.git_keep/logs/refs/heads/old-branch-3 similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/logs/refs/heads/old-branch-3 rename to test/integration/branchDelete/expected/repo/.git_keep/logs/refs/heads/old-branch-3 diff --git a/test/integration/branchDelete/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 b/test/integration/branchDelete/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 rename to test/integration/branchDelete/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 diff --git a/test/integration/branchDelete/expected/.git_keep/objects/21/b436d66d2c515ad17285e53d9e6380d599b044 b/test/integration/branchDelete/expected/repo/.git_keep/objects/21/b436d66d2c515ad17285e53d9e6380d599b044 similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/objects/21/b436d66d2c515ad17285e53d9e6380d599b044 rename to test/integration/branchDelete/expected/repo/.git_keep/objects/21/b436d66d2c515ad17285e53d9e6380d599b044 diff --git a/test/integration/branchDelete/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da b/test/integration/branchDelete/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da rename to test/integration/branchDelete/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da diff --git a/test/integration/branchDelete/expected/.git_keep/refs/heads/master b/test/integration/branchDelete/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/refs/heads/master rename to test/integration/branchDelete/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/branchDelete/expected/.git_keep/refs/heads/new-branch b/test/integration/branchDelete/expected/repo/.git_keep/refs/heads/new-branch similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/refs/heads/new-branch rename to test/integration/branchDelete/expected/repo/.git_keep/refs/heads/new-branch diff --git a/test/integration/branchDelete/expected/.git_keep/refs/heads/new-branch-2 b/test/integration/branchDelete/expected/repo/.git_keep/refs/heads/new-branch-2 similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/refs/heads/new-branch-2 rename to test/integration/branchDelete/expected/repo/.git_keep/refs/heads/new-branch-2 diff --git a/test/integration/branchDelete/expected/.git_keep/refs/heads/new-branch-3 b/test/integration/branchDelete/expected/repo/.git_keep/refs/heads/new-branch-3 similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/refs/heads/new-branch-3 rename to test/integration/branchDelete/expected/repo/.git_keep/refs/heads/new-branch-3 diff --git a/test/integration/branchDelete/expected/.git_keep/refs/heads/old-branch b/test/integration/branchDelete/expected/repo/.git_keep/refs/heads/old-branch similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/refs/heads/old-branch rename to test/integration/branchDelete/expected/repo/.git_keep/refs/heads/old-branch diff --git a/test/integration/branchDelete/expected/.git_keep/refs/heads/old-branch-3 b/test/integration/branchDelete/expected/repo/.git_keep/refs/heads/old-branch-3 similarity index 100% rename from test/integration/branchDelete/expected/.git_keep/refs/heads/old-branch-3 rename to test/integration/branchDelete/expected/repo/.git_keep/refs/heads/old-branch-3 diff --git a/test/integration/branchDelete/expected/file0 b/test/integration/branchDelete/expected/repo/file0 similarity index 100% rename from test/integration/branchDelete/expected/file0 rename to test/integration/branchDelete/expected/repo/file0 diff --git a/test/integration/branchRebase/expected/.git_keep/COMMIT_EDITMSG b/test/integration/branchRebase/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/branchRebase/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/branchRebase/expected/.git_keep/FETCH_HEAD b/test/integration/branchRebase/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/FETCH_HEAD rename to test/integration/branchRebase/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/branchRebase/expected/.git_keep/HEAD b/test/integration/branchRebase/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/HEAD rename to test/integration/branchRebase/expected/repo/.git_keep/HEAD diff --git a/test/integration/branchRebase/expected/.git_keep/ORIG_HEAD b/test/integration/branchRebase/expected/repo/.git_keep/ORIG_HEAD similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/ORIG_HEAD rename to test/integration/branchRebase/expected/repo/.git_keep/ORIG_HEAD diff --git a/test/integration/branchRebase/expected/.git_keep/config b/test/integration/branchRebase/expected/repo/.git_keep/config similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/config rename to test/integration/branchRebase/expected/repo/.git_keep/config diff --git a/test/integration/branchRebase/expected/.git_keep/description b/test/integration/branchRebase/expected/repo/.git_keep/description similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/description rename to test/integration/branchRebase/expected/repo/.git_keep/description diff --git a/test/integration/branchRebase/expected/.git_keep/index b/test/integration/branchRebase/expected/repo/.git_keep/index similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/index rename to test/integration/branchRebase/expected/repo/.git_keep/index diff --git a/test/integration/branchRebase/expected/.git_keep/info/exclude b/test/integration/branchRebase/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/info/exclude rename to test/integration/branchRebase/expected/repo/.git_keep/info/exclude diff --git a/test/integration/branchRebase/expected/.git_keep/logs/HEAD b/test/integration/branchRebase/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/logs/HEAD rename to test/integration/branchRebase/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/branchRebase/expected/.git_keep/logs/refs/heads/develop b/test/integration/branchRebase/expected/repo/.git_keep/logs/refs/heads/develop similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/logs/refs/heads/develop rename to test/integration/branchRebase/expected/repo/.git_keep/logs/refs/heads/develop diff --git a/test/integration/branchRebase/expected/.git_keep/logs/refs/heads/master b/test/integration/branchRebase/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/logs/refs/heads/master rename to test/integration/branchRebase/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/branchRebase/expected/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d b/test/integration/branchRebase/expected/repo/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d rename to test/integration/branchRebase/expected/repo/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d diff --git a/test/integration/branchRebase/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/branchRebase/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca b/test/integration/branchRebase/expected/repo/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca rename to test/integration/branchRebase/expected/repo/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca diff --git a/test/integration/branchRebase/expected/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af b/test/integration/branchRebase/expected/repo/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af rename to test/integration/branchRebase/expected/repo/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af diff --git a/test/integration/branchRebase/expected/.git_keep/objects/2e/83133d8d6b88c588de66c3ff8405501b5215b4 b/test/integration/branchRebase/expected/repo/.git_keep/objects/2e/83133d8d6b88c588de66c3ff8405501b5215b4 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/2e/83133d8d6b88c588de66c3ff8405501b5215b4 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/2e/83133d8d6b88c588de66c3ff8405501b5215b4 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd b/test/integration/branchRebase/expected/repo/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd rename to test/integration/branchRebase/expected/repo/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd diff --git a/test/integration/branchRebase/expected/.git_keep/objects/36/27f93f3cc779dc2f99484fb8ffa49953e43b2f b/test/integration/branchRebase/expected/repo/.git_keep/objects/36/27f93f3cc779dc2f99484fb8ffa49953e43b2f similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/36/27f93f3cc779dc2f99484fb8ffa49953e43b2f rename to test/integration/branchRebase/expected/repo/.git_keep/objects/36/27f93f3cc779dc2f99484fb8ffa49953e43b2f diff --git a/test/integration/branchRebase/expected/.git_keep/objects/3e/1706cdf670f5641be0715178471abfc9ed1748 b/test/integration/branchRebase/expected/repo/.git_keep/objects/3e/1706cdf670f5641be0715178471abfc9ed1748 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/3e/1706cdf670f5641be0715178471abfc9ed1748 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/3e/1706cdf670f5641be0715178471abfc9ed1748 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/42/1b29bba240f23ea39e216bb0873cd4012624b5 b/test/integration/branchRebase/expected/repo/.git_keep/objects/42/1b29bba240f23ea39e216bb0873cd4012624b5 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/42/1b29bba240f23ea39e216bb0873cd4012624b5 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/42/1b29bba240f23ea39e216bb0873cd4012624b5 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/42/597904331c82f6d5c8c902755c8dfa5767ea95 b/test/integration/branchRebase/expected/repo/.git_keep/objects/42/597904331c82f6d5c8c902755c8dfa5767ea95 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/42/597904331c82f6d5c8c902755c8dfa5767ea95 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/42/597904331c82f6d5c8c902755c8dfa5767ea95 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 b/test/integration/branchRebase/expected/repo/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 b/test/integration/branchRebase/expected/repo/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 b/test/integration/branchRebase/expected/repo/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 b/test/integration/branchRebase/expected/repo/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/69/f11ae88c8712fe38ffd0fe9ff9df05371500a6 b/test/integration/branchRebase/expected/repo/.git_keep/objects/69/f11ae88c8712fe38ffd0fe9ff9df05371500a6 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/69/f11ae88c8712fe38ffd0fe9ff9df05371500a6 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/69/f11ae88c8712fe38ffd0fe9ff9df05371500a6 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/70/95508e3cd0fd40572f8e711170db38ef2342d7 b/test/integration/branchRebase/expected/repo/.git_keep/objects/70/95508e3cd0fd40572f8e711170db38ef2342d7 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/70/95508e3cd0fd40572f8e711170db38ef2342d7 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/70/95508e3cd0fd40572f8e711170db38ef2342d7 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/7a/45b8933308e43f2597ee5d290862a62a9b46b3 b/test/integration/branchRebase/expected/repo/.git_keep/objects/7a/45b8933308e43f2597ee5d290862a62a9b46b3 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/7a/45b8933308e43f2597ee5d290862a62a9b46b3 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/7a/45b8933308e43f2597ee5d290862a62a9b46b3 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 b/test/integration/branchRebase/expected/repo/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/8c/7a45270a95d66c8e3b843df3f466be5dc19960 b/test/integration/branchRebase/expected/repo/.git_keep/objects/8c/7a45270a95d66c8e3b843df3f466be5dc19960 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/8c/7a45270a95d66c8e3b843df3f466be5dc19960 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/8c/7a45270a95d66c8e3b843df3f466be5dc19960 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/8d/3bd1cbd5560c759c78a948bc0d24acb9cfae73 b/test/integration/branchRebase/expected/repo/.git_keep/objects/8d/3bd1cbd5560c759c78a948bc0d24acb9cfae73 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/8d/3bd1cbd5560c759c78a948bc0d24acb9cfae73 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/8d/3bd1cbd5560c759c78a948bc0d24acb9cfae73 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/9a/6521a3788b4d9e679b1709130ff8dc3f73ab18 b/test/integration/branchRebase/expected/repo/.git_keep/objects/9a/6521a3788b4d9e679b1709130ff8dc3f73ab18 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/9a/6521a3788b4d9e679b1709130ff8dc3f73ab18 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/9a/6521a3788b4d9e679b1709130ff8dc3f73ab18 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 b/test/integration/branchRebase/expected/repo/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/branchRebase/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/a8/381c9130b03aef530b60b5a4546b93dc59ae12 b/test/integration/branchRebase/expected/repo/.git_keep/objects/a8/381c9130b03aef530b60b5a4546b93dc59ae12 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/a8/381c9130b03aef530b60b5a4546b93dc59ae12 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/a8/381c9130b03aef530b60b5a4546b93dc59ae12 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/cb/289e645aed5251ce74fa2eaf0cd1145b9cb014 b/test/integration/branchRebase/expected/repo/.git_keep/objects/cb/289e645aed5251ce74fa2eaf0cd1145b9cb014 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/cb/289e645aed5251ce74fa2eaf0cd1145b9cb014 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/cb/289e645aed5251ce74fa2eaf0cd1145b9cb014 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/cc/52f7d833c761b3b11a5fa1ae76ba9aba2edd6f b/test/integration/branchRebase/expected/repo/.git_keep/objects/cc/52f7d833c761b3b11a5fa1ae76ba9aba2edd6f similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/cc/52f7d833c761b3b11a5fa1ae76ba9aba2edd6f rename to test/integration/branchRebase/expected/repo/.git_keep/objects/cc/52f7d833c761b3b11a5fa1ae76ba9aba2edd6f diff --git a/test/integration/branchRebase/expected/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c b/test/integration/branchRebase/expected/repo/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c rename to test/integration/branchRebase/expected/repo/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c diff --git a/test/integration/branchRebase/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/branchRebase/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/branchRebase/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/branchRebase/expected/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e b/test/integration/branchRebase/expected/repo/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e rename to test/integration/branchRebase/expected/repo/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e diff --git a/test/integration/branchRebase/expected/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 b/test/integration/branchRebase/expected/repo/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/e9/57aaf2eef0c03a9052b472d4862d9ee684c3e5 b/test/integration/branchRebase/expected/repo/.git_keep/objects/e9/57aaf2eef0c03a9052b472d4862d9ee684c3e5 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/e9/57aaf2eef0c03a9052b472d4862d9ee684c3e5 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/e9/57aaf2eef0c03a9052b472d4862d9ee684c3e5 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 b/test/integration/branchRebase/expected/repo/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/f5/067da83b48f8588edce682fd2715a575f34373 b/test/integration/branchRebase/expected/repo/.git_keep/objects/f5/067da83b48f8588edce682fd2715a575f34373 similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/f5/067da83b48f8588edce682fd2715a575f34373 rename to test/integration/branchRebase/expected/repo/.git_keep/objects/f5/067da83b48f8588edce682fd2715a575f34373 diff --git a/test/integration/branchRebase/expected/.git_keep/objects/fe/427b52bbbe9dac81b463a162f37ab979ca772b b/test/integration/branchRebase/expected/repo/.git_keep/objects/fe/427b52bbbe9dac81b463a162f37ab979ca772b similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/objects/fe/427b52bbbe9dac81b463a162f37ab979ca772b rename to test/integration/branchRebase/expected/repo/.git_keep/objects/fe/427b52bbbe9dac81b463a162f37ab979ca772b diff --git a/test/integration/branchRebase/expected/.git_keep/refs/heads/develop b/test/integration/branchRebase/expected/repo/.git_keep/refs/heads/develop similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/refs/heads/develop rename to test/integration/branchRebase/expected/repo/.git_keep/refs/heads/develop diff --git a/test/integration/branchRebase/expected/.git_keep/refs/heads/master b/test/integration/branchRebase/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/branchRebase/expected/.git_keep/refs/heads/master rename to test/integration/branchRebase/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/branchRebase/expected/directory/file b/test/integration/branchRebase/expected/repo/directory/file similarity index 100% rename from test/integration/branchRebase/expected/directory/file rename to test/integration/branchRebase/expected/repo/directory/file diff --git a/test/integration/branchRebase/expected/directory/file2 b/test/integration/branchRebase/expected/repo/directory/file2 similarity index 100% rename from test/integration/branchRebase/expected/directory/file2 rename to test/integration/branchRebase/expected/repo/directory/file2 diff --git a/test/integration/branchRebase/expected/file1 b/test/integration/branchRebase/expected/repo/file1 similarity index 100% rename from test/integration/branchRebase/expected/file1 rename to test/integration/branchRebase/expected/repo/file1 diff --git a/test/integration/branchRebase/expected/file3 b/test/integration/branchRebase/expected/repo/file3 similarity index 100% rename from test/integration/branchRebase/expected/file3 rename to test/integration/branchRebase/expected/repo/file3 diff --git a/test/integration/branchRebase/expected/file4 b/test/integration/branchRebase/expected/repo/file4 similarity index 100% rename from test/integration/branchRebase/expected/file4 rename to test/integration/branchRebase/expected/repo/file4 diff --git a/test/integration/branchRebase/expected/file5 b/test/integration/branchRebase/expected/repo/file5 similarity index 100% rename from test/integration/branchRebase/expected/file5 rename to test/integration/branchRebase/expected/repo/file5 diff --git a/test/integration/branchReset/expected/.git_keep/COMMIT_EDITMSG b/test/integration/branchReset/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/branchReset/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/branchReset/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/branchReset/expected/.git_keep/FETCH_HEAD b/test/integration/branchReset/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/branchReset/expected/.git_keep/FETCH_HEAD rename to test/integration/branchReset/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/branchReset/expected/.git_keep/HEAD b/test/integration/branchReset/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/branchReset/expected/.git_keep/HEAD rename to test/integration/branchReset/expected/repo/.git_keep/HEAD diff --git a/test/integration/branchReset/expected/.git_keep/ORIG_HEAD b/test/integration/branchReset/expected/repo/.git_keep/ORIG_HEAD similarity index 100% rename from test/integration/branchReset/expected/.git_keep/ORIG_HEAD rename to test/integration/branchReset/expected/repo/.git_keep/ORIG_HEAD diff --git a/test/integration/branchReset/expected/.git_keep/config b/test/integration/branchReset/expected/repo/.git_keep/config similarity index 100% rename from test/integration/branchReset/expected/.git_keep/config rename to test/integration/branchReset/expected/repo/.git_keep/config diff --git a/test/integration/branchReset/expected/.git_keep/description b/test/integration/branchReset/expected/repo/.git_keep/description similarity index 100% rename from test/integration/branchReset/expected/.git_keep/description rename to test/integration/branchReset/expected/repo/.git_keep/description diff --git a/test/integration/branchReset/expected/.git_keep/index b/test/integration/branchReset/expected/repo/.git_keep/index similarity index 100% rename from test/integration/branchReset/expected/.git_keep/index rename to test/integration/branchReset/expected/repo/.git_keep/index diff --git a/test/integration/branchReset/expected/.git_keep/info/exclude b/test/integration/branchReset/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/branchReset/expected/.git_keep/info/exclude rename to test/integration/branchReset/expected/repo/.git_keep/info/exclude diff --git a/test/integration/branchReset/expected/.git_keep/logs/HEAD b/test/integration/branchReset/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/branchReset/expected/.git_keep/logs/HEAD rename to test/integration/branchReset/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/branchReset/expected/.git_keep/logs/refs/heads/develop b/test/integration/branchReset/expected/repo/.git_keep/logs/refs/heads/develop similarity index 100% rename from test/integration/branchReset/expected/.git_keep/logs/refs/heads/develop rename to test/integration/branchReset/expected/repo/.git_keep/logs/refs/heads/develop diff --git a/test/integration/branchReset/expected/.git_keep/logs/refs/heads/master b/test/integration/branchReset/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/branchReset/expected/.git_keep/logs/refs/heads/master rename to test/integration/branchReset/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/branchReset/expected/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d b/test/integration/branchReset/expected/repo/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d rename to test/integration/branchReset/expected/repo/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d diff --git a/test/integration/branchReset/expected/.git_keep/objects/10/6606554f129e8b6e4b942908734deef5628dcd b/test/integration/branchReset/expected/repo/.git_keep/objects/10/6606554f129e8b6e4b942908734deef5628dcd similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/10/6606554f129e8b6e4b942908734deef5628dcd rename to test/integration/branchReset/expected/repo/.git_keep/objects/10/6606554f129e8b6e4b942908734deef5628dcd diff --git a/test/integration/branchReset/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/branchReset/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/branchReset/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/branchReset/expected/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca b/test/integration/branchReset/expected/repo/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca rename to test/integration/branchReset/expected/repo/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca diff --git a/test/integration/branchReset/expected/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af b/test/integration/branchReset/expected/repo/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af rename to test/integration/branchReset/expected/repo/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af diff --git a/test/integration/branchReset/expected/.git_keep/objects/27/ba706fa463253f9189b2f258430877d2b5ed4f b/test/integration/branchReset/expected/repo/.git_keep/objects/27/ba706fa463253f9189b2f258430877d2b5ed4f similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/27/ba706fa463253f9189b2f258430877d2b5ed4f rename to test/integration/branchReset/expected/repo/.git_keep/objects/27/ba706fa463253f9189b2f258430877d2b5ed4f diff --git a/test/integration/branchReset/expected/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd b/test/integration/branchReset/expected/repo/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd rename to test/integration/branchReset/expected/repo/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd diff --git a/test/integration/branchReset/expected/.git_keep/objects/37/14b55ba17f3d8b0233c6e5924a5e497eb09bb7 b/test/integration/branchReset/expected/repo/.git_keep/objects/37/14b55ba17f3d8b0233c6e5924a5e497eb09bb7 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/37/14b55ba17f3d8b0233c6e5924a5e497eb09bb7 rename to test/integration/branchReset/expected/repo/.git_keep/objects/37/14b55ba17f3d8b0233c6e5924a5e497eb09bb7 diff --git a/test/integration/branchReset/expected/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 b/test/integration/branchReset/expected/repo/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 rename to test/integration/branchReset/expected/repo/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 diff --git a/test/integration/branchReset/expected/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 b/test/integration/branchReset/expected/repo/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 rename to test/integration/branchReset/expected/repo/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 diff --git a/test/integration/branchReset/expected/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 b/test/integration/branchReset/expected/repo/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 rename to test/integration/branchReset/expected/repo/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 diff --git a/test/integration/branchReset/expected/.git_keep/objects/7a/45b8933308e43f2597ee5d290862a62a9b46b3 b/test/integration/branchReset/expected/repo/.git_keep/objects/7a/45b8933308e43f2597ee5d290862a62a9b46b3 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/7a/45b8933308e43f2597ee5d290862a62a9b46b3 rename to test/integration/branchReset/expected/repo/.git_keep/objects/7a/45b8933308e43f2597ee5d290862a62a9b46b3 diff --git a/test/integration/branchReset/expected/.git_keep/objects/7c/d86f0c3e1894b4270d0bf9fa246c33568f9bf1 b/test/integration/branchReset/expected/repo/.git_keep/objects/7c/d86f0c3e1894b4270d0bf9fa246c33568f9bf1 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/7c/d86f0c3e1894b4270d0bf9fa246c33568f9bf1 rename to test/integration/branchReset/expected/repo/.git_keep/objects/7c/d86f0c3e1894b4270d0bf9fa246c33568f9bf1 diff --git a/test/integration/branchReset/expected/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 b/test/integration/branchReset/expected/repo/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 rename to test/integration/branchReset/expected/repo/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 diff --git a/test/integration/branchReset/expected/.git_keep/objects/8b/24e74245461f6ad529c77c040fe17e415cf3da b/test/integration/branchReset/expected/repo/.git_keep/objects/8b/24e74245461f6ad529c77c040fe17e415cf3da similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/8b/24e74245461f6ad529c77c040fe17e415cf3da rename to test/integration/branchReset/expected/repo/.git_keep/objects/8b/24e74245461f6ad529c77c040fe17e415cf3da diff --git a/test/integration/branchReset/expected/.git_keep/objects/8c/7a45270a95d66c8e3b843df3f466be5dc19960 b/test/integration/branchReset/expected/repo/.git_keep/objects/8c/7a45270a95d66c8e3b843df3f466be5dc19960 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/8c/7a45270a95d66c8e3b843df3f466be5dc19960 rename to test/integration/branchReset/expected/repo/.git_keep/objects/8c/7a45270a95d66c8e3b843df3f466be5dc19960 diff --git a/test/integration/branchReset/expected/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 b/test/integration/branchReset/expected/repo/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 rename to test/integration/branchReset/expected/repo/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 diff --git a/test/integration/branchReset/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/branchReset/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/branchReset/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/branchReset/expected/.git_keep/objects/a7/3e01f9d181ff16b3d821dd962e98accbd62936 b/test/integration/branchReset/expected/repo/.git_keep/objects/a7/3e01f9d181ff16b3d821dd962e98accbd62936 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/a7/3e01f9d181ff16b3d821dd962e98accbd62936 rename to test/integration/branchReset/expected/repo/.git_keep/objects/a7/3e01f9d181ff16b3d821dd962e98accbd62936 diff --git a/test/integration/branchReset/expected/.git_keep/objects/bd/8db1919bbbbd4509ad4d9fa3baf546460e17a2 b/test/integration/branchReset/expected/repo/.git_keep/objects/bd/8db1919bbbbd4509ad4d9fa3baf546460e17a2 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/bd/8db1919bbbbd4509ad4d9fa3baf546460e17a2 rename to test/integration/branchReset/expected/repo/.git_keep/objects/bd/8db1919bbbbd4509ad4d9fa3baf546460e17a2 diff --git a/test/integration/branchReset/expected/.git_keep/objects/c2/3c3e0496a9b3decc42344bfd94514f0834b93c b/test/integration/branchReset/expected/repo/.git_keep/objects/c2/3c3e0496a9b3decc42344bfd94514f0834b93c similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/c2/3c3e0496a9b3decc42344bfd94514f0834b93c rename to test/integration/branchReset/expected/repo/.git_keep/objects/c2/3c3e0496a9b3decc42344bfd94514f0834b93c diff --git a/test/integration/branchReset/expected/.git_keep/objects/cb/289e645aed5251ce74fa2eaf0cd1145b9cb014 b/test/integration/branchReset/expected/repo/.git_keep/objects/cb/289e645aed5251ce74fa2eaf0cd1145b9cb014 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/cb/289e645aed5251ce74fa2eaf0cd1145b9cb014 rename to test/integration/branchReset/expected/repo/.git_keep/objects/cb/289e645aed5251ce74fa2eaf0cd1145b9cb014 diff --git a/test/integration/branchReset/expected/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c b/test/integration/branchReset/expected/repo/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c rename to test/integration/branchReset/expected/repo/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c diff --git a/test/integration/branchReset/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/branchReset/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/branchReset/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/branchReset/expected/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e b/test/integration/branchReset/expected/repo/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e rename to test/integration/branchReset/expected/repo/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e diff --git a/test/integration/branchReset/expected/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 b/test/integration/branchReset/expected/repo/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 rename to test/integration/branchReset/expected/repo/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 diff --git a/test/integration/branchReset/expected/.git_keep/objects/ee/a0cf47f42fe8d027b4cecaf534ecc0673f7981 b/test/integration/branchReset/expected/repo/.git_keep/objects/ee/a0cf47f42fe8d027b4cecaf534ecc0673f7981 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/ee/a0cf47f42fe8d027b4cecaf534ecc0673f7981 rename to test/integration/branchReset/expected/repo/.git_keep/objects/ee/a0cf47f42fe8d027b4cecaf534ecc0673f7981 diff --git a/test/integration/branchReset/expected/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 b/test/integration/branchReset/expected/repo/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 rename to test/integration/branchReset/expected/repo/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 diff --git a/test/integration/branchReset/expected/.git_keep/objects/fe/427b52bbbe9dac81b463a162f37ab979ca772b b/test/integration/branchReset/expected/repo/.git_keep/objects/fe/427b52bbbe9dac81b463a162f37ab979ca772b similarity index 100% rename from test/integration/branchReset/expected/.git_keep/objects/fe/427b52bbbe9dac81b463a162f37ab979ca772b rename to test/integration/branchReset/expected/repo/.git_keep/objects/fe/427b52bbbe9dac81b463a162f37ab979ca772b diff --git a/test/integration/branchReset/expected/.git_keep/refs/heads/develop b/test/integration/branchReset/expected/repo/.git_keep/refs/heads/develop similarity index 100% rename from test/integration/branchReset/expected/.git_keep/refs/heads/develop rename to test/integration/branchReset/expected/repo/.git_keep/refs/heads/develop diff --git a/test/integration/branchReset/expected/.git_keep/refs/heads/master b/test/integration/branchReset/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/branchReset/expected/.git_keep/refs/heads/master rename to test/integration/branchReset/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/branchReset/expected/directory/file b/test/integration/branchReset/expected/repo/directory/file similarity index 100% rename from test/integration/branchReset/expected/directory/file rename to test/integration/branchReset/expected/repo/directory/file diff --git a/test/integration/branchReset/expected/directory/file2 b/test/integration/branchReset/expected/repo/directory/file2 similarity index 100% rename from test/integration/branchReset/expected/directory/file2 rename to test/integration/branchReset/expected/repo/directory/file2 diff --git a/test/integration/branchReset/expected/file1 b/test/integration/branchReset/expected/repo/file1 similarity index 100% rename from test/integration/branchReset/expected/file1 rename to test/integration/branchReset/expected/repo/file1 diff --git a/test/integration/branchReset/expected/file3 b/test/integration/branchReset/expected/repo/file3 similarity index 100% rename from test/integration/branchReset/expected/file3 rename to test/integration/branchReset/expected/repo/file3 diff --git a/test/integration/branchReset/expected/file4 b/test/integration/branchReset/expected/repo/file4 similarity index 100% rename from test/integration/branchReset/expected/file4 rename to test/integration/branchReset/expected/repo/file4 diff --git a/test/integration/branchReset/expected/file5 b/test/integration/branchReset/expected/repo/file5 similarity index 100% rename from test/integration/branchReset/expected/file5 rename to test/integration/branchReset/expected/repo/file5 diff --git a/test/integration/branchSuggestions/expected/.git_keep/COMMIT_EDITMSG b/test/integration/branchSuggestions/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/branchSuggestions/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/branchSuggestions/expected/.git_keep/FETCH_HEAD b/test/integration/branchSuggestions/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/FETCH_HEAD rename to test/integration/branchSuggestions/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/branchSuggestions/expected/.git_keep/HEAD b/test/integration/branchSuggestions/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/HEAD rename to test/integration/branchSuggestions/expected/repo/.git_keep/HEAD diff --git a/test/integration/branchSuggestions/expected/.git_keep/config b/test/integration/branchSuggestions/expected/repo/.git_keep/config similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/config rename to test/integration/branchSuggestions/expected/repo/.git_keep/config diff --git a/test/integration/branchSuggestions/expected/.git_keep/description b/test/integration/branchSuggestions/expected/repo/.git_keep/description similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/description rename to test/integration/branchSuggestions/expected/repo/.git_keep/description diff --git a/test/integration/branchSuggestions/expected/.git_keep/index b/test/integration/branchSuggestions/expected/repo/.git_keep/index similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/index rename to test/integration/branchSuggestions/expected/repo/.git_keep/index diff --git a/test/integration/branchSuggestions/expected/.git_keep/info/exclude b/test/integration/branchSuggestions/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/info/exclude rename to test/integration/branchSuggestions/expected/repo/.git_keep/info/exclude diff --git a/test/integration/branchSuggestions/expected/.git_keep/logs/HEAD b/test/integration/branchSuggestions/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/logs/HEAD rename to test/integration/branchSuggestions/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/master b/test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/master rename to test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/new-branch b/test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/new-branch similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/new-branch rename to test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/new-branch diff --git a/test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/new-branch-2 b/test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/new-branch-2 similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/new-branch-2 rename to test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/new-branch-2 diff --git a/test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/new-branch-3 b/test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/new-branch-3 similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/new-branch-3 rename to test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/new-branch-3 diff --git a/test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/old-branch b/test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/old-branch similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/old-branch rename to test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/old-branch diff --git a/test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/old-branch-2 b/test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/old-branch-2 similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/old-branch-2 rename to test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/old-branch-2 diff --git a/test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/old-branch-3 b/test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/old-branch-3 similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/logs/refs/heads/old-branch-3 rename to test/integration/branchSuggestions/expected/repo/.git_keep/logs/refs/heads/old-branch-3 diff --git a/test/integration/branchSuggestions/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 b/test/integration/branchSuggestions/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 rename to test/integration/branchSuggestions/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 diff --git a/test/integration/branchSuggestions/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da b/test/integration/branchSuggestions/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da rename to test/integration/branchSuggestions/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da diff --git a/test/integration/branchSuggestions/expected/.git_keep/objects/75/e9e90a1d58c37d97d46a543dfbfd0f33fc52d8 b/test/integration/branchSuggestions/expected/repo/.git_keep/objects/75/e9e90a1d58c37d97d46a543dfbfd0f33fc52d8 similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/objects/75/e9e90a1d58c37d97d46a543dfbfd0f33fc52d8 rename to test/integration/branchSuggestions/expected/repo/.git_keep/objects/75/e9e90a1d58c37d97d46a543dfbfd0f33fc52d8 diff --git a/test/integration/branchSuggestions/expected/.git_keep/refs/heads/master b/test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/refs/heads/master rename to test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/branchSuggestions/expected/.git_keep/refs/heads/new-branch b/test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/new-branch similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/refs/heads/new-branch rename to test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/new-branch diff --git a/test/integration/branchSuggestions/expected/.git_keep/refs/heads/new-branch-2 b/test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/new-branch-2 similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/refs/heads/new-branch-2 rename to test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/new-branch-2 diff --git a/test/integration/branchSuggestions/expected/.git_keep/refs/heads/new-branch-3 b/test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/new-branch-3 similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/refs/heads/new-branch-3 rename to test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/new-branch-3 diff --git a/test/integration/branchSuggestions/expected/.git_keep/refs/heads/old-branch b/test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/old-branch similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/refs/heads/old-branch rename to test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/old-branch diff --git a/test/integration/branchSuggestions/expected/.git_keep/refs/heads/old-branch-2 b/test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/old-branch-2 similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/refs/heads/old-branch-2 rename to test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/old-branch-2 diff --git a/test/integration/branchSuggestions/expected/.git_keep/refs/heads/old-branch-3 b/test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/old-branch-3 similarity index 100% rename from test/integration/branchSuggestions/expected/.git_keep/refs/heads/old-branch-3 rename to test/integration/branchSuggestions/expected/repo/.git_keep/refs/heads/old-branch-3 diff --git a/test/integration/branchSuggestions/expected/file0 b/test/integration/branchSuggestions/expected/repo/file0 similarity index 100% rename from test/integration/branchSuggestions/expected/file0 rename to test/integration/branchSuggestions/expected/repo/file0 diff --git a/test/integration/cherryPicking/expected/.git_keep/COMMIT_EDITMSG b/test/integration/cherryPicking/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/cherryPicking/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/cherryPicking/expected/.git_keep/FETCH_HEAD b/test/integration/cherryPicking/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/FETCH_HEAD rename to test/integration/cherryPicking/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/cherryPicking/expected/.git_keep/HEAD b/test/integration/cherryPicking/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/HEAD rename to test/integration/cherryPicking/expected/repo/.git_keep/HEAD diff --git a/test/integration/cherryPicking/expected/.git_keep/ORIG_HEAD b/test/integration/cherryPicking/expected/repo/.git_keep/ORIG_HEAD similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/ORIG_HEAD rename to test/integration/cherryPicking/expected/repo/.git_keep/ORIG_HEAD diff --git a/test/integration/cherryPicking/expected/.git_keep/REBASE_HEAD b/test/integration/cherryPicking/expected/repo/.git_keep/REBASE_HEAD similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/REBASE_HEAD rename to test/integration/cherryPicking/expected/repo/.git_keep/REBASE_HEAD diff --git a/test/integration/cherryPicking/expected/.git_keep/config b/test/integration/cherryPicking/expected/repo/.git_keep/config similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/config rename to test/integration/cherryPicking/expected/repo/.git_keep/config diff --git a/test/integration/cherryPicking/expected/.git_keep/description b/test/integration/cherryPicking/expected/repo/.git_keep/description similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/description rename to test/integration/cherryPicking/expected/repo/.git_keep/description diff --git a/test/integration/cherryPicking/expected/.git_keep/index b/test/integration/cherryPicking/expected/repo/.git_keep/index similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/index rename to test/integration/cherryPicking/expected/repo/.git_keep/index diff --git a/test/integration/cherryPicking/expected/.git_keep/info/exclude b/test/integration/cherryPicking/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/info/exclude rename to test/integration/cherryPicking/expected/repo/.git_keep/info/exclude diff --git a/test/integration/cherryPicking/expected/.git_keep/logs/HEAD b/test/integration/cherryPicking/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/logs/HEAD rename to test/integration/cherryPicking/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/cherryPicking/expected/.git_keep/logs/refs/heads/base_branch b/test/integration/cherryPicking/expected/repo/.git_keep/logs/refs/heads/base_branch similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/logs/refs/heads/base_branch rename to test/integration/cherryPicking/expected/repo/.git_keep/logs/refs/heads/base_branch diff --git a/test/integration/cherryPicking/expected/.git_keep/logs/refs/heads/develop b/test/integration/cherryPicking/expected/repo/.git_keep/logs/refs/heads/develop similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/logs/refs/heads/develop rename to test/integration/cherryPicking/expected/repo/.git_keep/logs/refs/heads/develop diff --git a/test/integration/cherryPicking/expected/.git_keep/logs/refs/heads/feature/cherry-picking b/test/integration/cherryPicking/expected/repo/.git_keep/logs/refs/heads/feature/cherry-picking similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/logs/refs/heads/feature/cherry-picking rename to test/integration/cherryPicking/expected/repo/.git_keep/logs/refs/heads/feature/cherry-picking diff --git a/test/integration/cherryPicking/expected/.git_keep/logs/refs/heads/master b/test/integration/cherryPicking/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/logs/refs/heads/master rename to test/integration/cherryPicking/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/cherryPicking/expected/.git_keep/logs/refs/heads/other_branch b/test/integration/cherryPicking/expected/repo/.git_keep/logs/refs/heads/other_branch similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/logs/refs/heads/other_branch rename to test/integration/cherryPicking/expected/repo/.git_keep/logs/refs/heads/other_branch diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/05/56e5da1cda4e150d6cc1182be6efdb061f59fe b/test/integration/cherryPicking/expected/repo/.git_keep/objects/05/56e5da1cda4e150d6cc1182be6efdb061f59fe similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/05/56e5da1cda4e150d6cc1182be6efdb061f59fe rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/05/56e5da1cda4e150d6cc1182be6efdb061f59fe diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d b/test/integration/cherryPicking/expected/repo/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/16/f2bcca6ce7bcc17277103a5555072a6c3322a2 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/16/f2bcca6ce7bcc17277103a5555072a6c3322a2 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/16/f2bcca6ce7bcc17277103a5555072a6c3322a2 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/16/f2bcca6ce7bcc17277103a5555072a6c3322a2 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c b/test/integration/cherryPicking/expected/repo/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/19/079c78db18112c5a2720896a040014a2d05f6d b/test/integration/cherryPicking/expected/repo/.git_keep/objects/19/079c78db18112c5a2720896a040014a2d05f6d similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/19/079c78db18112c5a2720896a040014a2d05f6d rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/19/079c78db18112c5a2720896a040014a2d05f6d diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca b/test/integration/cherryPicking/expected/repo/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/21/28c3c3def18d6e2a389957252fdb69ba85fce0 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/21/28c3c3def18d6e2a389957252fdb69ba85fce0 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/21/28c3c3def18d6e2a389957252fdb69ba85fce0 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/21/28c3c3def18d6e2a389957252fdb69ba85fce0 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af b/test/integration/cherryPicking/expected/repo/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/23/4e2fa9a01b8d7e849b0c2a1bbd550e788ea18d b/test/integration/cherryPicking/expected/repo/.git_keep/objects/23/4e2fa9a01b8d7e849b0c2a1bbd550e788ea18d similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/23/4e2fa9a01b8d7e849b0c2a1bbd550e788ea18d rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/23/4e2fa9a01b8d7e849b0c2a1bbd550e788ea18d diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/24/93c87610e0a9b8edfca592cb01a027f60ce587 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/24/93c87610e0a9b8edfca592cb01a027f60ce587 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/24/93c87610e0a9b8edfca592cb01a027f60ce587 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/24/93c87610e0a9b8edfca592cb01a027f60ce587 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/2c/f63d6da8c52131dd79622f8572b44a1267e420 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/2c/f63d6da8c52131dd79622f8572b44a1267e420 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/2c/f63d6da8c52131dd79622f8572b44a1267e420 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/2c/f63d6da8c52131dd79622f8572b44a1267e420 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/33/9e2d062760be9ecdb4bb90f97bdb0e634e7831 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/33/9e2d062760be9ecdb4bb90f97bdb0e634e7831 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/33/9e2d062760be9ecdb4bb90f97bdb0e634e7831 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/33/9e2d062760be9ecdb4bb90f97bdb0e634e7831 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd b/test/integration/cherryPicking/expected/repo/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c b/test/integration/cherryPicking/expected/repo/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/3e/0d4389ab458a8643281e494e3ebae7ce307eec b/test/integration/cherryPicking/expected/repo/.git_keep/objects/3e/0d4389ab458a8643281e494e3ebae7ce307eec similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/3e/0d4389ab458a8643281e494e3ebae7ce307eec rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/3e/0d4389ab458a8643281e494e3ebae7ce307eec diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/45/20f99d650662a3f597a200fea5f2599f528180 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/45/20f99d650662a3f597a200fea5f2599f528180 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/45/20f99d650662a3f597a200fea5f2599f528180 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/45/20f99d650662a3f597a200fea5f2599f528180 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/5d/2484f3cb6ce658e296526c48e1a376b2790dfc b/test/integration/cherryPicking/expected/repo/.git_keep/objects/5d/2484f3cb6ce658e296526c48e1a376b2790dfc similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/5d/2484f3cb6ce658e296526c48e1a376b2790dfc rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/5d/2484f3cb6ce658e296526c48e1a376b2790dfc diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/65/c0438e428cd1aa94588eaa52eb7ebad7ec62fd b/test/integration/cherryPicking/expected/repo/.git_keep/objects/65/c0438e428cd1aa94588eaa52eb7ebad7ec62fd similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/65/c0438e428cd1aa94588eaa52eb7ebad7ec62fd rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/65/c0438e428cd1aa94588eaa52eb7ebad7ec62fd diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/68/728b56ed31d03ca94496b9e2a45c62ba0f4e8f b/test/integration/cherryPicking/expected/repo/.git_keep/objects/68/728b56ed31d03ca94496b9e2a45c62ba0f4e8f similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/68/728b56ed31d03ca94496b9e2a45c62ba0f4e8f rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/68/728b56ed31d03ca94496b9e2a45c62ba0f4e8f diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/69/6a8fd43c580b3bed203977faab4566b052a4e4 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/69/6a8fd43c580b3bed203977faab4566b052a4e4 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/69/6a8fd43c580b3bed203977faab4566b052a4e4 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/69/6a8fd43c580b3bed203977faab4566b052a4e4 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/6b/6092c6840d05583489cc32a1260db0d5390a98 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/6b/6092c6840d05583489cc32a1260db0d5390a98 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/6b/6092c6840d05583489cc32a1260db0d5390a98 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/6b/6092c6840d05583489cc32a1260db0d5390a98 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/73/17cf7580efd92f974c8dfb3cde84eded8dafec b/test/integration/cherryPicking/expected/repo/.git_keep/objects/73/17cf7580efd92f974c8dfb3cde84eded8dafec similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/73/17cf7580efd92f974c8dfb3cde84eded8dafec rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/73/17cf7580efd92f974c8dfb3cde84eded8dafec diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/78/a5ec82970200538b70f5ac61c18acb45ccb8ee b/test/integration/cherryPicking/expected/repo/.git_keep/objects/78/a5ec82970200538b70f5ac61c18acb45ccb8ee similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/78/a5ec82970200538b70f5ac61c18acb45ccb8ee rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/78/a5ec82970200538b70f5ac61c18acb45ccb8ee diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/79/23e4a952f4b169373b0389be6a9db3cd929547 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/79/23e4a952f4b169373b0389be6a9db3cd929547 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/79/23e4a952f4b169373b0389be6a9db3cd929547 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/79/23e4a952f4b169373b0389be6a9db3cd929547 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d b/test/integration/cherryPicking/expected/repo/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd b/test/integration/cherryPicking/expected/repo/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c b/test/integration/cherryPicking/expected/repo/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/9b/b8cd97914c8e8a7b8a6ec6f94bca0b09fa0048 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/9b/b8cd97914c8e8a7b8a6ec6f94bca0b09fa0048 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/9b/b8cd97914c8e8a7b8a6ec6f94bca0b09fa0048 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/9b/b8cd97914c8e8a7b8a6ec6f94bca0b09fa0048 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c b/test/integration/cherryPicking/expected/repo/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/b8/ab98a9ab0599193a3f41a9cc5cb988283e6722 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/b8/ab98a9ab0599193a3f41a9cc5cb988283e6722 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/b8/ab98a9ab0599193a3f41a9cc5cb988283e6722 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/b8/ab98a9ab0599193a3f41a9cc5cb988283e6722 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/bd/6f34089ba29cbae102003bd973e9f37a235c2e b/test/integration/cherryPicking/expected/repo/.git_keep/objects/bd/6f34089ba29cbae102003bd973e9f37a235c2e similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/bd/6f34089ba29cbae102003bd973e9f37a235c2e rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/bd/6f34089ba29cbae102003bd973e9f37a235c2e diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/bf/cc5725cd2ef871ff804996f4e02beef3e4dec2 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/bf/cc5725cd2ef871ff804996f4e02beef3e4dec2 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/bf/cc5725cd2ef871ff804996f4e02beef3e4dec2 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/bf/cc5725cd2ef871ff804996f4e02beef3e4dec2 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/ce/ecbe69460104e09eb2cd7c865df520c5679a68 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/ce/ecbe69460104e09eb2cd7c865df520c5679a68 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/ce/ecbe69460104e09eb2cd7c865df520c5679a68 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/ce/ecbe69460104e09eb2cd7c865df520c5679a68 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/d8/e5ca46d2bbd7c115e5849e637efe2361203368 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/d8/e5ca46d2bbd7c115e5849e637efe2361203368 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/d8/e5ca46d2bbd7c115e5849e637efe2361203368 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/d8/e5ca46d2bbd7c115e5849e637efe2361203368 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c b/test/integration/cherryPicking/expected/repo/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/cherryPicking/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e b/test/integration/cherryPicking/expected/repo/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/e4/aa98b835d0a871d9ea02e6d286f0fbb2204cdc b/test/integration/cherryPicking/expected/repo/.git_keep/objects/e4/aa98b835d0a871d9ea02e6d286f0fbb2204cdc similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/e4/aa98b835d0a871d9ea02e6d286f0fbb2204cdc rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/e4/aa98b835d0a871d9ea02e6d286f0fbb2204cdc diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d b/test/integration/cherryPicking/expected/repo/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/ef/029771f117b5f31c972dfa546037662e243ca7 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/ef/029771f117b5f31c972dfa546037662e243ca7 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/ef/029771f117b5f31c972dfa546037662e243ca7 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/ef/029771f117b5f31c972dfa546037662e243ca7 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/f3/7d8713ef1390c277b45a084a08c0c142ff7ed9 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/f3/7d8713ef1390c277b45a084a08c0c142ff7ed9 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/f3/7d8713ef1390c277b45a084a08c0c142ff7ed9 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/f3/7d8713ef1390c277b45a084a08c0c142ff7ed9 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/f4/ffac820a371104fe611d81bc13a45b70a3ebb3 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/f4/ffac820a371104fe611d81bc13a45b70a3ebb3 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/f4/ffac820a371104fe611d81bc13a45b70a3ebb3 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/f4/ffac820a371104fe611d81bc13a45b70a3ebb3 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/fa/cb56c48e4718f71c08116153c93d87bc699671 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/fa/cb56c48e4718f71c08116153c93d87bc699671 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/fa/cb56c48e4718f71c08116153c93d87bc699671 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/fa/cb56c48e4718f71c08116153c93d87bc699671 diff --git a/test/integration/cherryPicking/expected/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 b/test/integration/cherryPicking/expected/repo/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 rename to test/integration/cherryPicking/expected/repo/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 diff --git a/test/integration/cherryPicking/expected/.git_keep/refs/heads/base_branch b/test/integration/cherryPicking/expected/repo/.git_keep/refs/heads/base_branch similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/refs/heads/base_branch rename to test/integration/cherryPicking/expected/repo/.git_keep/refs/heads/base_branch diff --git a/test/integration/cherryPicking/expected/.git_keep/refs/heads/develop b/test/integration/cherryPicking/expected/repo/.git_keep/refs/heads/develop similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/refs/heads/develop rename to test/integration/cherryPicking/expected/repo/.git_keep/refs/heads/develop diff --git a/test/integration/cherryPicking/expected/.git_keep/refs/heads/feature/cherry-picking b/test/integration/cherryPicking/expected/repo/.git_keep/refs/heads/feature/cherry-picking similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/refs/heads/feature/cherry-picking rename to test/integration/cherryPicking/expected/repo/.git_keep/refs/heads/feature/cherry-picking diff --git a/test/integration/cherryPicking/expected/.git_keep/refs/heads/master b/test/integration/cherryPicking/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/refs/heads/master rename to test/integration/cherryPicking/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/cherryPicking/expected/.git_keep/refs/heads/other_branch b/test/integration/cherryPicking/expected/repo/.git_keep/refs/heads/other_branch similarity index 100% rename from test/integration/cherryPicking/expected/.git_keep/refs/heads/other_branch rename to test/integration/cherryPicking/expected/repo/.git_keep/refs/heads/other_branch diff --git a/test/integration/cherryPicking/expected/cherrypicking3 b/test/integration/cherryPicking/expected/repo/cherrypicking3 similarity index 100% rename from test/integration/cherryPicking/expected/cherrypicking3 rename to test/integration/cherryPicking/expected/repo/cherrypicking3 diff --git a/test/integration/cherryPicking/expected/cherrypicking4 b/test/integration/cherryPicking/expected/repo/cherrypicking4 similarity index 100% rename from test/integration/cherryPicking/expected/cherrypicking4 rename to test/integration/cherryPicking/expected/repo/cherrypicking4 diff --git a/test/integration/cherryPicking/expected/cherrypicking5 b/test/integration/cherryPicking/expected/repo/cherrypicking5 similarity index 100% rename from test/integration/cherryPicking/expected/cherrypicking5 rename to test/integration/cherryPicking/expected/repo/cherrypicking5 diff --git a/test/integration/cherryPicking/expected/directory/file b/test/integration/cherryPicking/expected/repo/directory/file similarity index 100% rename from test/integration/cherryPicking/expected/directory/file rename to test/integration/cherryPicking/expected/repo/directory/file diff --git a/test/integration/cherryPicking/expected/directory/file2 b/test/integration/cherryPicking/expected/repo/directory/file2 similarity index 100% rename from test/integration/cherryPicking/expected/directory/file2 rename to test/integration/cherryPicking/expected/repo/directory/file2 diff --git a/test/integration/cherryPicking/expected/file b/test/integration/cherryPicking/expected/repo/file similarity index 100% rename from test/integration/cherryPicking/expected/file rename to test/integration/cherryPicking/expected/repo/file diff --git a/test/integration/cherryPicking/expected/file1 b/test/integration/cherryPicking/expected/repo/file1 similarity index 100% rename from test/integration/cherryPicking/expected/file1 rename to test/integration/cherryPicking/expected/repo/file1 diff --git a/test/integration/cherryPicking/expected/file3 b/test/integration/cherryPicking/expected/repo/file3 similarity index 100% rename from test/integration/cherryPicking/expected/file3 rename to test/integration/cherryPicking/expected/repo/file3 diff --git a/test/integration/cherryPicking/expected/file4 b/test/integration/cherryPicking/expected/repo/file4 similarity index 100% rename from test/integration/cherryPicking/expected/file4 rename to test/integration/cherryPicking/expected/repo/file4 diff --git a/test/integration/cherryPicking/expected/file5 b/test/integration/cherryPicking/expected/repo/file5 similarity index 100% rename from test/integration/cherryPicking/expected/file5 rename to test/integration/cherryPicking/expected/repo/file5 diff --git a/test/integration/commit/expected/.git_keep/COMMIT_EDITMSG b/test/integration/commit/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/commit/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/commit/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/commit/expected/.git_keep/FETCH_HEAD b/test/integration/commit/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/commit/expected/.git_keep/FETCH_HEAD rename to test/integration/commit/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/commit/expected/.git_keep/HEAD b/test/integration/commit/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/commit/expected/.git_keep/HEAD rename to test/integration/commit/expected/repo/.git_keep/HEAD diff --git a/test/integration/commit/expected/.git_keep/config b/test/integration/commit/expected/repo/.git_keep/config similarity index 100% rename from test/integration/commit/expected/.git_keep/config rename to test/integration/commit/expected/repo/.git_keep/config diff --git a/test/integration/commit/expected/.git_keep/description b/test/integration/commit/expected/repo/.git_keep/description similarity index 100% rename from test/integration/commit/expected/.git_keep/description rename to test/integration/commit/expected/repo/.git_keep/description diff --git a/test/integration/commit/expected/.git_keep/index b/test/integration/commit/expected/repo/.git_keep/index similarity index 100% rename from test/integration/commit/expected/.git_keep/index rename to test/integration/commit/expected/repo/.git_keep/index diff --git a/test/integration/commit/expected/.git_keep/info/exclude b/test/integration/commit/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/commit/expected/.git_keep/info/exclude rename to test/integration/commit/expected/repo/.git_keep/info/exclude diff --git a/test/integration/commit/expected/.git_keep/logs/HEAD b/test/integration/commit/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/commit/expected/.git_keep/logs/HEAD rename to test/integration/commit/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/commit/expected/.git_keep/logs/refs/heads/master b/test/integration/commit/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/commit/expected/.git_keep/logs/refs/heads/master rename to test/integration/commit/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/commit/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/commit/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/commit/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/commit/expected/.git_keep/objects/14/40bc6cc888a09dca2329d1060eec6de78d9d21 b/test/integration/commit/expected/repo/.git_keep/objects/14/40bc6cc888a09dca2329d1060eec6de78d9d21 similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/14/40bc6cc888a09dca2329d1060eec6de78d9d21 rename to test/integration/commit/expected/repo/.git_keep/objects/14/40bc6cc888a09dca2329d1060eec6de78d9d21 diff --git a/test/integration/commit/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/commit/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/commit/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/commit/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/commit/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce rename to test/integration/commit/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce diff --git a/test/integration/commit/expected/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 b/test/integration/commit/expected/repo/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 rename to test/integration/commit/expected/repo/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 diff --git a/test/integration/commit/expected/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be b/test/integration/commit/expected/repo/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be rename to test/integration/commit/expected/repo/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be diff --git a/test/integration/commit/expected/.git_keep/objects/3d/f3d8761bc0f0828596b11845aeac175b7b7393 b/test/integration/commit/expected/repo/.git_keep/objects/3d/f3d8761bc0f0828596b11845aeac175b7b7393 similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/3d/f3d8761bc0f0828596b11845aeac175b7b7393 rename to test/integration/commit/expected/repo/.git_keep/objects/3d/f3d8761bc0f0828596b11845aeac175b7b7393 diff --git a/test/integration/commit/expected/.git_keep/objects/4b/a4f1ed711a9081fab21bc222469aa5176a01f8 b/test/integration/commit/expected/repo/.git_keep/objects/4b/a4f1ed711a9081fab21bc222469aa5176a01f8 similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/4b/a4f1ed711a9081fab21bc222469aa5176a01f8 rename to test/integration/commit/expected/repo/.git_keep/objects/4b/a4f1ed711a9081fab21bc222469aa5176a01f8 diff --git a/test/integration/commit/expected/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f b/test/integration/commit/expected/repo/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f rename to test/integration/commit/expected/repo/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f diff --git a/test/integration/commit/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/commit/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/commit/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/commit/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 b/test/integration/commit/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 rename to test/integration/commit/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 diff --git a/test/integration/commit/expected/.git_keep/objects/a7/d53cc21fd53100f955377be379423b0e386274 b/test/integration/commit/expected/repo/.git_keep/objects/a7/d53cc21fd53100f955377be379423b0e386274 similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/a7/d53cc21fd53100f955377be379423b0e386274 rename to test/integration/commit/expected/repo/.git_keep/objects/a7/d53cc21fd53100f955377be379423b0e386274 diff --git a/test/integration/commit/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/commit/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename to test/integration/commit/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 diff --git a/test/integration/commit/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/commit/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/commit/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/commit/expected/.git_keep/objects/e7/560e2cd4783a261ad32496cefed2d9f69a46e7 b/test/integration/commit/expected/repo/.git_keep/objects/e7/560e2cd4783a261ad32496cefed2d9f69a46e7 similarity index 100% rename from test/integration/commit/expected/.git_keep/objects/e7/560e2cd4783a261ad32496cefed2d9f69a46e7 rename to test/integration/commit/expected/repo/.git_keep/objects/e7/560e2cd4783a261ad32496cefed2d9f69a46e7 diff --git a/test/integration/commit/expected/.git_keep/refs/heads/master b/test/integration/commit/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/commit/expected/.git_keep/refs/heads/master rename to test/integration/commit/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/commit/expected/myfile1 b/test/integration/commit/expected/repo/myfile1 similarity index 100% rename from test/integration/commit/expected/myfile1 rename to test/integration/commit/expected/repo/myfile1 diff --git a/test/integration/commit/expected/myfile2 b/test/integration/commit/expected/repo/myfile2 similarity index 100% rename from test/integration/commit/expected/myfile2 rename to test/integration/commit/expected/repo/myfile2 diff --git a/test/integration/commit/expected/myfile3 b/test/integration/commit/expected/repo/myfile3 similarity index 100% rename from test/integration/commit/expected/myfile3 rename to test/integration/commit/expected/repo/myfile3 diff --git a/test/integration/commit/expected/myfile4 b/test/integration/commit/expected/repo/myfile4 similarity index 100% rename from test/integration/commit/expected/myfile4 rename to test/integration/commit/expected/repo/myfile4 diff --git a/test/integration/commit/expected/myfile5 b/test/integration/commit/expected/repo/myfile5 similarity index 100% rename from test/integration/commit/expected/myfile5 rename to test/integration/commit/expected/repo/myfile5 diff --git a/test/integration/commitMultiline/expected/.git_keep/COMMIT_EDITMSG b/test/integration/commitMultiline/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/commitMultiline/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/commitMultiline/expected/.git_keep/FETCH_HEAD b/test/integration/commitMultiline/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/FETCH_HEAD rename to test/integration/commitMultiline/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/commitMultiline/expected/.git_keep/HEAD b/test/integration/commitMultiline/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/HEAD rename to test/integration/commitMultiline/expected/repo/.git_keep/HEAD diff --git a/test/integration/commitMultiline/expected/.git_keep/config b/test/integration/commitMultiline/expected/repo/.git_keep/config similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/config rename to test/integration/commitMultiline/expected/repo/.git_keep/config diff --git a/test/integration/commitMultiline/expected/.git_keep/description b/test/integration/commitMultiline/expected/repo/.git_keep/description similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/description rename to test/integration/commitMultiline/expected/repo/.git_keep/description diff --git a/test/integration/commitMultiline/expected/.git_keep/index b/test/integration/commitMultiline/expected/repo/.git_keep/index similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/index rename to test/integration/commitMultiline/expected/repo/.git_keep/index diff --git a/test/integration/commitMultiline/expected/.git_keep/info/exclude b/test/integration/commitMultiline/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/info/exclude rename to test/integration/commitMultiline/expected/repo/.git_keep/info/exclude diff --git a/test/integration/commitMultiline/expected/.git_keep/logs/HEAD b/test/integration/commitMultiline/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/logs/HEAD rename to test/integration/commitMultiline/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/commitMultiline/expected/.git_keep/logs/refs/heads/master b/test/integration/commitMultiline/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/logs/refs/heads/master rename to test/integration/commitMultiline/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/commitMultiline/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/17/6069f0ded1db43eecb3b629a6077dba6c68295 b/test/integration/commitMultiline/expected/repo/.git_keep/objects/17/6069f0ded1db43eecb3b629a6077dba6c68295 similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/17/6069f0ded1db43eecb3b629a6077dba6c68295 rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/17/6069f0ded1db43eecb3b629a6077dba6c68295 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/commitMultiline/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/commitMultiline/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 b/test/integration/commitMultiline/expected/repo/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be b/test/integration/commitMultiline/expected/repo/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/30/a1ca3481fdec3245b02aeacfb72ddfe2a433be diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/37/128a3020849daa0847462d14c384cc74c42ae0 b/test/integration/commitMultiline/expected/repo/.git_keep/objects/37/128a3020849daa0847462d14c384cc74c42ae0 similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/37/128a3020849daa0847462d14c384cc74c42ae0 rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/37/128a3020849daa0847462d14c384cc74c42ae0 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/39/33a268c502712421b7bfa04888319d6f108574 b/test/integration/commitMultiline/expected/repo/.git_keep/objects/39/33a268c502712421b7bfa04888319d6f108574 similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/39/33a268c502712421b7bfa04888319d6f108574 rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/39/33a268c502712421b7bfa04888319d6f108574 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f b/test/integration/commitMultiline/expected/repo/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/57/4013716a7f007a27b647b90cdbc78d006d792b b/test/integration/commitMultiline/expected/repo/.git_keep/objects/57/4013716a7f007a27b647b90cdbc78d006d792b similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/57/4013716a7f007a27b647b90cdbc78d006d792b rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/57/4013716a7f007a27b647b90cdbc78d006d792b diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/9f/1b5440546da24daad7014ccf3e1f4d81f9414b b/test/integration/commitMultiline/expected/repo/.git_keep/objects/9f/1b5440546da24daad7014ccf3e1f4d81f9414b similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/9f/1b5440546da24daad7014ccf3e1f4d81f9414b rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/9f/1b5440546da24daad7014ccf3e1f4d81f9414b diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/commitMultiline/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 b/test/integration/commitMultiline/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/commitMultiline/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 diff --git a/test/integration/commitMultiline/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/commitMultiline/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/commitMultiline/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/commitMultiline/expected/.git_keep/refs/heads/master b/test/integration/commitMultiline/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/commitMultiline/expected/.git_keep/refs/heads/master rename to test/integration/commitMultiline/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/commitMultiline/expected/myfile1 b/test/integration/commitMultiline/expected/repo/myfile1 similarity index 100% rename from test/integration/commitMultiline/expected/myfile1 rename to test/integration/commitMultiline/expected/repo/myfile1 diff --git a/test/integration/commitMultiline/expected/myfile2 b/test/integration/commitMultiline/expected/repo/myfile2 similarity index 100% rename from test/integration/commitMultiline/expected/myfile2 rename to test/integration/commitMultiline/expected/repo/myfile2 diff --git a/test/integration/commitMultiline/expected/myfile3 b/test/integration/commitMultiline/expected/repo/myfile3 similarity index 100% rename from test/integration/commitMultiline/expected/myfile3 rename to test/integration/commitMultiline/expected/repo/myfile3 diff --git a/test/integration/commitMultiline/expected/myfile4 b/test/integration/commitMultiline/expected/repo/myfile4 similarity index 100% rename from test/integration/commitMultiline/expected/myfile4 rename to test/integration/commitMultiline/expected/repo/myfile4 diff --git a/test/integration/commitMultiline/expected/myfile5 b/test/integration/commitMultiline/expected/repo/myfile5 similarity index 100% rename from test/integration/commitMultiline/expected/myfile5 rename to test/integration/commitMultiline/expected/repo/myfile5 diff --git a/test/integration/commitsNewBranch/expected/.git_keep/COMMIT_EDITMSG b/test/integration/commitsNewBranch/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/commitsNewBranch/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/commitsNewBranch/expected/.git_keep/FETCH_HEAD b/test/integration/commitsNewBranch/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/FETCH_HEAD rename to test/integration/commitsNewBranch/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/commitsNewBranch/expected/.git_keep/HEAD b/test/integration/commitsNewBranch/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/HEAD rename to test/integration/commitsNewBranch/expected/repo/.git_keep/HEAD diff --git a/test/integration/commitsNewBranch/expected/.git_keep/config b/test/integration/commitsNewBranch/expected/repo/.git_keep/config similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/config rename to test/integration/commitsNewBranch/expected/repo/.git_keep/config diff --git a/test/integration/commitsNewBranch/expected/.git_keep/description b/test/integration/commitsNewBranch/expected/repo/.git_keep/description similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/description rename to test/integration/commitsNewBranch/expected/repo/.git_keep/description diff --git a/test/integration/commitsNewBranch/expected/.git_keep/index b/test/integration/commitsNewBranch/expected/repo/.git_keep/index similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/index rename to test/integration/commitsNewBranch/expected/repo/.git_keep/index diff --git a/test/integration/commitsNewBranch/expected/.git_keep/info/exclude b/test/integration/commitsNewBranch/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/info/exclude rename to test/integration/commitsNewBranch/expected/repo/.git_keep/info/exclude diff --git a/test/integration/commitsNewBranch/expected/.git_keep/logs/HEAD b/test/integration/commitsNewBranch/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/logs/HEAD rename to test/integration/commitsNewBranch/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/commitsNewBranch/expected/.git_keep/logs/refs/heads/lol b/test/integration/commitsNewBranch/expected/repo/.git_keep/logs/refs/heads/lol similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/logs/refs/heads/lol rename to test/integration/commitsNewBranch/expected/repo/.git_keep/logs/refs/heads/lol diff --git a/test/integration/commitsNewBranch/expected/.git_keep/logs/refs/heads/master b/test/integration/commitsNewBranch/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/logs/refs/heads/master rename to test/integration/commitsNewBranch/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/commitsNewBranch/expected/.git_keep/objects/00/29f9bf66e346d47ede6a501abb5b82bee60096 b/test/integration/commitsNewBranch/expected/repo/.git_keep/objects/00/29f9bf66e346d47ede6a501abb5b82bee60096 similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/objects/00/29f9bf66e346d47ede6a501abb5b82bee60096 rename to test/integration/commitsNewBranch/expected/repo/.git_keep/objects/00/29f9bf66e346d47ede6a501abb5b82bee60096 diff --git a/test/integration/commitsNewBranch/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/commitsNewBranch/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/commitsNewBranch/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/commitsNewBranch/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 b/test/integration/commitsNewBranch/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 rename to test/integration/commitsNewBranch/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 diff --git a/test/integration/commitsNewBranch/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da b/test/integration/commitsNewBranch/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da rename to test/integration/commitsNewBranch/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da diff --git a/test/integration/commitsNewBranch/expected/.git_keep/objects/99/01fd9b7766be600bed07f55f1794a759527a98 b/test/integration/commitsNewBranch/expected/repo/.git_keep/objects/99/01fd9b7766be600bed07f55f1794a759527a98 similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/objects/99/01fd9b7766be600bed07f55f1794a759527a98 rename to test/integration/commitsNewBranch/expected/repo/.git_keep/objects/99/01fd9b7766be600bed07f55f1794a759527a98 diff --git a/test/integration/commitsNewBranch/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c b/test/integration/commitsNewBranch/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c rename to test/integration/commitsNewBranch/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c diff --git a/test/integration/commitsNewBranch/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/commitsNewBranch/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/commitsNewBranch/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/commitsNewBranch/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 b/test/integration/commitsNewBranch/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 rename to test/integration/commitsNewBranch/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 diff --git a/test/integration/commitsNewBranch/expected/.git_keep/objects/e1/cb250774fb8606d33062518d0ae03831130249 b/test/integration/commitsNewBranch/expected/repo/.git_keep/objects/e1/cb250774fb8606d33062518d0ae03831130249 similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/objects/e1/cb250774fb8606d33062518d0ae03831130249 rename to test/integration/commitsNewBranch/expected/repo/.git_keep/objects/e1/cb250774fb8606d33062518d0ae03831130249 diff --git a/test/integration/commitsNewBranch/expected/.git_keep/refs/heads/lol b/test/integration/commitsNewBranch/expected/repo/.git_keep/refs/heads/lol similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/refs/heads/lol rename to test/integration/commitsNewBranch/expected/repo/.git_keep/refs/heads/lol diff --git a/test/integration/commitsNewBranch/expected/.git_keep/refs/heads/master b/test/integration/commitsNewBranch/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/commitsNewBranch/expected/.git_keep/refs/heads/master rename to test/integration/commitsNewBranch/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/commitsNewBranch/expected/file0 b/test/integration/commitsNewBranch/expected/repo/file0 similarity index 100% rename from test/integration/commitsNewBranch/expected/file0 rename to test/integration/commitsNewBranch/expected/repo/file0 diff --git a/test/integration/commitsNewBranch/expected/file1 b/test/integration/commitsNewBranch/expected/repo/file1 similarity index 100% rename from test/integration/commitsNewBranch/expected/file1 rename to test/integration/commitsNewBranch/expected/repo/file1 diff --git a/test/integration/commitsRevert/expected/.git_keep/COMMIT_EDITMSG b/test/integration/commitsRevert/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/commitsRevert/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/commitsRevert/expected/.git_keep/FETCH_HEAD b/test/integration/commitsRevert/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/FETCH_HEAD rename to test/integration/commitsRevert/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/commitsRevert/expected/.git_keep/HEAD b/test/integration/commitsRevert/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/HEAD rename to test/integration/commitsRevert/expected/repo/.git_keep/HEAD diff --git a/test/integration/commitsRevert/expected/.git_keep/config b/test/integration/commitsRevert/expected/repo/.git_keep/config similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/config rename to test/integration/commitsRevert/expected/repo/.git_keep/config diff --git a/test/integration/commitsRevert/expected/.git_keep/description b/test/integration/commitsRevert/expected/repo/.git_keep/description similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/description rename to test/integration/commitsRevert/expected/repo/.git_keep/description diff --git a/test/integration/commitsRevert/expected/.git_keep/index b/test/integration/commitsRevert/expected/repo/.git_keep/index similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/index rename to test/integration/commitsRevert/expected/repo/.git_keep/index diff --git a/test/integration/commitsRevert/expected/.git_keep/info/exclude b/test/integration/commitsRevert/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/info/exclude rename to test/integration/commitsRevert/expected/repo/.git_keep/info/exclude diff --git a/test/integration/commitsRevert/expected/.git_keep/logs/HEAD b/test/integration/commitsRevert/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/logs/HEAD rename to test/integration/commitsRevert/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/commitsRevert/expected/.git_keep/logs/refs/heads/master b/test/integration/commitsRevert/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/logs/refs/heads/master rename to test/integration/commitsRevert/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/commitsRevert/expected/.git_keep/objects/17/27eeb6864e52a8967a1a494099359dbdfcc235 b/test/integration/commitsRevert/expected/repo/.git_keep/objects/17/27eeb6864e52a8967a1a494099359dbdfcc235 similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/objects/17/27eeb6864e52a8967a1a494099359dbdfcc235 rename to test/integration/commitsRevert/expected/repo/.git_keep/objects/17/27eeb6864e52a8967a1a494099359dbdfcc235 diff --git a/test/integration/commitsRevert/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/commitsRevert/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/commitsRevert/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/commitsRevert/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 b/test/integration/commitsRevert/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 rename to test/integration/commitsRevert/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 diff --git a/test/integration/commitsRevert/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da b/test/integration/commitsRevert/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da rename to test/integration/commitsRevert/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da diff --git a/test/integration/commitsRevert/expected/.git_keep/objects/3a/1ee58e5736049ad5b9266715d3642614816c1f b/test/integration/commitsRevert/expected/repo/.git_keep/objects/3a/1ee58e5736049ad5b9266715d3642614816c1f similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/objects/3a/1ee58e5736049ad5b9266715d3642614816c1f rename to test/integration/commitsRevert/expected/repo/.git_keep/objects/3a/1ee58e5736049ad5b9266715d3642614816c1f diff --git a/test/integration/commitsRevert/expected/.git_keep/objects/7e/03c9a9538a907c936de5c9a2154707b9ee541c b/test/integration/commitsRevert/expected/repo/.git_keep/objects/7e/03c9a9538a907c936de5c9a2154707b9ee541c similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/objects/7e/03c9a9538a907c936de5c9a2154707b9ee541c rename to test/integration/commitsRevert/expected/repo/.git_keep/objects/7e/03c9a9538a907c936de5c9a2154707b9ee541c diff --git a/test/integration/commitsRevert/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c b/test/integration/commitsRevert/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c rename to test/integration/commitsRevert/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c diff --git a/test/integration/commitsRevert/expected/.git_keep/objects/9e/aae8f342ca71c060b760870a715a6303905935 b/test/integration/commitsRevert/expected/repo/.git_keep/objects/9e/aae8f342ca71c060b760870a715a6303905935 similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/objects/9e/aae8f342ca71c060b760870a715a6303905935 rename to test/integration/commitsRevert/expected/repo/.git_keep/objects/9e/aae8f342ca71c060b760870a715a6303905935 diff --git a/test/integration/commitsRevert/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/commitsRevert/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/commitsRevert/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/commitsRevert/expected/.git_keep/objects/ab/15072795e72a2061bc40060494c3ca2138b297 b/test/integration/commitsRevert/expected/repo/.git_keep/objects/ab/15072795e72a2061bc40060494c3ca2138b297 similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/objects/ab/15072795e72a2061bc40060494c3ca2138b297 rename to test/integration/commitsRevert/expected/repo/.git_keep/objects/ab/15072795e72a2061bc40060494c3ca2138b297 diff --git a/test/integration/commitsRevert/expected/.git_keep/objects/b7/81ffd3aa940dde39f73c9149b67e2b128de085 b/test/integration/commitsRevert/expected/repo/.git_keep/objects/b7/81ffd3aa940dde39f73c9149b67e2b128de085 similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/objects/b7/81ffd3aa940dde39f73c9149b67e2b128de085 rename to test/integration/commitsRevert/expected/repo/.git_keep/objects/b7/81ffd3aa940dde39f73c9149b67e2b128de085 diff --git a/test/integration/commitsRevert/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 b/test/integration/commitsRevert/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 rename to test/integration/commitsRevert/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 diff --git a/test/integration/commitsRevert/expected/.git_keep/refs/heads/master b/test/integration/commitsRevert/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/commitsRevert/expected/.git_keep/refs/heads/master rename to test/integration/commitsRevert/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/commitsRevert/expected/file0 b/test/integration/commitsRevert/expected/repo/file0 similarity index 100% rename from test/integration/commitsRevert/expected/file0 rename to test/integration/commitsRevert/expected/repo/file0 diff --git a/test/integration/commitsRevert/expected/file2 b/test/integration/commitsRevert/expected/repo/file2 similarity index 100% rename from test/integration/commitsRevert/expected/file2 rename to test/integration/commitsRevert/expected/repo/file2 diff --git a/test/integration/confirmQuit/expected/.git_keep/COMMIT_EDITMSG b/test/integration/confirmQuit/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/confirmQuit/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/confirmQuit/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/confirmQuit/expected/.git_keep/FETCH_HEAD b/test/integration/confirmQuit/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/confirmQuit/expected/.git_keep/FETCH_HEAD rename to test/integration/confirmQuit/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/confirmQuit/expected/.git_keep/HEAD b/test/integration/confirmQuit/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/confirmQuit/expected/.git_keep/HEAD rename to test/integration/confirmQuit/expected/repo/.git_keep/HEAD diff --git a/test/integration/confirmQuit/expected/.git_keep/config b/test/integration/confirmQuit/expected/repo/.git_keep/config similarity index 100% rename from test/integration/confirmQuit/expected/.git_keep/config rename to test/integration/confirmQuit/expected/repo/.git_keep/config diff --git a/test/integration/confirmQuit/expected/.git_keep/description b/test/integration/confirmQuit/expected/repo/.git_keep/description similarity index 100% rename from test/integration/confirmQuit/expected/.git_keep/description rename to test/integration/confirmQuit/expected/repo/.git_keep/description diff --git a/test/integration/confirmQuit/expected/.git_keep/index b/test/integration/confirmQuit/expected/repo/.git_keep/index similarity index 100% rename from test/integration/confirmQuit/expected/.git_keep/index rename to test/integration/confirmQuit/expected/repo/.git_keep/index diff --git a/test/integration/confirmQuit/expected/.git_keep/info/exclude b/test/integration/confirmQuit/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/confirmQuit/expected/.git_keep/info/exclude rename to test/integration/confirmQuit/expected/repo/.git_keep/info/exclude diff --git a/test/integration/confirmQuit/expected/.git_keep/logs/HEAD b/test/integration/confirmQuit/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/confirmQuit/expected/.git_keep/logs/HEAD rename to test/integration/confirmQuit/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/confirmQuit/expected/.git_keep/logs/refs/heads/master b/test/integration/confirmQuit/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/confirmQuit/expected/.git_keep/logs/refs/heads/master rename to test/integration/confirmQuit/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/confirmQuit/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/confirmQuit/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/confirmQuit/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/confirmQuit/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/confirmQuit/expected/.git_keep/objects/54/4efed4e669ec3bd64b44799175bffac95035f5 b/test/integration/confirmQuit/expected/repo/.git_keep/objects/54/4efed4e669ec3bd64b44799175bffac95035f5 similarity index 100% rename from test/integration/confirmQuit/expected/.git_keep/objects/54/4efed4e669ec3bd64b44799175bffac95035f5 rename to test/integration/confirmQuit/expected/repo/.git_keep/objects/54/4efed4e669ec3bd64b44799175bffac95035f5 diff --git a/test/integration/confirmQuit/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/confirmQuit/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/confirmQuit/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/confirmQuit/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/confirmQuit/expected/.git_keep/refs/heads/master b/test/integration/confirmQuit/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/confirmQuit/expected/.git_keep/refs/heads/master rename to test/integration/confirmQuit/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/confirmQuit/expected/myfile1 b/test/integration/confirmQuit/expected/repo/myfile1 similarity index 100% rename from test/integration/confirmQuit/expected/myfile1 rename to test/integration/confirmQuit/expected/repo/myfile1 diff --git a/test/integration/customCommands/expected/.git_keep/COMMIT_EDITMSG b/test/integration/customCommands/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/customCommands/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/customCommands/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/customCommands/expected/.git_keep/FETCH_HEAD b/test/integration/customCommands/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/customCommands/expected/.git_keep/FETCH_HEAD rename to test/integration/customCommands/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/customCommands/expected/.git_keep/HEAD b/test/integration/customCommands/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/customCommands/expected/.git_keep/HEAD rename to test/integration/customCommands/expected/repo/.git_keep/HEAD diff --git a/test/integration/customCommands/expected/.git_keep/config b/test/integration/customCommands/expected/repo/.git_keep/config similarity index 100% rename from test/integration/customCommands/expected/.git_keep/config rename to test/integration/customCommands/expected/repo/.git_keep/config diff --git a/test/integration/customCommands/expected/.git_keep/description b/test/integration/customCommands/expected/repo/.git_keep/description similarity index 100% rename from test/integration/customCommands/expected/.git_keep/description rename to test/integration/customCommands/expected/repo/.git_keep/description diff --git a/test/integration/customCommands/expected/.git_keep/index b/test/integration/customCommands/expected/repo/.git_keep/index similarity index 100% rename from test/integration/customCommands/expected/.git_keep/index rename to test/integration/customCommands/expected/repo/.git_keep/index diff --git a/test/integration/customCommands/expected/.git_keep/info/exclude b/test/integration/customCommands/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/customCommands/expected/.git_keep/info/exclude rename to test/integration/customCommands/expected/repo/.git_keep/info/exclude diff --git a/test/integration/customCommands/expected/.git_keep/logs/HEAD b/test/integration/customCommands/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/customCommands/expected/.git_keep/logs/HEAD rename to test/integration/customCommands/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/customCommands/expected/.git_keep/logs/refs/heads/master b/test/integration/customCommands/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/customCommands/expected/.git_keep/logs/refs/heads/master rename to test/integration/customCommands/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/customCommands/expected/.git_keep/objects/15/bdb2c31c825116ad5af06ee25517d90b24f13b b/test/integration/customCommands/expected/repo/.git_keep/objects/15/bdb2c31c825116ad5af06ee25517d90b24f13b similarity index 100% rename from test/integration/customCommands/expected/.git_keep/objects/15/bdb2c31c825116ad5af06ee25517d90b24f13b rename to test/integration/customCommands/expected/repo/.git_keep/objects/15/bdb2c31c825116ad5af06ee25517d90b24f13b diff --git a/test/integration/customCommands/expected/.git_keep/objects/20/f11a5545b04a86ca81f7a9967d5207349052d7 b/test/integration/customCommands/expected/repo/.git_keep/objects/20/f11a5545b04a86ca81f7a9967d5207349052d7 similarity index 100% rename from test/integration/customCommands/expected/.git_keep/objects/20/f11a5545b04a86ca81f7a9967d5207349052d7 rename to test/integration/customCommands/expected/repo/.git_keep/objects/20/f11a5545b04a86ca81f7a9967d5207349052d7 diff --git a/test/integration/customCommands/expected/.git_keep/objects/8a/2e45643093ea7cf7b06382e38470034c24e812 b/test/integration/customCommands/expected/repo/.git_keep/objects/8a/2e45643093ea7cf7b06382e38470034c24e812 similarity index 100% rename from test/integration/customCommands/expected/.git_keep/objects/8a/2e45643093ea7cf7b06382e38470034c24e812 rename to test/integration/customCommands/expected/repo/.git_keep/objects/8a/2e45643093ea7cf7b06382e38470034c24e812 diff --git a/test/integration/customCommands/expected/.git_keep/refs/heads/master b/test/integration/customCommands/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/customCommands/expected/.git_keep/refs/heads/master rename to test/integration/customCommands/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/customCommands/expected/blah b/test/integration/customCommands/expected/repo/blah similarity index 100% rename from test/integration/customCommands/expected/blah rename to test/integration/customCommands/expected/repo/blah diff --git a/test/integration/customCommandsComplex/expected/.git_keep/COMMIT_EDITMSG b/test/integration/customCommandsComplex/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/customCommandsComplex/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/customCommandsComplex/expected/.git_keep/FETCH_HEAD b/test/integration/customCommandsComplex/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/FETCH_HEAD rename to test/integration/customCommandsComplex/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/customCommandsComplex/expected/.git_keep/HEAD b/test/integration/customCommandsComplex/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/HEAD rename to test/integration/customCommandsComplex/expected/repo/.git_keep/HEAD diff --git a/test/integration/customCommandsComplex/expected/.git_keep/config b/test/integration/customCommandsComplex/expected/repo/.git_keep/config similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/config rename to test/integration/customCommandsComplex/expected/repo/.git_keep/config diff --git a/test/integration/customCommandsComplex/expected/.git_keep/description b/test/integration/customCommandsComplex/expected/repo/.git_keep/description similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/description rename to test/integration/customCommandsComplex/expected/repo/.git_keep/description diff --git a/test/integration/customCommandsComplex/expected/.git_keep/index b/test/integration/customCommandsComplex/expected/repo/.git_keep/index similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/index rename to test/integration/customCommandsComplex/expected/repo/.git_keep/index diff --git a/test/integration/customCommandsComplex/expected/.git_keep/info/exclude b/test/integration/customCommandsComplex/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/info/exclude rename to test/integration/customCommandsComplex/expected/repo/.git_keep/info/exclude diff --git a/test/integration/customCommandsComplex/expected/.git_keep/logs/HEAD b/test/integration/customCommandsComplex/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/logs/HEAD rename to test/integration/customCommandsComplex/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/customCommandsComplex/expected/.git_keep/logs/refs/heads/master b/test/integration/customCommandsComplex/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/logs/refs/heads/master rename to test/integration/customCommandsComplex/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/05/3cf208ac3728c36c6ed86f2a03a1fb72a8e6bc b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/05/3cf208ac3728c36c6ed86f2a03a1fb72a8e6bc similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/05/3cf208ac3728c36c6ed86f2a03a1fb72a8e6bc rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/05/3cf208ac3728c36c6ed86f2a03a1fb72a8e6bc diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/4f/dfedfd9d406506be8b02f5b863dbc08d43cc9f b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/4f/dfedfd9d406506be8b02f5b863dbc08d43cc9f similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/4f/dfedfd9d406506be8b02f5b863dbc08d43cc9f rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/4f/dfedfd9d406506be8b02f5b863dbc08d43cc9f diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/54/28838691c97ac192c8b8e1c3f573d8541a94b6 b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/54/28838691c97ac192c8b8e1c3f573d8541a94b6 similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/54/28838691c97ac192c8b8e1c3f573d8541a94b6 rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/54/28838691c97ac192c8b8e1c3f573d8541a94b6 diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/7d/b446a082f8c10183f1f27178698f07f3750b6b b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/7d/b446a082f8c10183f1f27178698f07f3750b6b similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/7d/b446a082f8c10183f1f27178698f07f3750b6b rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/7d/b446a082f8c10183f1f27178698f07f3750b6b diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/7d/d93a4be3d27d40fbe791d6d77e0d2fedc4d785 b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/7d/d93a4be3d27d40fbe791d6d77e0d2fedc4d785 similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/7d/d93a4be3d27d40fbe791d6d77e0d2fedc4d785 rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/7d/d93a4be3d27d40fbe791d6d77e0d2fedc4d785 diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/ab/38b1ca116f77648925d952e731f419db360cdb b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/ab/38b1ca116f77648925d952e731f419db360cdb similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/ab/38b1ca116f77648925d952e731f419db360cdb rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/ab/38b1ca116f77648925d952e731f419db360cdb diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/customCommandsComplex/expected/.git_keep/objects/f7/08d3e3819470a69f6c8562ff1e68eef02f8cac b/test/integration/customCommandsComplex/expected/repo/.git_keep/objects/f7/08d3e3819470a69f6c8562ff1e68eef02f8cac similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/objects/f7/08d3e3819470a69f6c8562ff1e68eef02f8cac rename to test/integration/customCommandsComplex/expected/repo/.git_keep/objects/f7/08d3e3819470a69f6c8562ff1e68eef02f8cac diff --git a/test/integration/customCommandsComplex/expected/.git_keep/refs/heads/master b/test/integration/customCommandsComplex/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/customCommandsComplex/expected/.git_keep/refs/heads/master rename to test/integration/customCommandsComplex/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/customCommandsComplex/expected/myfile1 b/test/integration/customCommandsComplex/expected/repo/myfile1 similarity index 100% rename from test/integration/customCommandsComplex/expected/myfile1 rename to test/integration/customCommandsComplex/expected/repo/myfile1 diff --git a/test/integration/customCommandsComplex/expected/myfile2 b/test/integration/customCommandsComplex/expected/repo/myfile2 similarity index 100% rename from test/integration/customCommandsComplex/expected/myfile2 rename to test/integration/customCommandsComplex/expected/repo/myfile2 diff --git a/test/integration/customCommandsComplex/expected/myfile3 b/test/integration/customCommandsComplex/expected/repo/myfile3 similarity index 100% rename from test/integration/customCommandsComplex/expected/myfile3 rename to test/integration/customCommandsComplex/expected/repo/myfile3 diff --git a/test/integration/customCommandsComplex/expected/myfile4 b/test/integration/customCommandsComplex/expected/repo/myfile4 similarity index 100% rename from test/integration/customCommandsComplex/expected/myfile4 rename to test/integration/customCommandsComplex/expected/repo/myfile4 diff --git a/test/integration/customCommandsComplex/expected/output.txt b/test/integration/customCommandsComplex/expected/repo/output.txt similarity index 100% rename from test/integration/customCommandsComplex/expected/output.txt rename to test/integration/customCommandsComplex/expected/repo/output.txt diff --git a/test/integration/diffing/expected/.git_keep/COMMIT_EDITMSG b/test/integration/diffing/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/diffing/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/diffing/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/diffing/expected/.git_keep/FETCH_HEAD b/test/integration/diffing/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/diffing/expected/.git_keep/FETCH_HEAD rename to test/integration/diffing/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/diffing/expected/.git_keep/HEAD b/test/integration/diffing/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/diffing/expected/.git_keep/HEAD rename to test/integration/diffing/expected/repo/.git_keep/HEAD diff --git a/test/integration/diffing/expected/.git_keep/config b/test/integration/diffing/expected/repo/.git_keep/config similarity index 100% rename from test/integration/diffing/expected/.git_keep/config rename to test/integration/diffing/expected/repo/.git_keep/config diff --git a/test/integration/diffing/expected/.git_keep/description b/test/integration/diffing/expected/repo/.git_keep/description similarity index 100% rename from test/integration/diffing/expected/.git_keep/description rename to test/integration/diffing/expected/repo/.git_keep/description diff --git a/test/integration/diffing/expected/.git_keep/index b/test/integration/diffing/expected/repo/.git_keep/index similarity index 100% rename from test/integration/diffing/expected/.git_keep/index rename to test/integration/diffing/expected/repo/.git_keep/index diff --git a/test/integration/diffing/expected/.git_keep/info/exclude b/test/integration/diffing/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/diffing/expected/.git_keep/info/exclude rename to test/integration/diffing/expected/repo/.git_keep/info/exclude diff --git a/test/integration/diffing/expected/.git_keep/logs/HEAD b/test/integration/diffing/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/diffing/expected/.git_keep/logs/HEAD rename to test/integration/diffing/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/diffing/expected/.git_keep/logs/refs/heads/branch2 b/test/integration/diffing/expected/repo/.git_keep/logs/refs/heads/branch2 similarity index 100% rename from test/integration/diffing/expected/.git_keep/logs/refs/heads/branch2 rename to test/integration/diffing/expected/repo/.git_keep/logs/refs/heads/branch2 diff --git a/test/integration/diffing/expected/.git_keep/logs/refs/heads/master b/test/integration/diffing/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/diffing/expected/.git_keep/logs/refs/heads/master rename to test/integration/diffing/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/diffing/expected/.git_keep/objects/05/19814b4923f4639f1a47348b1539e3c5c54904 b/test/integration/diffing/expected/repo/.git_keep/objects/05/19814b4923f4639f1a47348b1539e3c5c54904 similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/05/19814b4923f4639f1a47348b1539e3c5c54904 rename to test/integration/diffing/expected/repo/.git_keep/objects/05/19814b4923f4639f1a47348b1539e3c5c54904 diff --git a/test/integration/diffing/expected/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 b/test/integration/diffing/expected/repo/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 rename to test/integration/diffing/expected/repo/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 diff --git a/test/integration/diffing/expected/.git_keep/objects/14/4da8a531224129210249f43dded86056891506 b/test/integration/diffing/expected/repo/.git_keep/objects/14/4da8a531224129210249f43dded86056891506 similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/14/4da8a531224129210249f43dded86056891506 rename to test/integration/diffing/expected/repo/.git_keep/objects/14/4da8a531224129210249f43dded86056891506 diff --git a/test/integration/diffing/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/diffing/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/diffing/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/diffing/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 b/test/integration/diffing/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 rename to test/integration/diffing/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 diff --git a/test/integration/diffing/expected/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 b/test/integration/diffing/expected/repo/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 rename to test/integration/diffing/expected/repo/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 diff --git a/test/integration/diffing/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da b/test/integration/diffing/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da rename to test/integration/diffing/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da diff --git a/test/integration/diffing/expected/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a b/test/integration/diffing/expected/repo/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a rename to test/integration/diffing/expected/repo/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a diff --git a/test/integration/diffing/expected/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b b/test/integration/diffing/expected/repo/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b rename to test/integration/diffing/expected/repo/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b diff --git a/test/integration/diffing/expected/.git_keep/objects/57/51731b38a36f8eb54a4bb304522ca539e04522 b/test/integration/diffing/expected/repo/.git_keep/objects/57/51731b38a36f8eb54a4bb304522ca539e04522 similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/57/51731b38a36f8eb54a4bb304522ca539e04522 rename to test/integration/diffing/expected/repo/.git_keep/objects/57/51731b38a36f8eb54a4bb304522ca539e04522 diff --git a/test/integration/diffing/expected/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 b/test/integration/diffing/expected/repo/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 rename to test/integration/diffing/expected/repo/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 diff --git a/test/integration/diffing/expected/.git_keep/objects/75/b31f81dd4387724638dbd3aff7380155c672cd b/test/integration/diffing/expected/repo/.git_keep/objects/75/b31f81dd4387724638dbd3aff7380155c672cd similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/75/b31f81dd4387724638dbd3aff7380155c672cd rename to test/integration/diffing/expected/repo/.git_keep/objects/75/b31f81dd4387724638dbd3aff7380155c672cd diff --git a/test/integration/diffing/expected/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 b/test/integration/diffing/expected/repo/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 rename to test/integration/diffing/expected/repo/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 diff --git a/test/integration/diffing/expected/.git_keep/objects/96/a6d041bbb131df0e74d179c3adcd2ace0e7f9c b/test/integration/diffing/expected/repo/.git_keep/objects/96/a6d041bbb131df0e74d179c3adcd2ace0e7f9c similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/96/a6d041bbb131df0e74d179c3adcd2ace0e7f9c rename to test/integration/diffing/expected/repo/.git_keep/objects/96/a6d041bbb131df0e74d179c3adcd2ace0e7f9c diff --git a/test/integration/diffing/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c b/test/integration/diffing/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c rename to test/integration/diffing/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c diff --git a/test/integration/diffing/expected/.git_keep/objects/a1/00b407f33fd2e97a3cb6f62b68ed6b7cc6c676 b/test/integration/diffing/expected/repo/.git_keep/objects/a1/00b407f33fd2e97a3cb6f62b68ed6b7cc6c676 similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/a1/00b407f33fd2e97a3cb6f62b68ed6b7cc6c676 rename to test/integration/diffing/expected/repo/.git_keep/objects/a1/00b407f33fd2e97a3cb6f62b68ed6b7cc6c676 diff --git a/test/integration/diffing/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/diffing/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/diffing/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/diffing/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 b/test/integration/diffing/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 rename to test/integration/diffing/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 diff --git a/test/integration/diffing/expected/.git_keep/objects/d1/5e253139400c94b42fc266641d1698720d4ecf b/test/integration/diffing/expected/repo/.git_keep/objects/d1/5e253139400c94b42fc266641d1698720d4ecf similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/d1/5e253139400c94b42fc266641d1698720d4ecf rename to test/integration/diffing/expected/repo/.git_keep/objects/d1/5e253139400c94b42fc266641d1698720d4ecf diff --git a/test/integration/diffing/expected/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 b/test/integration/diffing/expected/repo/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 rename to test/integration/diffing/expected/repo/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 diff --git a/test/integration/diffing/expected/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a b/test/integration/diffing/expected/repo/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a rename to test/integration/diffing/expected/repo/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a diff --git a/test/integration/diffing/expected/.git_keep/objects/f6/77ef8a14ca2770e48129cc13acfa1c369908cc b/test/integration/diffing/expected/repo/.git_keep/objects/f6/77ef8a14ca2770e48129cc13acfa1c369908cc similarity index 100% rename from test/integration/diffing/expected/.git_keep/objects/f6/77ef8a14ca2770e48129cc13acfa1c369908cc rename to test/integration/diffing/expected/repo/.git_keep/objects/f6/77ef8a14ca2770e48129cc13acfa1c369908cc diff --git a/test/integration/diffing/expected/.git_keep/refs/heads/branch2 b/test/integration/diffing/expected/repo/.git_keep/refs/heads/branch2 similarity index 100% rename from test/integration/diffing/expected/.git_keep/refs/heads/branch2 rename to test/integration/diffing/expected/repo/.git_keep/refs/heads/branch2 diff --git a/test/integration/diffing/expected/.git_keep/refs/heads/master b/test/integration/diffing/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/diffing/expected/.git_keep/refs/heads/master rename to test/integration/diffing/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/diffing/expected/file0 b/test/integration/diffing/expected/repo/file0 similarity index 100% rename from test/integration/diffing/expected/file0 rename to test/integration/diffing/expected/repo/file0 diff --git a/test/integration/diffing/expected/file1 b/test/integration/diffing/expected/repo/file1 similarity index 100% rename from test/integration/diffing/expected/file1 rename to test/integration/diffing/expected/repo/file1 diff --git a/test/integration/diffing/expected/file2 b/test/integration/diffing/expected/repo/file2 similarity index 100% rename from test/integration/diffing/expected/file2 rename to test/integration/diffing/expected/repo/file2 diff --git a/test/integration/diffing/expected/file4 b/test/integration/diffing/expected/repo/file4 similarity index 100% rename from test/integration/diffing/expected/file4 rename to test/integration/diffing/expected/repo/file4 diff --git a/test/integration/diffing2/expected/.git_keep/COMMIT_EDITMSG b/test/integration/diffing2/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/diffing2/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/diffing2/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/diffing2/expected/.git_keep/FETCH_HEAD b/test/integration/diffing2/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/diffing2/expected/.git_keep/FETCH_HEAD rename to test/integration/diffing2/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/diffing2/expected/.git_keep/HEAD b/test/integration/diffing2/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/diffing2/expected/.git_keep/HEAD rename to test/integration/diffing2/expected/repo/.git_keep/HEAD diff --git a/test/integration/diffing2/expected/.git_keep/config b/test/integration/diffing2/expected/repo/.git_keep/config similarity index 100% rename from test/integration/diffing2/expected/.git_keep/config rename to test/integration/diffing2/expected/repo/.git_keep/config diff --git a/test/integration/diffing2/expected/.git_keep/description b/test/integration/diffing2/expected/repo/.git_keep/description similarity index 100% rename from test/integration/diffing2/expected/.git_keep/description rename to test/integration/diffing2/expected/repo/.git_keep/description diff --git a/test/integration/diffing2/expected/.git_keep/index b/test/integration/diffing2/expected/repo/.git_keep/index similarity index 100% rename from test/integration/diffing2/expected/.git_keep/index rename to test/integration/diffing2/expected/repo/.git_keep/index diff --git a/test/integration/diffing2/expected/.git_keep/info/exclude b/test/integration/diffing2/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/diffing2/expected/.git_keep/info/exclude rename to test/integration/diffing2/expected/repo/.git_keep/info/exclude diff --git a/test/integration/diffing2/expected/.git_keep/logs/HEAD b/test/integration/diffing2/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/diffing2/expected/.git_keep/logs/HEAD rename to test/integration/diffing2/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/diffing2/expected/.git_keep/logs/refs/heads/branch2 b/test/integration/diffing2/expected/repo/.git_keep/logs/refs/heads/branch2 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/logs/refs/heads/branch2 rename to test/integration/diffing2/expected/repo/.git_keep/logs/refs/heads/branch2 diff --git a/test/integration/diffing2/expected/.git_keep/logs/refs/heads/master b/test/integration/diffing2/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/diffing2/expected/.git_keep/logs/refs/heads/master rename to test/integration/diffing2/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/diffing2/expected/.git_keep/objects/06/da465196938ea235323950ee451ffb36a431cf b/test/integration/diffing2/expected/repo/.git_keep/objects/06/da465196938ea235323950ee451ffb36a431cf similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/06/da465196938ea235323950ee451ffb36a431cf rename to test/integration/diffing2/expected/repo/.git_keep/objects/06/da465196938ea235323950ee451ffb36a431cf diff --git a/test/integration/diffing2/expected/.git_keep/objects/08/04f2069f5af172770da3d231be982ca320bf8b b/test/integration/diffing2/expected/repo/.git_keep/objects/08/04f2069f5af172770da3d231be982ca320bf8b similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/08/04f2069f5af172770da3d231be982ca320bf8b rename to test/integration/diffing2/expected/repo/.git_keep/objects/08/04f2069f5af172770da3d231be982ca320bf8b diff --git a/test/integration/diffing2/expected/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 b/test/integration/diffing2/expected/repo/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 rename to test/integration/diffing2/expected/repo/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 diff --git a/test/integration/diffing2/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/diffing2/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/diffing2/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/diffing2/expected/.git_keep/objects/1b/74d64fe4055d4502ac600072586068b27d4aa7 b/test/integration/diffing2/expected/repo/.git_keep/objects/1b/74d64fe4055d4502ac600072586068b27d4aa7 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/1b/74d64fe4055d4502ac600072586068b27d4aa7 rename to test/integration/diffing2/expected/repo/.git_keep/objects/1b/74d64fe4055d4502ac600072586068b27d4aa7 diff --git a/test/integration/diffing2/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 b/test/integration/diffing2/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 rename to test/integration/diffing2/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 diff --git a/test/integration/diffing2/expected/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 b/test/integration/diffing2/expected/repo/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 rename to test/integration/diffing2/expected/repo/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 diff --git a/test/integration/diffing2/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da b/test/integration/diffing2/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da rename to test/integration/diffing2/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da diff --git a/test/integration/diffing2/expected/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a b/test/integration/diffing2/expected/repo/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a rename to test/integration/diffing2/expected/repo/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a diff --git a/test/integration/diffing2/expected/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b b/test/integration/diffing2/expected/repo/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b rename to test/integration/diffing2/expected/repo/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b diff --git a/test/integration/diffing2/expected/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 b/test/integration/diffing2/expected/repo/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 rename to test/integration/diffing2/expected/repo/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 diff --git a/test/integration/diffing2/expected/.git_keep/objects/6d/04f5ed53b383c0a4c63cac168df557b6df1e44 b/test/integration/diffing2/expected/repo/.git_keep/objects/6d/04f5ed53b383c0a4c63cac168df557b6df1e44 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/6d/04f5ed53b383c0a4c63cac168df557b6df1e44 rename to test/integration/diffing2/expected/repo/.git_keep/objects/6d/04f5ed53b383c0a4c63cac168df557b6df1e44 diff --git a/test/integration/diffing2/expected/.git_keep/objects/7b/f3d13079ced18f5b00e29c48c777e23f687d0a b/test/integration/diffing2/expected/repo/.git_keep/objects/7b/f3d13079ced18f5b00e29c48c777e23f687d0a similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/7b/f3d13079ced18f5b00e29c48c777e23f687d0a rename to test/integration/diffing2/expected/repo/.git_keep/objects/7b/f3d13079ced18f5b00e29c48c777e23f687d0a diff --git a/test/integration/diffing2/expected/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 b/test/integration/diffing2/expected/repo/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 rename to test/integration/diffing2/expected/repo/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 diff --git a/test/integration/diffing2/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c b/test/integration/diffing2/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c rename to test/integration/diffing2/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c diff --git a/test/integration/diffing2/expected/.git_keep/objects/a1/1d868e88adb55a48fc55ee1377b3255c0cd329 b/test/integration/diffing2/expected/repo/.git_keep/objects/a1/1d868e88adb55a48fc55ee1377b3255c0cd329 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/a1/1d868e88adb55a48fc55ee1377b3255c0cd329 rename to test/integration/diffing2/expected/repo/.git_keep/objects/a1/1d868e88adb55a48fc55ee1377b3255c0cd329 diff --git a/test/integration/diffing2/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/diffing2/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/diffing2/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/diffing2/expected/.git_keep/objects/c6/756882cc166f52b096a5e4fb9e4f5d507870c8 b/test/integration/diffing2/expected/repo/.git_keep/objects/c6/756882cc166f52b096a5e4fb9e4f5d507870c8 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/c6/756882cc166f52b096a5e4fb9e4f5d507870c8 rename to test/integration/diffing2/expected/repo/.git_keep/objects/c6/756882cc166f52b096a5e4fb9e4f5d507870c8 diff --git a/test/integration/diffing2/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 b/test/integration/diffing2/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 rename to test/integration/diffing2/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 diff --git a/test/integration/diffing2/expected/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 b/test/integration/diffing2/expected/repo/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 rename to test/integration/diffing2/expected/repo/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 diff --git a/test/integration/diffing2/expected/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a b/test/integration/diffing2/expected/repo/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a rename to test/integration/diffing2/expected/repo/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a diff --git a/test/integration/diffing2/expected/.git_keep/objects/e8/76c3dfe2826621bea1bd3c87c2b9e2be88e69e b/test/integration/diffing2/expected/repo/.git_keep/objects/e8/76c3dfe2826621bea1bd3c87c2b9e2be88e69e similarity index 100% rename from test/integration/diffing2/expected/.git_keep/objects/e8/76c3dfe2826621bea1bd3c87c2b9e2be88e69e rename to test/integration/diffing2/expected/repo/.git_keep/objects/e8/76c3dfe2826621bea1bd3c87c2b9e2be88e69e diff --git a/test/integration/diffing2/expected/.git_keep/refs/heads/branch2 b/test/integration/diffing2/expected/repo/.git_keep/refs/heads/branch2 similarity index 100% rename from test/integration/diffing2/expected/.git_keep/refs/heads/branch2 rename to test/integration/diffing2/expected/repo/.git_keep/refs/heads/branch2 diff --git a/test/integration/diffing2/expected/.git_keep/refs/heads/master b/test/integration/diffing2/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/diffing2/expected/.git_keep/refs/heads/master rename to test/integration/diffing2/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/diffing2/expected/file0 b/test/integration/diffing2/expected/repo/file0 similarity index 100% rename from test/integration/diffing2/expected/file0 rename to test/integration/diffing2/expected/repo/file0 diff --git a/test/integration/diffing2/expected/file1 b/test/integration/diffing2/expected/repo/file1 similarity index 100% rename from test/integration/diffing2/expected/file1 rename to test/integration/diffing2/expected/repo/file1 diff --git a/test/integration/diffing2/expected/file2 b/test/integration/diffing2/expected/repo/file2 similarity index 100% rename from test/integration/diffing2/expected/file2 rename to test/integration/diffing2/expected/repo/file2 diff --git a/test/integration/diffing2/expected/file4 b/test/integration/diffing2/expected/repo/file4 similarity index 100% rename from test/integration/diffing2/expected/file4 rename to test/integration/diffing2/expected/repo/file4 diff --git a/test/integration/diffing3/expected/.git_keep/COMMIT_EDITMSG b/test/integration/diffing3/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/diffing3/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/diffing3/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/diffing3/expected/.git_keep/FETCH_HEAD b/test/integration/diffing3/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/diffing3/expected/.git_keep/FETCH_HEAD rename to test/integration/diffing3/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/diffing3/expected/.git_keep/HEAD b/test/integration/diffing3/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/diffing3/expected/.git_keep/HEAD rename to test/integration/diffing3/expected/repo/.git_keep/HEAD diff --git a/test/integration/diffing3/expected/.git_keep/config b/test/integration/diffing3/expected/repo/.git_keep/config similarity index 100% rename from test/integration/diffing3/expected/.git_keep/config rename to test/integration/diffing3/expected/repo/.git_keep/config diff --git a/test/integration/diffing3/expected/.git_keep/description b/test/integration/diffing3/expected/repo/.git_keep/description similarity index 100% rename from test/integration/diffing3/expected/.git_keep/description rename to test/integration/diffing3/expected/repo/.git_keep/description diff --git a/test/integration/diffing3/expected/.git_keep/index b/test/integration/diffing3/expected/repo/.git_keep/index similarity index 100% rename from test/integration/diffing3/expected/.git_keep/index rename to test/integration/diffing3/expected/repo/.git_keep/index diff --git a/test/integration/diffing3/expected/.git_keep/info/exclude b/test/integration/diffing3/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/diffing3/expected/.git_keep/info/exclude rename to test/integration/diffing3/expected/repo/.git_keep/info/exclude diff --git a/test/integration/diffing3/expected/.git_keep/logs/HEAD b/test/integration/diffing3/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/diffing3/expected/.git_keep/logs/HEAD rename to test/integration/diffing3/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/diffing3/expected/.git_keep/logs/refs/heads/branch2 b/test/integration/diffing3/expected/repo/.git_keep/logs/refs/heads/branch2 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/logs/refs/heads/branch2 rename to test/integration/diffing3/expected/repo/.git_keep/logs/refs/heads/branch2 diff --git a/test/integration/diffing3/expected/.git_keep/logs/refs/heads/master b/test/integration/diffing3/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/diffing3/expected/.git_keep/logs/refs/heads/master rename to test/integration/diffing3/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/diffing3/expected/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 b/test/integration/diffing3/expected/repo/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 rename to test/integration/diffing3/expected/repo/.git_keep/objects/0c/2aa38e0600e0d2df09c2f84664d8a14f899879 diff --git a/test/integration/diffing3/expected/.git_keep/objects/13/d8ce6d541ffd4b323376e2530ccdd3bcc7b8d5 b/test/integration/diffing3/expected/repo/.git_keep/objects/13/d8ce6d541ffd4b323376e2530ccdd3bcc7b8d5 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/13/d8ce6d541ffd4b323376e2530ccdd3bcc7b8d5 rename to test/integration/diffing3/expected/repo/.git_keep/objects/13/d8ce6d541ffd4b323376e2530ccdd3bcc7b8d5 diff --git a/test/integration/diffing3/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/diffing3/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/diffing3/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/diffing3/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 b/test/integration/diffing3/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 rename to test/integration/diffing3/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 diff --git a/test/integration/diffing3/expected/.git_keep/objects/1e/dd26fd03ee6243bd1513788874c6c57ef1d41a b/test/integration/diffing3/expected/repo/.git_keep/objects/1e/dd26fd03ee6243bd1513788874c6c57ef1d41a similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/1e/dd26fd03ee6243bd1513788874c6c57ef1d41a rename to test/integration/diffing3/expected/repo/.git_keep/objects/1e/dd26fd03ee6243bd1513788874c6c57ef1d41a diff --git a/test/integration/diffing3/expected/.git_keep/objects/27/5e6a821120c07a9068a9701ed14a82eeed3117 b/test/integration/diffing3/expected/repo/.git_keep/objects/27/5e6a821120c07a9068a9701ed14a82eeed3117 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/27/5e6a821120c07a9068a9701ed14a82eeed3117 rename to test/integration/diffing3/expected/repo/.git_keep/objects/27/5e6a821120c07a9068a9701ed14a82eeed3117 diff --git a/test/integration/diffing3/expected/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 b/test/integration/diffing3/expected/repo/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 rename to test/integration/diffing3/expected/repo/.git_keep/objects/2d/00bd505971a8bc7318d98e003aee708a367c85 diff --git a/test/integration/diffing3/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da b/test/integration/diffing3/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da rename to test/integration/diffing3/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da diff --git a/test/integration/diffing3/expected/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a b/test/integration/diffing3/expected/repo/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a rename to test/integration/diffing3/expected/repo/.git_keep/objects/3b/aaa732b89ed46a1af1b24d0d4e3b8c7375684a diff --git a/test/integration/diffing3/expected/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b b/test/integration/diffing3/expected/repo/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b rename to test/integration/diffing3/expected/repo/.git_keep/objects/3d/b2086f780b1cf632eec29111ef395913a8ab2b diff --git a/test/integration/diffing3/expected/.git_keep/objects/4e/2d07409901af28a47f5d3b126953a5fb8b36ee b/test/integration/diffing3/expected/repo/.git_keep/objects/4e/2d07409901af28a47f5d3b126953a5fb8b36ee similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/4e/2d07409901af28a47f5d3b126953a5fb8b36ee rename to test/integration/diffing3/expected/repo/.git_keep/objects/4e/2d07409901af28a47f5d3b126953a5fb8b36ee diff --git a/test/integration/diffing3/expected/.git_keep/objects/57/695899c35539821690c4c132bd0e872a01c192 b/test/integration/diffing3/expected/repo/.git_keep/objects/57/695899c35539821690c4c132bd0e872a01c192 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/57/695899c35539821690c4c132bd0e872a01c192 rename to test/integration/diffing3/expected/repo/.git_keep/objects/57/695899c35539821690c4c132bd0e872a01c192 diff --git a/test/integration/diffing3/expected/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 b/test/integration/diffing3/expected/repo/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 rename to test/integration/diffing3/expected/repo/.git_keep/objects/59/a0ec98e1847ca72dc35b7ab8b84f527b6af280 diff --git a/test/integration/diffing3/expected/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 b/test/integration/diffing3/expected/repo/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 rename to test/integration/diffing3/expected/repo/.git_keep/objects/8e/4cb0cd56d785ba4442a5b20e7ae5de5ae33723 diff --git a/test/integration/diffing3/expected/.git_keep/objects/93/b73046d6820607f1da09399b55a145d5389ab8 b/test/integration/diffing3/expected/repo/.git_keep/objects/93/b73046d6820607f1da09399b55a145d5389ab8 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/93/b73046d6820607f1da09399b55a145d5389ab8 rename to test/integration/diffing3/expected/repo/.git_keep/objects/93/b73046d6820607f1da09399b55a145d5389ab8 diff --git a/test/integration/diffing3/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c b/test/integration/diffing3/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c rename to test/integration/diffing3/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c diff --git a/test/integration/diffing3/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/diffing3/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/diffing3/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/diffing3/expected/.git_keep/objects/b2/5b8446022fb5fcded2bab1ed2b02828a5c4d0b b/test/integration/diffing3/expected/repo/.git_keep/objects/b2/5b8446022fb5fcded2bab1ed2b02828a5c4d0b similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/b2/5b8446022fb5fcded2bab1ed2b02828a5c4d0b rename to test/integration/diffing3/expected/repo/.git_keep/objects/b2/5b8446022fb5fcded2bab1ed2b02828a5c4d0b diff --git a/test/integration/diffing3/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 b/test/integration/diffing3/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 rename to test/integration/diffing3/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 diff --git a/test/integration/diffing3/expected/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 b/test/integration/diffing3/expected/repo/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 rename to test/integration/diffing3/expected/repo/.git_keep/objects/e5/c5c5583f49a34e86ce622b59363df99e09d4c6 diff --git a/test/integration/diffing3/expected/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a b/test/integration/diffing3/expected/repo/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a rename to test/integration/diffing3/expected/repo/.git_keep/objects/e7/76522ac28860d2eba6fe98fa4fad67e798419a diff --git a/test/integration/diffing3/expected/.git_keep/objects/ff/b13702e6bc59e2806bc3a5f93500e46925b131 b/test/integration/diffing3/expected/repo/.git_keep/objects/ff/b13702e6bc59e2806bc3a5f93500e46925b131 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/objects/ff/b13702e6bc59e2806bc3a5f93500e46925b131 rename to test/integration/diffing3/expected/repo/.git_keep/objects/ff/b13702e6bc59e2806bc3a5f93500e46925b131 diff --git a/test/integration/diffing3/expected/.git_keep/refs/heads/branch2 b/test/integration/diffing3/expected/repo/.git_keep/refs/heads/branch2 similarity index 100% rename from test/integration/diffing3/expected/.git_keep/refs/heads/branch2 rename to test/integration/diffing3/expected/repo/.git_keep/refs/heads/branch2 diff --git a/test/integration/diffing3/expected/.git_keep/refs/heads/master b/test/integration/diffing3/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/diffing3/expected/.git_keep/refs/heads/master rename to test/integration/diffing3/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/diffing3/expected/file0 b/test/integration/diffing3/expected/repo/file0 similarity index 100% rename from test/integration/diffing3/expected/file0 rename to test/integration/diffing3/expected/repo/file0 diff --git a/test/integration/diffing3/expected/file1 b/test/integration/diffing3/expected/repo/file1 similarity index 100% rename from test/integration/diffing3/expected/file1 rename to test/integration/diffing3/expected/repo/file1 diff --git a/test/integration/diffing3/expected/file2 b/test/integration/diffing3/expected/repo/file2 similarity index 100% rename from test/integration/diffing3/expected/file2 rename to test/integration/diffing3/expected/repo/file2 diff --git a/test/integration/discardFileChanges/expected/.git_keep/COMMIT_EDITMSG b/test/integration/discardFileChanges/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/discardFileChanges/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/discardFileChanges/expected/.git_keep/FETCH_HEAD b/test/integration/discardFileChanges/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/FETCH_HEAD rename to test/integration/discardFileChanges/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/discardFileChanges/expected/.git_keep/HEAD b/test/integration/discardFileChanges/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/HEAD rename to test/integration/discardFileChanges/expected/repo/.git_keep/HEAD diff --git a/test/integration/discardFileChanges/expected/.git_keep/ORIG_HEAD b/test/integration/discardFileChanges/expected/repo/.git_keep/ORIG_HEAD similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/ORIG_HEAD rename to test/integration/discardFileChanges/expected/repo/.git_keep/ORIG_HEAD diff --git a/test/integration/discardFileChanges/expected/.git_keep/config b/test/integration/discardFileChanges/expected/repo/.git_keep/config similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/config rename to test/integration/discardFileChanges/expected/repo/.git_keep/config diff --git a/test/integration/discardFileChanges/expected/.git_keep/description b/test/integration/discardFileChanges/expected/repo/.git_keep/description similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/description rename to test/integration/discardFileChanges/expected/repo/.git_keep/description diff --git a/test/integration/discardFileChanges/expected/.git_keep/index b/test/integration/discardFileChanges/expected/repo/.git_keep/index similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/index rename to test/integration/discardFileChanges/expected/repo/.git_keep/index diff --git a/test/integration/discardFileChanges/expected/.git_keep/info/exclude b/test/integration/discardFileChanges/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/info/exclude rename to test/integration/discardFileChanges/expected/repo/.git_keep/info/exclude diff --git a/test/integration/discardFileChanges/expected/.git_keep/logs/HEAD b/test/integration/discardFileChanges/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/logs/HEAD rename to test/integration/discardFileChanges/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/discardFileChanges/expected/.git_keep/logs/refs/heads/conflict b/test/integration/discardFileChanges/expected/repo/.git_keep/logs/refs/heads/conflict similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/logs/refs/heads/conflict rename to test/integration/discardFileChanges/expected/repo/.git_keep/logs/refs/heads/conflict diff --git a/test/integration/discardFileChanges/expected/.git_keep/logs/refs/heads/conflict_second b/test/integration/discardFileChanges/expected/repo/.git_keep/logs/refs/heads/conflict_second similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/logs/refs/heads/conflict_second rename to test/integration/discardFileChanges/expected/repo/.git_keep/logs/refs/heads/conflict_second diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/11/bdfc142c42c6ffaa904890ab61ec76262ec9ca b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/11/bdfc142c42c6ffaa904890ab61ec76262ec9ca similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/11/bdfc142c42c6ffaa904890ab61ec76262ec9ca rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/11/bdfc142c42c6ffaa904890ab61ec76262ec9ca diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/15/fe7f43604da957ffb663b4db95b60d0af66469 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/15/fe7f43604da957ffb663b4db95b60d0af66469 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/15/fe7f43604da957ffb663b4db95b60d0af66469 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/15/fe7f43604da957ffb663b4db95b60d0af66469 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/1c/9488b0e1b8abd1ec8645b3345bdac91290b464 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/1c/9488b0e1b8abd1ec8645b3345bdac91290b464 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/1c/9488b0e1b8abd1ec8645b3345bdac91290b464 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/1c/9488b0e1b8abd1ec8645b3345bdac91290b464 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/26/80cfddbd9fa03c059ac60d2bec5e59a1c34281 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/26/80cfddbd9fa03c059ac60d2bec5e59a1c34281 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/26/80cfddbd9fa03c059ac60d2bec5e59a1c34281 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/26/80cfddbd9fa03c059ac60d2bec5e59a1c34281 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/2c/e75e2a24f7d6841a504cf3616ef5a59edb3a2d b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/2c/e75e2a24f7d6841a504cf3616ef5a59edb3a2d similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/2c/e75e2a24f7d6841a504cf3616ef5a59edb3a2d rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/2c/e75e2a24f7d6841a504cf3616ef5a59edb3a2d diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/30/07c9c07bf80aaa72b1f1f704e7fea622446678 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/30/07c9c07bf80aaa72b1f1f704e7fea622446678 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/30/07c9c07bf80aaa72b1f1f704e7fea622446678 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/30/07c9c07bf80aaa72b1f1f704e7fea622446678 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/3f/7bd8f68987d4e16b8f6fa7f6b0738b42180d1f b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/3f/7bd8f68987d4e16b8f6fa7f6b0738b42180d1f similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/3f/7bd8f68987d4e16b8f6fa7f6b0738b42180d1f rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/3f/7bd8f68987d4e16b8f6fa7f6b0738b42180d1f diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/47/966dcaa8ee736e89279b895faf8707de898e04 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/47/966dcaa8ee736e89279b895faf8707de898e04 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/47/966dcaa8ee736e89279b895faf8707de898e04 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/47/966dcaa8ee736e89279b895faf8707de898e04 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/48/f9387742d3cc3017c1a7e292c9187e35321753 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/48/f9387742d3cc3017c1a7e292c9187e35321753 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/48/f9387742d3cc3017c1a7e292c9187e35321753 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/48/f9387742d3cc3017c1a7e292c9187e35321753 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/4d/8452fc76beed0c7b15e40e45d06922bf746c5f b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/4d/8452fc76beed0c7b15e40e45d06922bf746c5f similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/4d/8452fc76beed0c7b15e40e45d06922bf746c5f rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/4d/8452fc76beed0c7b15e40e45d06922bf746c5f diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/59/cf7b78af9aab84813bcb0bc8be27fdd9216b2b b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/59/cf7b78af9aab84813bcb0bc8be27fdd9216b2b similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/59/cf7b78af9aab84813bcb0bc8be27fdd9216b2b rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/59/cf7b78af9aab84813bcb0bc8be27fdd9216b2b diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/5a/d28e22767f979da2c198dc6c1003b25964e3da b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/5a/d28e22767f979da2c198dc6c1003b25964e3da similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/5a/d28e22767f979da2c198dc6c1003b25964e3da rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/5a/d28e22767f979da2c198dc6c1003b25964e3da diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/5b/e4a414b32cf4204f889469942986d3d783da84 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/5b/e4a414b32cf4204f889469942986d3d783da84 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/5b/e4a414b32cf4204f889469942986d3d783da84 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/5b/e4a414b32cf4204f889469942986d3d783da84 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/7a/22af9d1908d85e3c4b6d916a9b6c733c55c990 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/7a/22af9d1908d85e3c4b6d916a9b6c733c55c990 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/7a/22af9d1908d85e3c4b6d916a9b6c733c55c990 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/7a/22af9d1908d85e3c4b6d916a9b6c733c55c990 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/85/4f08fa802293e0679d07771547fe9fe5d159e8 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/85/4f08fa802293e0679d07771547fe9fe5d159e8 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/85/4f08fa802293e0679d07771547fe9fe5d159e8 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/85/4f08fa802293e0679d07771547fe9fe5d159e8 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/89/44a13fdfc597e4cf1d23797df51977680f8e77 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/89/44a13fdfc597e4cf1d23797df51977680f8e77 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/89/44a13fdfc597e4cf1d23797df51977680f8e77 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/89/44a13fdfc597e4cf1d23797df51977680f8e77 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/8c/82faa1358ce6cddba19d59b2924cbcc5ef1c8e b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/8c/82faa1358ce6cddba19d59b2924cbcc5ef1c8e similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/8c/82faa1358ce6cddba19d59b2924cbcc5ef1c8e rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/8c/82faa1358ce6cddba19d59b2924cbcc5ef1c8e diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/90/7b308167f0880fb2a5c0e1614bb0c7620f9dc3 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/90/7b308167f0880fb2a5c0e1614bb0c7620f9dc3 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/90/7b308167f0880fb2a5c0e1614bb0c7620f9dc3 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/90/7b308167f0880fb2a5c0e1614bb0c7620f9dc3 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/90/be1f3056c4f471f977a28497b8d4b392c55a02 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/90/be1f3056c4f471f977a28497b8d4b392c55a02 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/90/be1f3056c4f471f977a28497b8d4b392c55a02 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/90/be1f3056c4f471f977a28497b8d4b392c55a02 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/98/e834e9cdae1191de7fafb2b6f334bddd0793e8 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/98/e834e9cdae1191de7fafb2b6f334bddd0793e8 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/98/e834e9cdae1191de7fafb2b6f334bddd0793e8 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/98/e834e9cdae1191de7fafb2b6f334bddd0793e8 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/99/76d7948def8b082e9d20135d6a04624d711752 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/99/76d7948def8b082e9d20135d6a04624d711752 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/99/76d7948def8b082e9d20135d6a04624d711752 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/99/76d7948def8b082e9d20135d6a04624d711752 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/9f/5118ee216a6e44728305f90633b0c0e2ad235c b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/9f/5118ee216a6e44728305f90633b0c0e2ad235c similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/9f/5118ee216a6e44728305f90633b0c0e2ad235c rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/9f/5118ee216a6e44728305f90633b0c0e2ad235c diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/a1/be04124078e38a592c153942bf75edf210f1ed b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/a1/be04124078e38a592c153942bf75edf210f1ed similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/a1/be04124078e38a592c153942bf75edf210f1ed rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/a1/be04124078e38a592c153942bf75edf210f1ed diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/a1/e09c2fda67b9f8d4440073c0c33f6e45689b7c b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/a1/e09c2fda67b9f8d4440073c0c33f6e45689b7c similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/a1/e09c2fda67b9f8d4440073c0c33f6e45689b7c rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/a1/e09c2fda67b9f8d4440073c0c33f6e45689b7c diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/ab/addc0b9edd523c69166a2c9f3a9e31a4c873e3 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/ab/addc0b9edd523c69166a2c9f3a9e31a4c873e3 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/ab/addc0b9edd523c69166a2c9f3a9e31a4c873e3 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/ab/addc0b9edd523c69166a2c9f3a9e31a4c873e3 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/c9/1b3b139ea108475c19839fcda3a4e33db4ccc9 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/c9/1b3b139ea108475c19839fcda3a4e33db4ccc9 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/c9/1b3b139ea108475c19839fcda3a4e33db4ccc9 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/c9/1b3b139ea108475c19839fcda3a4e33db4ccc9 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/ce/e08babc6b109f011f42eaba5f79e6e693c09e7 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/ce/e08babc6b109f011f42eaba5f79e6e693c09e7 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/ce/e08babc6b109f011f42eaba5f79e6e693c09e7 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/ce/e08babc6b109f011f42eaba5f79e6e693c09e7 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/d4/d1b67951582a751c12ff7ea29ede7d37fd9ee8 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/d4/d1b67951582a751c12ff7ea29ede7d37fd9ee8 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/d4/d1b67951582a751c12ff7ea29ede7d37fd9ee8 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/d4/d1b67951582a751c12ff7ea29ede7d37fd9ee8 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/d7/98b86744c3997c186e0f0dc666f02943c797a7 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/d7/98b86744c3997c186e0f0dc666f02943c797a7 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/d7/98b86744c3997c186e0f0dc666f02943c797a7 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/d7/98b86744c3997c186e0f0dc666f02943c797a7 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/e9/55de60e73263440d4651e79e947ec8b2902373 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/e9/55de60e73263440d4651e79e947ec8b2902373 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/e9/55de60e73263440d4651e79e947ec8b2902373 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/e9/55de60e73263440d4651e79e947ec8b2902373 diff --git a/test/integration/discardFileChanges/expected/.git_keep/objects/fa/938d99f6ee5cc562cd0f33fa64fd68d78ce2e9 b/test/integration/discardFileChanges/expected/repo/.git_keep/objects/fa/938d99f6ee5cc562cd0f33fa64fd68d78ce2e9 similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/objects/fa/938d99f6ee5cc562cd0f33fa64fd68d78ce2e9 rename to test/integration/discardFileChanges/expected/repo/.git_keep/objects/fa/938d99f6ee5cc562cd0f33fa64fd68d78ce2e9 diff --git a/test/integration/discardFileChanges/expected/.git_keep/refs/heads/conflict b/test/integration/discardFileChanges/expected/repo/.git_keep/refs/heads/conflict similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/refs/heads/conflict rename to test/integration/discardFileChanges/expected/repo/.git_keep/refs/heads/conflict diff --git a/test/integration/discardFileChanges/expected/.git_keep/refs/heads/conflict_second b/test/integration/discardFileChanges/expected/repo/.git_keep/refs/heads/conflict_second similarity index 100% rename from test/integration/discardFileChanges/expected/.git_keep/refs/heads/conflict_second rename to test/integration/discardFileChanges/expected/repo/.git_keep/refs/heads/conflict_second diff --git a/test/integration/discardFileChanges/expected/both-added.txt b/test/integration/discardFileChanges/expected/repo/both-added.txt similarity index 100% rename from test/integration/discardFileChanges/expected/both-added.txt rename to test/integration/discardFileChanges/expected/repo/both-added.txt diff --git a/test/integration/discardFileChanges/expected/both-modded.txt b/test/integration/discardFileChanges/expected/repo/both-modded.txt similarity index 100% rename from test/integration/discardFileChanges/expected/both-modded.txt rename to test/integration/discardFileChanges/expected/repo/both-modded.txt diff --git a/test/integration/discardFileChanges/expected/change-delete.txt b/test/integration/discardFileChanges/expected/repo/change-delete.txt similarity index 100% rename from test/integration/discardFileChanges/expected/change-delete.txt rename to test/integration/discardFileChanges/expected/repo/change-delete.txt diff --git a/test/integration/discardFileChanges/expected/changed-them-added-us.txt b/test/integration/discardFileChanges/expected/repo/changed-them-added-us.txt similarity index 100% rename from test/integration/discardFileChanges/expected/changed-them-added-us.txt rename to test/integration/discardFileChanges/expected/repo/changed-them-added-us.txt diff --git a/test/integration/discardFileChanges/expected/delete-change.txt b/test/integration/discardFileChanges/expected/repo/delete-change.txt similarity index 100% rename from test/integration/discardFileChanges/expected/delete-change.txt rename to test/integration/discardFileChanges/expected/repo/delete-change.txt diff --git a/test/integration/discardFileChanges/expected/deleted-staged.txt b/test/integration/discardFileChanges/expected/repo/deleted-staged.txt similarity index 100% rename from test/integration/discardFileChanges/expected/deleted-staged.txt rename to test/integration/discardFileChanges/expected/repo/deleted-staged.txt diff --git a/test/integration/discardFileChanges/expected/deleted-them.txt b/test/integration/discardFileChanges/expected/repo/deleted-them.txt similarity index 100% rename from test/integration/discardFileChanges/expected/deleted-them.txt rename to test/integration/discardFileChanges/expected/repo/deleted-them.txt diff --git a/test/integration/discardFileChanges/expected/deleted.txt b/test/integration/discardFileChanges/expected/repo/deleted.txt similarity index 100% rename from test/integration/discardFileChanges/expected/deleted.txt rename to test/integration/discardFileChanges/expected/repo/deleted.txt diff --git a/test/integration/discardFileChanges/expected/double-modded.txt b/test/integration/discardFileChanges/expected/repo/double-modded.txt similarity index 100% rename from test/integration/discardFileChanges/expected/double-modded.txt rename to test/integration/discardFileChanges/expected/repo/double-modded.txt diff --git a/test/integration/discardFileChanges/expected/modded-staged.txt b/test/integration/discardFileChanges/expected/repo/modded-staged.txt similarity index 100% rename from test/integration/discardFileChanges/expected/modded-staged.txt rename to test/integration/discardFileChanges/expected/repo/modded-staged.txt diff --git a/test/integration/discardFileChanges/expected/modded.txt b/test/integration/discardFileChanges/expected/repo/modded.txt similarity index 100% rename from test/integration/discardFileChanges/expected/modded.txt rename to test/integration/discardFileChanges/expected/repo/modded.txt diff --git a/test/integration/discardFileChanges/expected/renamed.txt b/test/integration/discardFileChanges/expected/repo/renamed.txt similarity index 100% rename from test/integration/discardFileChanges/expected/renamed.txt rename to test/integration/discardFileChanges/expected/repo/renamed.txt diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/COMMIT_EDITMSG b/test/integration/discardOldFileChanges/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/FETCH_HEAD b/test/integration/discardOldFileChanges/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/FETCH_HEAD rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/HEAD b/test/integration/discardOldFileChanges/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/HEAD rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/HEAD diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/ORIG_HEAD b/test/integration/discardOldFileChanges/expected/repo/.git_keep/ORIG_HEAD similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/ORIG_HEAD rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/ORIG_HEAD diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/config b/test/integration/discardOldFileChanges/expected/repo/.git_keep/config similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/config rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/config diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/description b/test/integration/discardOldFileChanges/expected/repo/.git_keep/description similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/description rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/description diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/index b/test/integration/discardOldFileChanges/expected/repo/.git_keep/index similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/index rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/index diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/info/exclude b/test/integration/discardOldFileChanges/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/info/exclude rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/info/exclude diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/logs/HEAD b/test/integration/discardOldFileChanges/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/logs/HEAD rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/logs/refs/heads/master b/test/integration/discardOldFileChanges/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/logs/refs/heads/master rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/00/cbccfd35a05ef9373bba9d5633cf6e67f83dd5 b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/00/cbccfd35a05ef9373bba9d5633cf6e67f83dd5 similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/00/cbccfd35a05ef9373bba9d5633cf6e67f83dd5 rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/00/cbccfd35a05ef9373bba9d5633cf6e67f83dd5 diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/0a/91dcf3772f7fd7409b3df04eb6ef177219303a b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/0a/91dcf3772f7fd7409b3df04eb6ef177219303a similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/0a/91dcf3772f7fd7409b3df04eb6ef177219303a rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/0a/91dcf3772f7fd7409b3df04eb6ef177219303a diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/0c/db6daba7e25b6d6d10da326e0ab74401021370 b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/0c/db6daba7e25b6d6d10da326e0ab74401021370 similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/0c/db6daba7e25b6d6d10da326e0ab74401021370 rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/0c/db6daba7e25b6d6d10da326e0ab74401021370 diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/18/e987d34afb121659724591cd709e2a789184fc b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/18/e987d34afb121659724591cd709e2a789184fc similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/18/e987d34afb121659724591cd709e2a789184fc rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/18/e987d34afb121659724591cd709e2a789184fc diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/22/5ad83faa797c1831a2bc956a21e2d472f21443 b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/22/5ad83faa797c1831a2bc956a21e2d472f21443 similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/22/5ad83faa797c1831a2bc956a21e2d472f21443 rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/22/5ad83faa797c1831a2bc956a21e2d472f21443 diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/42/786aead9ca20a3427c38e5e5262fa787ce9868 b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/42/786aead9ca20a3427c38e5e5262fa787ce9868 similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/42/786aead9ca20a3427c38e5e5262fa787ce9868 rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/42/786aead9ca20a3427c38e5e5262fa787ce9868 diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/78/80a9728615a4d196df39600a0c8c71b40d96d6 b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/78/80a9728615a4d196df39600a0c8c71b40d96d6 similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/78/80a9728615a4d196df39600a0c8c71b40d96d6 rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/78/80a9728615a4d196df39600a0c8c71b40d96d6 diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/7b/8a8396be4352039598acb43acaadc1c380551f b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/7b/8a8396be4352039598acb43acaadc1c380551f similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/7b/8a8396be4352039598acb43acaadc1c380551f rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/7b/8a8396be4352039598acb43acaadc1c380551f diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/af/6725ba23f43a286deff0747476d7874113df1e b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/af/6725ba23f43a286deff0747476d7874113df1e similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/af/6725ba23f43a286deff0747476d7874113df1e rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/af/6725ba23f43a286deff0747476d7874113df1e diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/b7/a702b642978f2a9b1af9c1c67b22127af78c92 b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/b7/a702b642978f2a9b1af9c1c67b22127af78c92 similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/b7/a702b642978f2a9b1af9c1c67b22127af78c92 rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/b7/a702b642978f2a9b1af9c1c67b22127af78c92 diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/d1/4505f281a54cda96fc5fb8cd4b4ee14bae6264 b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/d1/4505f281a54cda96fc5fb8cd4b4ee14bae6264 similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/d1/4505f281a54cda96fc5fb8cd4b4ee14bae6264 rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/d1/4505f281a54cda96fc5fb8cd4b4ee14bae6264 diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/discardOldFileChanges/expected/.git_keep/refs/heads/master b/test/integration/discardOldFileChanges/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/discardOldFileChanges/expected/.git_keep/refs/heads/master rename to test/integration/discardOldFileChanges/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/discardOldFileChanges/expected/file0 b/test/integration/discardOldFileChanges/expected/repo/file0 similarity index 100% rename from test/integration/discardOldFileChanges/expected/file0 rename to test/integration/discardOldFileChanges/expected/repo/file0 diff --git a/test/integration/discardOldFileChanges/expected/file1 b/test/integration/discardOldFileChanges/expected/repo/file1 similarity index 100% rename from test/integration/discardOldFileChanges/expected/file1 rename to test/integration/discardOldFileChanges/expected/repo/file1 diff --git a/test/integration/discardOldFileChanges/expected/file2 b/test/integration/discardOldFileChanges/expected/repo/file2 similarity index 100% rename from test/integration/discardOldFileChanges/expected/file2 rename to test/integration/discardOldFileChanges/expected/repo/file2 diff --git a/test/integration/discardOldFileChanges/expected/file3 b/test/integration/discardOldFileChanges/expected/repo/file3 similarity index 100% rename from test/integration/discardOldFileChanges/expected/file3 rename to test/integration/discardOldFileChanges/expected/repo/file3 diff --git a/test/integration/fetchPrune/expected/.git_keep/FETCH_HEAD b/test/integration/fetchPrune/expected/.git_keep/FETCH_HEAD deleted file mode 100644 index 8ef89fd5e..000000000 --- a/test/integration/fetchPrune/expected/.git_keep/FETCH_HEAD +++ /dev/null @@ -1 +0,0 @@ -f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 branch 'master' of ../actual_remote diff --git a/test/integration/fetchPrune/expected/.git_keep/index b/test/integration/fetchPrune/expected/.git_keep/index deleted file mode 100644 index 35b2e51a41fb2f2f9e218cffb40a031b02f6096b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 137 zcmZ?q402{*U|<4b#w5EpmF64um|-*{0|P75oPAFj7#f!VrN08zhyXF$(mjv=s;1uf z5)m53lkapPz^kSEDg%3NWm;xVsv%H8NRX>5kdkCDR50M;%lWWu`@CM4hix~67Jm13 ezUIFs=mej|q}#XDe!ICeo|kQ?QVuWiPXhoKkuLK9 diff --git a/test/integration/fetchPrune/expected/.git_keep/logs/HEAD b/test/integration/fetchPrune/expected/.git_keep/logs/HEAD deleted file mode 100644 index eac6e78df..000000000 --- a/test/integration/fetchPrune/expected/.git_keep/logs/HEAD +++ /dev/null @@ -1,3 +0,0 @@ -0000000000000000000000000000000000000000 f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 CI 1648290937 +1100 commit (initial): myfile1 -f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 CI 1648290937 +1100 checkout: moving from master to other_branch -f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 CI 1648290937 +1100 checkout: moving from other_branch to master diff --git a/test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/master b/test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/master deleted file mode 100644 index 94180e0b5..000000000 --- a/test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/master +++ /dev/null @@ -1 +0,0 @@ -0000000000000000000000000000000000000000 f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 CI 1648290937 +1100 commit (initial): myfile1 diff --git a/test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/other_branch b/test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/other_branch deleted file mode 100644 index 7cd5bcbce..000000000 --- a/test/integration/fetchPrune/expected/.git_keep/logs/refs/heads/other_branch +++ /dev/null @@ -1 +0,0 @@ -0000000000000000000000000000000000000000 f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 CI 1648290937 +1100 branch: Created from HEAD diff --git a/test/integration/fetchPrune/expected/.git_keep/logs/refs/remotes/origin/master b/test/integration/fetchPrune/expected/.git_keep/logs/refs/remotes/origin/master deleted file mode 100644 index 225a60ab5..000000000 --- a/test/integration/fetchPrune/expected/.git_keep/logs/refs/remotes/origin/master +++ /dev/null @@ -1 +0,0 @@ -0000000000000000000000000000000000000000 f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 CI 1648290938 +1100 fetch origin: storing head diff --git a/test/integration/fetchPrune/expected/.git_keep/objects/f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 b/test/integration/fetchPrune/expected/.git_keep/objects/f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 deleted file mode 100644 index 3d352742a54fef71e79f7712cdc1716f1d7fa401..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121 zcmV-<0EYi~0gcT;3d0}}K+&!}#q0}Z#!N?rQVLn+7)D1Lh**M! r}>NB&Fm+Z+#DvoC!vT%v%ZcY65ciUi`;4w}w-DCZ%dP}W7frPyc b7zPJdB1Ci6bJF!sZt78%RmuDSG=MDIu$DTV diff --git a/test/integration/fetchPrune/expected/.git_keep/refs/heads/master b/test/integration/fetchPrune/expected/.git_keep/refs/heads/master deleted file mode 100644 index 0725115bd..000000000 --- a/test/integration/fetchPrune/expected/.git_keep/refs/heads/master +++ /dev/null @@ -1 +0,0 @@ -f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 diff --git a/test/integration/fetchPrune/expected/.git_keep/refs/heads/other_branch b/test/integration/fetchPrune/expected/.git_keep/refs/heads/other_branch deleted file mode 100644 index 0725115bd..000000000 --- a/test/integration/fetchPrune/expected/.git_keep/refs/heads/other_branch +++ /dev/null @@ -1 +0,0 @@ -f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 diff --git a/test/integration/fetchPrune/expected/.git_keep/refs/remotes/origin/master b/test/integration/fetchPrune/expected/.git_keep/refs/remotes/origin/master deleted file mode 100644 index 0725115bd..000000000 --- a/test/integration/fetchPrune/expected/.git_keep/refs/remotes/origin/master +++ /dev/null @@ -1 +0,0 @@ -f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 diff --git a/test/integration/fetchPrune/expected/.git_keep/HEAD b/test/integration/fetchPrune/expected/origin/HEAD similarity index 100% rename from test/integration/fetchPrune/expected/.git_keep/HEAD rename to test/integration/fetchPrune/expected/origin/HEAD diff --git a/test/integration/fetchPrune/expected/origin/config b/test/integration/fetchPrune/expected/origin/config new file mode 100644 index 000000000..4caf7663f --- /dev/null +++ b/test/integration/fetchPrune/expected/origin/config @@ -0,0 +1,8 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true + ignorecase = true + precomposeunicode = true +[remote "origin"] + url = /Users/jesseduffieldduffield/go/src/github.com/jesseduffield/lazygit/test/integration/fetchPrune/actual/./repo diff --git a/test/integration/fetchPrune/expected/.git_keep/description b/test/integration/fetchPrune/expected/origin/description similarity index 100% rename from test/integration/fetchPrune/expected/.git_keep/description rename to test/integration/fetchPrune/expected/origin/description diff --git a/test/integration/fetchPrune/expected/.git_keep/info/exclude b/test/integration/fetchPrune/expected/origin/info/exclude similarity index 100% rename from test/integration/fetchPrune/expected/.git_keep/info/exclude rename to test/integration/fetchPrune/expected/origin/info/exclude diff --git a/test/integration/fetchPrune/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/fetchPrune/expected/origin/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/fetchPrune/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/fetchPrune/expected/origin/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/fetchPrune/expected/origin/objects/75/f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 b/test/integration/fetchPrune/expected/origin/objects/75/f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 new file mode 100644 index 000000000..965fc5498 --- /dev/null +++ b/test/integration/fetchPrune/expected/origin/objects/75/f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 @@ -0,0 +1,3 @@ +x嵧A +0@Q9澎嗓覫~c歀靶!R"桧軂讨H|昊*x錦金瘹 +慴鈷0諬 叐J儞wn狱袕豮覭nvdJ"#絯G=&]湮緐2, \ No newline at end of file diff --git a/test/integration/fetchPrune/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/fetchPrune/expected/origin/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/fetchPrune/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/fetchPrune/expected/origin/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/fetchPrune/expected/origin/packed-refs b/test/integration/fetchPrune/expected/origin/packed-refs new file mode 100644 index 000000000..37e4528a7 --- /dev/null +++ b/test/integration/fetchPrune/expected/origin/packed-refs @@ -0,0 +1,2 @@ +# pack-refs with: peeled fully-peeled sorted +75f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 refs/heads/master diff --git a/test/integration/fetchPrune/expected/.git_keep/COMMIT_EDITMSG b/test/integration/fetchPrune/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/fetchPrune/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/fetchPrune/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/fetchPrune/expected/repo/.git_keep/FETCH_HEAD b/test/integration/fetchPrune/expected/repo/.git_keep/FETCH_HEAD new file mode 100644 index 000000000..800c8511d --- /dev/null +++ b/test/integration/fetchPrune/expected/repo/.git_keep/FETCH_HEAD @@ -0,0 +1 @@ +75f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 branch 'master' of ../origin diff --git a/test/integration/fetchPrune/expected_remote/HEAD b/test/integration/fetchPrune/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/fetchPrune/expected_remote/HEAD rename to test/integration/fetchPrune/expected/repo/.git_keep/HEAD diff --git a/test/integration/fetchPrune/expected/.git_keep/config b/test/integration/fetchPrune/expected/repo/.git_keep/config similarity index 94% rename from test/integration/fetchPrune/expected/.git_keep/config rename to test/integration/fetchPrune/expected/repo/.git_keep/config index 6dfad7326..957eae48a 100644 --- a/test/integration/fetchPrune/expected/.git_keep/config +++ b/test/integration/fetchPrune/expected/repo/.git_keep/config @@ -11,7 +11,7 @@ [fetch] prune = true [remote "origin"] - url = ../actual_remote + url = ../origin fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin diff --git a/test/integration/fetchPrune/expected_remote/description b/test/integration/fetchPrune/expected/repo/.git_keep/description similarity index 100% rename from test/integration/fetchPrune/expected_remote/description rename to test/integration/fetchPrune/expected/repo/.git_keep/description diff --git a/test/integration/fetchPrune/expected/repo/.git_keep/index b/test/integration/fetchPrune/expected/repo/.git_keep/index new file mode 100644 index 0000000000000000000000000000000000000000..6955ab1975627f52285cfaecbc4504c38ef8f683 GIT binary patch literal 137 zcmZ?q402{*U|<4b#w7c@KgB<)=fY@41_oB9`TAQJ7#f!VrN08zhyXF$(mjv=s;1uf z5)m53lkapPz^kSEDg%3NWm;xVsv%H8NRX>5kdkCDR50M;%lWWu`@CM4hix~67Jm13 ezUIFs$a?WXj)}WPHW;lf=NGkSYB`!vvIzj1Y%f;; literal 0 HcmV?d00001 diff --git a/test/integration/fetchPrune/expected_remote/info/exclude b/test/integration/fetchPrune/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/fetchPrune/expected_remote/info/exclude rename to test/integration/fetchPrune/expected/repo/.git_keep/info/exclude diff --git a/test/integration/fetchPrune/expected/repo/.git_keep/logs/HEAD b/test/integration/fetchPrune/expected/repo/.git_keep/logs/HEAD new file mode 100644 index 000000000..639cde24f --- /dev/null +++ b/test/integration/fetchPrune/expected/repo/.git_keep/logs/HEAD @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 75f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 CI 1648352761 +1100 commit (initial): myfile1 +75f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 75f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 CI 1648352761 +1100 checkout: moving from master to other_branch +75f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 75f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 CI 1648352761 +1100 checkout: moving from other_branch to master diff --git a/test/integration/fetchPrune/expected/repo/.git_keep/logs/refs/heads/master b/test/integration/fetchPrune/expected/repo/.git_keep/logs/refs/heads/master new file mode 100644 index 000000000..f44229efe --- /dev/null +++ b/test/integration/fetchPrune/expected/repo/.git_keep/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 75f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 CI 1648352761 +1100 commit (initial): myfile1 diff --git a/test/integration/fetchPrune/expected/repo/.git_keep/logs/refs/heads/other_branch b/test/integration/fetchPrune/expected/repo/.git_keep/logs/refs/heads/other_branch new file mode 100644 index 000000000..01e383d7f --- /dev/null +++ b/test/integration/fetchPrune/expected/repo/.git_keep/logs/refs/heads/other_branch @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 75f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 CI 1648352761 +1100 branch: Created from HEAD diff --git a/test/integration/fetchPrune/expected/repo/.git_keep/logs/refs/remotes/origin/master b/test/integration/fetchPrune/expected/repo/.git_keep/logs/refs/remotes/origin/master new file mode 100644 index 000000000..7fe249171 --- /dev/null +++ b/test/integration/fetchPrune/expected/repo/.git_keep/logs/refs/remotes/origin/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 75f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 CI 1648352761 +1100 fetch origin: storing head diff --git a/test/integration/fetchPrune/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/fetchPrune/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/fetchPrune/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/fetchPrune/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/fetchPrune/expected/repo/.git_keep/objects/75/f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 b/test/integration/fetchPrune/expected/repo/.git_keep/objects/75/f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 new file mode 100644 index 000000000..965fc5498 --- /dev/null +++ b/test/integration/fetchPrune/expected/repo/.git_keep/objects/75/f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 @@ -0,0 +1,3 @@ +x嵧A +0@Q9澎嗓覫~c歀靶!R"桧軂讨H|昊*x錦金瘹 +慴鈷0諬 叐J儞wn狱袕豮覭nvdJ"#絯G=&]湮緐2, \ No newline at end of file diff --git a/test/integration/fetchPrune/expected_remote/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/fetchPrune/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/fetchPrune/expected_remote/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/fetchPrune/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/fetchPrune/expected/.git_keep/packed-refs b/test/integration/fetchPrune/expected/repo/.git_keep/packed-refs similarity index 100% rename from test/integration/fetchPrune/expected/.git_keep/packed-refs rename to test/integration/fetchPrune/expected/repo/.git_keep/packed-refs diff --git a/test/integration/fetchPrune/expected/repo/.git_keep/refs/heads/master b/test/integration/fetchPrune/expected/repo/.git_keep/refs/heads/master new file mode 100644 index 000000000..817ade7eb --- /dev/null +++ b/test/integration/fetchPrune/expected/repo/.git_keep/refs/heads/master @@ -0,0 +1 @@ +75f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 diff --git a/test/integration/fetchPrune/expected/repo/.git_keep/refs/heads/other_branch b/test/integration/fetchPrune/expected/repo/.git_keep/refs/heads/other_branch new file mode 100644 index 000000000..817ade7eb --- /dev/null +++ b/test/integration/fetchPrune/expected/repo/.git_keep/refs/heads/other_branch @@ -0,0 +1 @@ +75f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 diff --git a/test/integration/fetchPrune/expected/repo/.git_keep/refs/remotes/origin/master b/test/integration/fetchPrune/expected/repo/.git_keep/refs/remotes/origin/master new file mode 100644 index 000000000..817ade7eb --- /dev/null +++ b/test/integration/fetchPrune/expected/repo/.git_keep/refs/remotes/origin/master @@ -0,0 +1 @@ +75f37fc5ae7e9967e9833b66beb2c9ee2f9f6c27 diff --git a/test/integration/fetchPrune/expected/myfile1 b/test/integration/fetchPrune/expected/repo/myfile1 similarity index 100% rename from test/integration/fetchPrune/expected/myfile1 rename to test/integration/fetchPrune/expected/repo/myfile1 diff --git a/test/integration/fetchPrune/expected_remote/objects/f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 b/test/integration/fetchPrune/expected_remote/objects/f3/ff4de48fa4e8fdb4f3631e58841ba81047d8f1 deleted file mode 100644 index 3d352742a54fef71e79f7712cdc1716f1d7fa401..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121 zcmV-<0EYi~0gcT;3d0}}K+&!}#q0}Z#!N?rQVLn+7)D1Lh**M! r}>NB&Fm+Z+#DvoC!vT%v%ZcY65ciUi`;4w}w-DCZ%dP}W7frPyc b7zPJdB1Ci6bJF!sZt78%RmuDSG=MDIu$DTV diff --git a/test/integration/fetchPrune/expected_remote/packed-refs b/test/integration/fetchPrune/expected_remote/packed-refs deleted file mode 100644 index 0488de20d..000000000 --- a/test/integration/fetchPrune/expected_remote/packed-refs +++ /dev/null @@ -1,2 +0,0 @@ -# pack-refs with: peeled fully-peeled sorted -f3ff4de48fa4e8fdb4f3631e58841ba81047d8f1 refs/heads/master diff --git a/test/integration/fetchPrune/setup.sh b/test/integration/fetchPrune/setup.sh index 19d0beec7..87829a2e3 100644 --- a/test/integration/fetchPrune/setup.sh +++ b/test/integration/fetchPrune/setup.sh @@ -20,15 +20,15 @@ git checkout -b other_branch git checkout master cd .. -git clone --bare ./actual actual_remote +git clone --bare ./repo origin -cd actual +cd repo -git remote add origin ../actual_remote +git remote add origin ../origin git fetch origin git branch --set-upstream-to=origin/master master git branch --set-upstream-to=origin/other_branch other_branch # unbenownst to our test repo we're removing the branch on the remote, so upon # fetching with prune: true we expect git to realise the remote branch is gone -git -C ../actual_remote branch -d other_branch +git -C ../origin branch -d other_branch diff --git a/test/integration/fetchPrune/test.json b/test/integration/fetchPrune/test.json index e358a8c9a..3d696e153 100644 --- a/test/integration/fetchPrune/test.json +++ b/test/integration/fetchPrune/test.json @@ -1,4 +1,4 @@ { - "description": "fetch from the remote with the 'prune' option set in the git config", + "description": "fetch from the remote with the 'prune' option set in the git config. Note this has a false positive until we find a way to show ls-remote origin in all tests when creating snapshots.", "speed": 10 } diff --git a/test/integration/filterPath/expected/.git_keep/COMMIT_EDITMSG b/test/integration/filterPath/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/filterPath/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/filterPath/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/filterPath/expected/.git_keep/FETCH_HEAD b/test/integration/filterPath/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/filterPath/expected/.git_keep/FETCH_HEAD rename to test/integration/filterPath/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/filterPath/expected/.git_keep/HEAD b/test/integration/filterPath/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/filterPath/expected/.git_keep/HEAD rename to test/integration/filterPath/expected/repo/.git_keep/HEAD diff --git a/test/integration/filterPath/expected/.git_keep/config b/test/integration/filterPath/expected/repo/.git_keep/config similarity index 100% rename from test/integration/filterPath/expected/.git_keep/config rename to test/integration/filterPath/expected/repo/.git_keep/config diff --git a/test/integration/filterPath/expected/.git_keep/description b/test/integration/filterPath/expected/repo/.git_keep/description similarity index 100% rename from test/integration/filterPath/expected/.git_keep/description rename to test/integration/filterPath/expected/repo/.git_keep/description diff --git a/test/integration/filterPath/expected/.git_keep/index b/test/integration/filterPath/expected/repo/.git_keep/index similarity index 100% rename from test/integration/filterPath/expected/.git_keep/index rename to test/integration/filterPath/expected/repo/.git_keep/index diff --git a/test/integration/filterPath/expected/.git_keep/info/exclude b/test/integration/filterPath/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/filterPath/expected/.git_keep/info/exclude rename to test/integration/filterPath/expected/repo/.git_keep/info/exclude diff --git a/test/integration/filterPath/expected/.git_keep/logs/HEAD b/test/integration/filterPath/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/filterPath/expected/.git_keep/logs/HEAD rename to test/integration/filterPath/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/filterPath/expected/.git_keep/logs/refs/heads/master b/test/integration/filterPath/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/filterPath/expected/.git_keep/logs/refs/heads/master rename to test/integration/filterPath/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/filterPath/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/filterPath/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/filterPath/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/filterPath/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 b/test/integration/filterPath/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 rename to test/integration/filterPath/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 diff --git a/test/integration/filterPath/expected/.git_keep/objects/22/adc4567aba3d1a0acf28b4cef312922d516aeb b/test/integration/filterPath/expected/repo/.git_keep/objects/22/adc4567aba3d1a0acf28b4cef312922d516aeb similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/22/adc4567aba3d1a0acf28b4cef312922d516aeb rename to test/integration/filterPath/expected/repo/.git_keep/objects/22/adc4567aba3d1a0acf28b4cef312922d516aeb diff --git a/test/integration/filterPath/expected/.git_keep/objects/2e/a97a56215f6adbe991eaf0dcf61c7086880ea5 b/test/integration/filterPath/expected/repo/.git_keep/objects/2e/a97a56215f6adbe991eaf0dcf61c7086880ea5 similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/2e/a97a56215f6adbe991eaf0dcf61c7086880ea5 rename to test/integration/filterPath/expected/repo/.git_keep/objects/2e/a97a56215f6adbe991eaf0dcf61c7086880ea5 diff --git a/test/integration/filterPath/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da b/test/integration/filterPath/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da rename to test/integration/filterPath/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da diff --git a/test/integration/filterPath/expected/.git_keep/objects/4b/9d1f9f9fc76b123a5c90cd8396390cac41a3e3 b/test/integration/filterPath/expected/repo/.git_keep/objects/4b/9d1f9f9fc76b123a5c90cd8396390cac41a3e3 similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/4b/9d1f9f9fc76b123a5c90cd8396390cac41a3e3 rename to test/integration/filterPath/expected/repo/.git_keep/objects/4b/9d1f9f9fc76b123a5c90cd8396390cac41a3e3 diff --git a/test/integration/filterPath/expected/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 b/test/integration/filterPath/expected/repo/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 rename to test/integration/filterPath/expected/repo/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 diff --git a/test/integration/filterPath/expected/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 b/test/integration/filterPath/expected/repo/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 rename to test/integration/filterPath/expected/repo/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 diff --git a/test/integration/filterPath/expected/.git_keep/objects/8b/476a1094290d7251c56305e199eb2a203d8682 b/test/integration/filterPath/expected/repo/.git_keep/objects/8b/476a1094290d7251c56305e199eb2a203d8682 similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/8b/476a1094290d7251c56305e199eb2a203d8682 rename to test/integration/filterPath/expected/repo/.git_keep/objects/8b/476a1094290d7251c56305e199eb2a203d8682 diff --git a/test/integration/filterPath/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c b/test/integration/filterPath/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c rename to test/integration/filterPath/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c diff --git a/test/integration/filterPath/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/filterPath/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/filterPath/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/filterPath/expected/.git_keep/objects/af/3ef564e968dbe92fb4e08a67dd5f835f43d4e8 b/test/integration/filterPath/expected/repo/.git_keep/objects/af/3ef564e968dbe92fb4e08a67dd5f835f43d4e8 similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/af/3ef564e968dbe92fb4e08a67dd5f835f43d4e8 rename to test/integration/filterPath/expected/repo/.git_keep/objects/af/3ef564e968dbe92fb4e08a67dd5f835f43d4e8 diff --git a/test/integration/filterPath/expected/.git_keep/objects/b7/c728d5b4e9dfc210ec19f0549f25c94b766e4e b/test/integration/filterPath/expected/repo/.git_keep/objects/b7/c728d5b4e9dfc210ec19f0549f25c94b766e4e similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/b7/c728d5b4e9dfc210ec19f0549f25c94b766e4e rename to test/integration/filterPath/expected/repo/.git_keep/objects/b7/c728d5b4e9dfc210ec19f0549f25c94b766e4e diff --git a/test/integration/filterPath/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 b/test/integration/filterPath/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 rename to test/integration/filterPath/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 diff --git a/test/integration/filterPath/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/filterPath/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename to test/integration/filterPath/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 diff --git a/test/integration/filterPath/expected/.git_keep/objects/d7/236d5f85ad303f5f23141661e4c8959610b70b b/test/integration/filterPath/expected/repo/.git_keep/objects/d7/236d5f85ad303f5f23141661e4c8959610b70b similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/d7/236d5f85ad303f5f23141661e4c8959610b70b rename to test/integration/filterPath/expected/repo/.git_keep/objects/d7/236d5f85ad303f5f23141661e4c8959610b70b diff --git a/test/integration/filterPath/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/filterPath/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/filterPath/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/filterPath/expected/.git_keep/objects/f2/4812da035a21812bc4c73018349ac2f0a6ec39 b/test/integration/filterPath/expected/repo/.git_keep/objects/f2/4812da035a21812bc4c73018349ac2f0a6ec39 similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/f2/4812da035a21812bc4c73018349ac2f0a6ec39 rename to test/integration/filterPath/expected/repo/.git_keep/objects/f2/4812da035a21812bc4c73018349ac2f0a6ec39 diff --git a/test/integration/filterPath/expected/.git_keep/objects/f3/d94fa1d4be39b8daae35b82525bf357aa712de b/test/integration/filterPath/expected/repo/.git_keep/objects/f3/d94fa1d4be39b8daae35b82525bf357aa712de similarity index 100% rename from test/integration/filterPath/expected/.git_keep/objects/f3/d94fa1d4be39b8daae35b82525bf357aa712de rename to test/integration/filterPath/expected/repo/.git_keep/objects/f3/d94fa1d4be39b8daae35b82525bf357aa712de diff --git a/test/integration/filterPath/expected/.git_keep/refs/heads/master b/test/integration/filterPath/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/filterPath/expected/.git_keep/refs/heads/master rename to test/integration/filterPath/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/filterPath/expected/file b/test/integration/filterPath/expected/repo/file similarity index 100% rename from test/integration/filterPath/expected/file rename to test/integration/filterPath/expected/repo/file diff --git a/test/integration/filterPath/expected/file0 b/test/integration/filterPath/expected/repo/file0 similarity index 100% rename from test/integration/filterPath/expected/file0 rename to test/integration/filterPath/expected/repo/file0 diff --git a/test/integration/filterPath/expected/file2 b/test/integration/filterPath/expected/repo/file2 similarity index 100% rename from test/integration/filterPath/expected/file2 rename to test/integration/filterPath/expected/repo/file2 diff --git a/test/integration/filterPath2/expected/.git_keep/COMMIT_EDITMSG b/test/integration/filterPath2/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/filterPath2/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/filterPath2/expected/.git_keep/FETCH_HEAD b/test/integration/filterPath2/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/FETCH_HEAD rename to test/integration/filterPath2/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/filterPath2/expected/.git_keep/HEAD b/test/integration/filterPath2/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/HEAD rename to test/integration/filterPath2/expected/repo/.git_keep/HEAD diff --git a/test/integration/filterPath2/expected/.git_keep/config b/test/integration/filterPath2/expected/repo/.git_keep/config similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/config rename to test/integration/filterPath2/expected/repo/.git_keep/config diff --git a/test/integration/filterPath2/expected/.git_keep/description b/test/integration/filterPath2/expected/repo/.git_keep/description similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/description rename to test/integration/filterPath2/expected/repo/.git_keep/description diff --git a/test/integration/filterPath2/expected/.git_keep/index b/test/integration/filterPath2/expected/repo/.git_keep/index similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/index rename to test/integration/filterPath2/expected/repo/.git_keep/index diff --git a/test/integration/filterPath2/expected/.git_keep/info/exclude b/test/integration/filterPath2/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/info/exclude rename to test/integration/filterPath2/expected/repo/.git_keep/info/exclude diff --git a/test/integration/filterPath2/expected/.git_keep/logs/HEAD b/test/integration/filterPath2/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/logs/HEAD rename to test/integration/filterPath2/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/filterPath2/expected/.git_keep/logs/refs/heads/master b/test/integration/filterPath2/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/logs/refs/heads/master rename to test/integration/filterPath2/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/filterPath2/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/filterPath2/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/filterPath2/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/filterPath2/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 b/test/integration/filterPath2/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 rename to test/integration/filterPath2/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 diff --git a/test/integration/filterPath2/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da b/test/integration/filterPath2/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da rename to test/integration/filterPath2/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da diff --git a/test/integration/filterPath2/expected/.git_keep/objects/6c/dce80c062ba2c8f8758879834a936b84ead78c b/test/integration/filterPath2/expected/repo/.git_keep/objects/6c/dce80c062ba2c8f8758879834a936b84ead78c similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/6c/dce80c062ba2c8f8758879834a936b84ead78c rename to test/integration/filterPath2/expected/repo/.git_keep/objects/6c/dce80c062ba2c8f8758879834a936b84ead78c diff --git a/test/integration/filterPath2/expected/.git_keep/objects/70/3f7069185227287623aaba7cdb0e56ae7a6c60 b/test/integration/filterPath2/expected/repo/.git_keep/objects/70/3f7069185227287623aaba7cdb0e56ae7a6c60 similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/70/3f7069185227287623aaba7cdb0e56ae7a6c60 rename to test/integration/filterPath2/expected/repo/.git_keep/objects/70/3f7069185227287623aaba7cdb0e56ae7a6c60 diff --git a/test/integration/filterPath2/expected/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 b/test/integration/filterPath2/expected/repo/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 rename to test/integration/filterPath2/expected/repo/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 diff --git a/test/integration/filterPath2/expected/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 b/test/integration/filterPath2/expected/repo/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 rename to test/integration/filterPath2/expected/repo/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 diff --git a/test/integration/filterPath2/expected/.git_keep/objects/92/ec47058a2894afbbbd69c5f79bff20c503e686 b/test/integration/filterPath2/expected/repo/.git_keep/objects/92/ec47058a2894afbbbd69c5f79bff20c503e686 similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/92/ec47058a2894afbbbd69c5f79bff20c503e686 rename to test/integration/filterPath2/expected/repo/.git_keep/objects/92/ec47058a2894afbbbd69c5f79bff20c503e686 diff --git a/test/integration/filterPath2/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c b/test/integration/filterPath2/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c rename to test/integration/filterPath2/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c diff --git a/test/integration/filterPath2/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/filterPath2/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/filterPath2/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/filterPath2/expected/.git_keep/objects/a5/c053a7a46bce2775edb371a9aa97424b542ab7 b/test/integration/filterPath2/expected/repo/.git_keep/objects/a5/c053a7a46bce2775edb371a9aa97424b542ab7 similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/a5/c053a7a46bce2775edb371a9aa97424b542ab7 rename to test/integration/filterPath2/expected/repo/.git_keep/objects/a5/c053a7a46bce2775edb371a9aa97424b542ab7 diff --git a/test/integration/filterPath2/expected/.git_keep/objects/c5/f9a8793f15aa0db816944424adb4303eb036a8 b/test/integration/filterPath2/expected/repo/.git_keep/objects/c5/f9a8793f15aa0db816944424adb4303eb036a8 similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/c5/f9a8793f15aa0db816944424adb4303eb036a8 rename to test/integration/filterPath2/expected/repo/.git_keep/objects/c5/f9a8793f15aa0db816944424adb4303eb036a8 diff --git a/test/integration/filterPath2/expected/.git_keep/objects/c8/68546458601b9c71b76b893f9020ecf7405528 b/test/integration/filterPath2/expected/repo/.git_keep/objects/c8/68546458601b9c71b76b893f9020ecf7405528 similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/c8/68546458601b9c71b76b893f9020ecf7405528 rename to test/integration/filterPath2/expected/repo/.git_keep/objects/c8/68546458601b9c71b76b893f9020ecf7405528 diff --git a/test/integration/filterPath2/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 b/test/integration/filterPath2/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 rename to test/integration/filterPath2/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 diff --git a/test/integration/filterPath2/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/filterPath2/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename to test/integration/filterPath2/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 diff --git a/test/integration/filterPath2/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/filterPath2/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/filterPath2/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/filterPath2/expected/.git_keep/objects/e7/c2bd00356720683d5bc4362ef5b92655fa8914 b/test/integration/filterPath2/expected/repo/.git_keep/objects/e7/c2bd00356720683d5bc4362ef5b92655fa8914 similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/objects/e7/c2bd00356720683d5bc4362ef5b92655fa8914 rename to test/integration/filterPath2/expected/repo/.git_keep/objects/e7/c2bd00356720683d5bc4362ef5b92655fa8914 diff --git a/test/integration/filterPath2/expected/.git_keep/refs/heads/master b/test/integration/filterPath2/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/filterPath2/expected/.git_keep/refs/heads/master rename to test/integration/filterPath2/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/filterPath2/expected/file b/test/integration/filterPath2/expected/repo/file similarity index 100% rename from test/integration/filterPath2/expected/file rename to test/integration/filterPath2/expected/repo/file diff --git a/test/integration/filterPath2/expected/file0 b/test/integration/filterPath2/expected/repo/file0 similarity index 100% rename from test/integration/filterPath2/expected/file0 rename to test/integration/filterPath2/expected/repo/file0 diff --git a/test/integration/filterPath2/expected/file1 b/test/integration/filterPath2/expected/repo/file1 similarity index 100% rename from test/integration/filterPath2/expected/file1 rename to test/integration/filterPath2/expected/repo/file1 diff --git a/test/integration/filterPath2/expected/file2 b/test/integration/filterPath2/expected/repo/file2 similarity index 100% rename from test/integration/filterPath2/expected/file2 rename to test/integration/filterPath2/expected/repo/file2 diff --git a/test/integration/filterPath3/expected/.git_keep/COMMIT_EDITMSG b/test/integration/filterPath3/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/filterPath3/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/filterPath3/expected/.git_keep/FETCH_HEAD b/test/integration/filterPath3/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/FETCH_HEAD rename to test/integration/filterPath3/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/filterPath3/expected/.git_keep/HEAD b/test/integration/filterPath3/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/HEAD rename to test/integration/filterPath3/expected/repo/.git_keep/HEAD diff --git a/test/integration/filterPath3/expected/.git_keep/config b/test/integration/filterPath3/expected/repo/.git_keep/config similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/config rename to test/integration/filterPath3/expected/repo/.git_keep/config diff --git a/test/integration/filterPath3/expected/.git_keep/description b/test/integration/filterPath3/expected/repo/.git_keep/description similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/description rename to test/integration/filterPath3/expected/repo/.git_keep/description diff --git a/test/integration/filterPath3/expected/.git_keep/index b/test/integration/filterPath3/expected/repo/.git_keep/index similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/index rename to test/integration/filterPath3/expected/repo/.git_keep/index diff --git a/test/integration/filterPath3/expected/.git_keep/info/exclude b/test/integration/filterPath3/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/info/exclude rename to test/integration/filterPath3/expected/repo/.git_keep/info/exclude diff --git a/test/integration/filterPath3/expected/.git_keep/logs/HEAD b/test/integration/filterPath3/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/logs/HEAD rename to test/integration/filterPath3/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/filterPath3/expected/.git_keep/logs/refs/heads/master b/test/integration/filterPath3/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/logs/refs/heads/master rename to test/integration/filterPath3/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/filterPath3/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/filterPath3/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/filterPath3/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/filterPath3/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 b/test/integration/filterPath3/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 rename to test/integration/filterPath3/expected/repo/.git_keep/objects/1e/3e67b999db1576ad1ee08bf4f02bdf29e49442 diff --git a/test/integration/filterPath3/expected/.git_keep/objects/23/1410172e8f51138f06d8dff963898fb1e97b30 b/test/integration/filterPath3/expected/repo/.git_keep/objects/23/1410172e8f51138f06d8dff963898fb1e97b30 similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/23/1410172e8f51138f06d8dff963898fb1e97b30 rename to test/integration/filterPath3/expected/repo/.git_keep/objects/23/1410172e8f51138f06d8dff963898fb1e97b30 diff --git a/test/integration/filterPath3/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da b/test/integration/filterPath3/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da rename to test/integration/filterPath3/expected/repo/.git_keep/objects/38/143ad4a0fe2ab6ee53c2ef89a5d9e2bd9535da diff --git a/test/integration/filterPath3/expected/.git_keep/objects/72/226d27a85fff688d32c134a22ebe650d6c2e41 b/test/integration/filterPath3/expected/repo/.git_keep/objects/72/226d27a85fff688d32c134a22ebe650d6c2e41 similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/72/226d27a85fff688d32c134a22ebe650d6c2e41 rename to test/integration/filterPath3/expected/repo/.git_keep/objects/72/226d27a85fff688d32c134a22ebe650d6c2e41 diff --git a/test/integration/filterPath3/expected/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 b/test/integration/filterPath3/expected/repo/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 rename to test/integration/filterPath3/expected/repo/.git_keep/objects/77/9de836a10ac879fa919f48d5dc4f4ce11528e2 diff --git a/test/integration/filterPath3/expected/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 b/test/integration/filterPath3/expected/repo/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 rename to test/integration/filterPath3/expected/repo/.git_keep/objects/84/b823dc5fc92fcf08eb8c8545716232ce49bd45 diff --git a/test/integration/filterPath3/expected/.git_keep/objects/8e/d4f7b4eae8cc97d9add459348cc95e936b8f25 b/test/integration/filterPath3/expected/repo/.git_keep/objects/8e/d4f7b4eae8cc97d9add459348cc95e936b8f25 similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/8e/d4f7b4eae8cc97d9add459348cc95e936b8f25 rename to test/integration/filterPath3/expected/repo/.git_keep/objects/8e/d4f7b4eae8cc97d9add459348cc95e936b8f25 diff --git a/test/integration/filterPath3/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c b/test/integration/filterPath3/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c rename to test/integration/filterPath3/expected/repo/.git_keep/objects/9e/88a70dc8d82dd2afbfd50176ef78e18823bc2c diff --git a/test/integration/filterPath3/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/filterPath3/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/filterPath3/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/filterPath3/expected/.git_keep/objects/b3/5d7fa77c939890020952987eeb461f410297d8 b/test/integration/filterPath3/expected/repo/.git_keep/objects/b3/5d7fa77c939890020952987eeb461f410297d8 similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/b3/5d7fa77c939890020952987eeb461f410297d8 rename to test/integration/filterPath3/expected/repo/.git_keep/objects/b3/5d7fa77c939890020952987eeb461f410297d8 diff --git a/test/integration/filterPath3/expected/.git_keep/objects/c1/a1ba9d2873d7163606bb5fdf46e50975db042b b/test/integration/filterPath3/expected/repo/.git_keep/objects/c1/a1ba9d2873d7163606bb5fdf46e50975db042b similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/c1/a1ba9d2873d7163606bb5fdf46e50975db042b rename to test/integration/filterPath3/expected/repo/.git_keep/objects/c1/a1ba9d2873d7163606bb5fdf46e50975db042b diff --git a/test/integration/filterPath3/expected/.git_keep/objects/c8/68546458601b9c71b76b893f9020ecf7405528 b/test/integration/filterPath3/expected/repo/.git_keep/objects/c8/68546458601b9c71b76b893f9020ecf7405528 similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/c8/68546458601b9c71b76b893f9020ecf7405528 rename to test/integration/filterPath3/expected/repo/.git_keep/objects/c8/68546458601b9c71b76b893f9020ecf7405528 diff --git a/test/integration/filterPath3/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 b/test/integration/filterPath3/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 rename to test/integration/filterPath3/expected/repo/.git_keep/objects/d0/76cc9cc09acaa2d36fbc7a95fd3e2306494641 diff --git a/test/integration/filterPath3/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/filterPath3/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename to test/integration/filterPath3/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 diff --git a/test/integration/filterPath3/expected/.git_keep/objects/db/6681a3e9fb9fb6ef524771cdc763904dd2b54d b/test/integration/filterPath3/expected/repo/.git_keep/objects/db/6681a3e9fb9fb6ef524771cdc763904dd2b54d similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/db/6681a3e9fb9fb6ef524771cdc763904dd2b54d rename to test/integration/filterPath3/expected/repo/.git_keep/objects/db/6681a3e9fb9fb6ef524771cdc763904dd2b54d diff --git a/test/integration/filterPath3/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/filterPath3/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/filterPath3/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/filterPath3/expected/.git_keep/refs/heads/master b/test/integration/filterPath3/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/filterPath3/expected/.git_keep/refs/heads/master rename to test/integration/filterPath3/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/filterPath3/expected/file b/test/integration/filterPath3/expected/repo/file similarity index 100% rename from test/integration/filterPath3/expected/file rename to test/integration/filterPath3/expected/repo/file diff --git a/test/integration/filterPath3/expected/file0 b/test/integration/filterPath3/expected/repo/file0 similarity index 100% rename from test/integration/filterPath3/expected/file0 rename to test/integration/filterPath3/expected/repo/file0 diff --git a/test/integration/filterPath3/expected/file1 b/test/integration/filterPath3/expected/repo/file1 similarity index 100% rename from test/integration/filterPath3/expected/file1 rename to test/integration/filterPath3/expected/repo/file1 diff --git a/test/integration/filterPath3/expected/file2 b/test/integration/filterPath3/expected/repo/file2 similarity index 100% rename from test/integration/filterPath3/expected/file2 rename to test/integration/filterPath3/expected/repo/file2 diff --git a/test/integration/forcePush/expected/.git_keep/FETCH_HEAD b/test/integration/forcePush/expected/.git_keep/FETCH_HEAD deleted file mode 100644 index 8997b0d11..000000000 --- a/test/integration/forcePush/expected/.git_keep/FETCH_HEAD +++ /dev/null @@ -1 +0,0 @@ -a9848fd98935937cd7d3909023ed1b588ccd4bfb branch 'master' of ../actual_remote diff --git a/test/integration/forcePush/expected/.git_keep/ORIG_HEAD b/test/integration/forcePush/expected/.git_keep/ORIG_HEAD deleted file mode 100644 index c081af82f..000000000 --- a/test/integration/forcePush/expected/.git_keep/ORIG_HEAD +++ /dev/null @@ -1 +0,0 @@ -a9848fd98935937cd7d3909023ed1b588ccd4bfb diff --git a/test/integration/forcePush/expected/.git_keep/index b/test/integration/forcePush/expected/.git_keep/index deleted file mode 100644 index 84d23c3f4afbf4ff385625f5edc40502c1aad440..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 281 zcmZ?q402{*U|<4b=ES1Der2a!>tQq_0|P5#M9>!ohQ=if42)laYD9pTZRwuJe^pa& ze2EB+;>mZq5a89)eU*Vdw=yj=C)E(B0Hj}~Ts0R)L(B>0MmI--=Z8^)(!O&qS1k&! z>Th|aJ>NndW{wfm9GxZ8d_d-aXs9_Y=;mB9Ir<>{pV6_hSLrWKTYO21z4bZ-W{wHa zoRA<_S0E+HV60%kb&kWMklA^8Q1Yvy)6w^rrR{ukE5mzDMNUU^<< &qP HJah;EYD8cc diff --git a/test/integration/forcePush/expected/.git_keep/logs/HEAD b/test/integration/forcePush/expected/.git_keep/logs/HEAD deleted file mode 100644 index 9cef8b360..000000000 --- a/test/integration/forcePush/expected/.git_keep/logs/HEAD +++ /dev/null @@ -1,5 +0,0 @@ -0000000000000000000000000000000000000000 1fe60e6b7023a1b9751850f83ac5bda49ddd9278 CI 1634897551 +1100 commit (initial): myfile1 -1fe60e6b7023a1b9751850f83ac5bda49ddd9278 66bd8d357f6226ec264478db3606bc1c4be87e63 CI 1634897551 +1100 commit: myfile2 -66bd8d357f6226ec264478db3606bc1c4be87e63 a9848fd98935937cd7d3909023ed1b588ccd4bfb CI 1634897551 +1100 commit: myfile3 -a9848fd98935937cd7d3909023ed1b588ccd4bfb 66bd8d357f6226ec264478db3606bc1c4be87e63 CI 1634897551 +1100 reset: moving to HEAD^ -66bd8d357f6226ec264478db3606bc1c4be87e63 aed1af42535c9c6a27b9f660119452328fddd7cd CI 1634897551 +1100 commit: myfile4 diff --git a/test/integration/forcePush/expected/.git_keep/logs/refs/heads/master b/test/integration/forcePush/expected/.git_keep/logs/refs/heads/master deleted file mode 100644 index 9cef8b360..000000000 --- a/test/integration/forcePush/expected/.git_keep/logs/refs/heads/master +++ /dev/null @@ -1,5 +0,0 @@ -0000000000000000000000000000000000000000 1fe60e6b7023a1b9751850f83ac5bda49ddd9278 CI 1634897551 +1100 commit (initial): myfile1 -1fe60e6b7023a1b9751850f83ac5bda49ddd9278 66bd8d357f6226ec264478db3606bc1c4be87e63 CI 1634897551 +1100 commit: myfile2 -66bd8d357f6226ec264478db3606bc1c4be87e63 a9848fd98935937cd7d3909023ed1b588ccd4bfb CI 1634897551 +1100 commit: myfile3 -a9848fd98935937cd7d3909023ed1b588ccd4bfb 66bd8d357f6226ec264478db3606bc1c4be87e63 CI 1634897551 +1100 reset: moving to HEAD^ -66bd8d357f6226ec264478db3606bc1c4be87e63 aed1af42535c9c6a27b9f660119452328fddd7cd CI 1634897551 +1100 commit: myfile4 diff --git a/test/integration/forcePush/expected/.git_keep/logs/refs/remotes/origin/master b/test/integration/forcePush/expected/.git_keep/logs/refs/remotes/origin/master deleted file mode 100644 index 9ba3d77f4..000000000 --- a/test/integration/forcePush/expected/.git_keep/logs/refs/remotes/origin/master +++ /dev/null @@ -1,3 +0,0 @@ -0000000000000000000000000000000000000000 66bd8d357f6226ec264478db3606bc1c4be87e63 CI 1634897551 +1100 fetch origin: storing head -66bd8d357f6226ec264478db3606bc1c4be87e63 a9848fd98935937cd7d3909023ed1b588ccd4bfb CI 1634897551 +1100 update by push -a9848fd98935937cd7d3909023ed1b588ccd4bfb aed1af42535c9c6a27b9f660119452328fddd7cd CI 1634897553 +1100 update by push diff --git a/test/integration/forcePush/expected/.git_keep/objects/1f/e60e6b7023a1b9751850f83ac5bda49ddd9278 b/test/integration/forcePush/expected/.git_keep/objects/1f/e60e6b7023a1b9751850f83ac5bda49ddd9278 deleted file mode 100644 index 3c2c7f4e4..000000000 --- a/test/integration/forcePush/expected/.git_keep/objects/1f/e60e6b7023a1b9751850f83ac5bda49ddd9278 +++ /dev/null @@ -1,5 +0,0 @@ -x嵧A -0@旬s娰JF'E - mY$*}+_T~s~AMe3iw$|3J zf&8f-BATP~z=5hMMWhmvAk~ZxlSM4nW>c*PR68H?8etVQf;k%N7&65GDVUlZFCiE9 zR7xQmlj3)OY=@p^eVyjJe7NmTxhz||X+Y=GC JV#kSZgYPH5!f?!LmQeqV{yit81cMVnH7&Sxdr}oC~pJBtw~j zU6vSxP^EW&Zik*`Jx=pOKB?`i+<0qu4TLTZ!F$kG0Ati?kd=Bj<`vI?pn7SB4i Dk%vNF diff --git a/test/integration/forcePush/expected/.git_keep/objects/ae/d1af42535c9c6a27b9f660119452328fddd7cd b/test/integration/forcePush/expected/.git_keep/objects/ae/d1af42535c9c6a27b9f660119452328fddd7cd deleted file mode 100644 index 3cd0bc9f7..000000000 --- a/test/integration/forcePush/expected/.git_keep/objects/ae/d1af42535c9c6a27b9f660119452328fddd7cd +++ /dev/null @@ -1,3 +0,0 @@ -x嵨A -0@Q9澎$揑 -"BW=F2檅霖R"桧>粟谝:鮙Dm褄9荿stRB﹕f2ㄔ躺ly譝嘋j>臋漜荄1这賠*殺7譹弘'讽Y =!唨pF粗zLu37;/O%):e \ No newline at end of file diff --git a/test/integration/forcePush/expected/.git_keep/refs/heads/master b/test/integration/forcePush/expected/.git_keep/refs/heads/master deleted file mode 100644 index eaa7bcba3..000000000 --- a/test/integration/forcePush/expected/.git_keep/refs/heads/master +++ /dev/null @@ -1 +0,0 @@ -aed1af42535c9c6a27b9f660119452328fddd7cd diff --git a/test/integration/forcePush/expected/.git_keep/refs/remotes/origin/master b/test/integration/forcePush/expected/.git_keep/refs/remotes/origin/master deleted file mode 100644 index eaa7bcba3..000000000 --- a/test/integration/forcePush/expected/.git_keep/refs/remotes/origin/master +++ /dev/null @@ -1 +0,0 @@ -aed1af42535c9c6a27b9f660119452328fddd7cd diff --git a/test/integration/forcePush/expected/.git_keep/HEAD b/test/integration/forcePush/expected/origin/HEAD similarity index 100% rename from test/integration/forcePush/expected/.git_keep/HEAD rename to test/integration/forcePush/expected/origin/HEAD diff --git a/test/integration/pull/expected_remote/config b/test/integration/forcePush/expected/origin/config similarity index 78% rename from test/integration/pull/expected_remote/config rename to test/integration/forcePush/expected/origin/config index 94ceda391..5b015dc91 100644 --- a/test/integration/pull/expected_remote/config +++ b/test/integration/forcePush/expected/origin/config @@ -5,4 +5,4 @@ ignorecase = true precomposeunicode = true [remote "origin"] - url = /Users/jesseduffieldduffield/go/src/github.com/jesseduffield/lazygit/test/integration/pull/./actual + url = /Users/jesseduffieldduffield/go/src/github.com/jesseduffield/lazygit/test/integration/forcePush/actual/./repo diff --git a/test/integration/forcePush/expected/.git_keep/description b/test/integration/forcePush/expected/origin/description similarity index 100% rename from test/integration/forcePush/expected/.git_keep/description rename to test/integration/forcePush/expected/origin/description diff --git a/test/integration/forcePush/expected/.git_keep/info/exclude b/test/integration/forcePush/expected/origin/info/exclude similarity index 100% rename from test/integration/forcePush/expected/.git_keep/info/exclude rename to test/integration/forcePush/expected/origin/info/exclude diff --git a/test/integration/forcePush/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/forcePush/expected/origin/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/forcePush/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/forcePush/expected/origin/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/forcePush/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/forcePush/expected/origin/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/forcePush/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/forcePush/expected/origin/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/forcePush/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/forcePush/expected/origin/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce similarity index 100% rename from test/integration/forcePush/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce rename to test/integration/forcePush/expected/origin/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce diff --git a/test/integration/forcePush/expected/origin/objects/55/58e3589b913d8280499a5f9bf698971a83c5bd b/test/integration/forcePush/expected/origin/objects/55/58e3589b913d8280499a5f9bf698971a83c5bd new file mode 100644 index 0000000000000000000000000000000000000000..901f430029d2e4a3fe6ccfe3378f4c1b51549a7f GIT binary patch literal 121 zcmV-<0EYi~0gcT;3WG2ZK+qirE*+OdQ7ur4(FwjF?QQ;1H1%+S}J7bo+VmQ#D%~ z5X+? n~V3cJTHDqR`AUTkaR0dwS%fcn5-n;m2uX?~V!+n~c`iZu0dP~(FK*FKx bJ>m#gB1CuAbJFxr?(AFEP09TLFwrctScMzn7}yiC(dxA8Px`x4N~vhUn1+YfRQx0AtiiBIT>Z*NZS=p-}DwaCt Dn L4Z)S$HQ+{;yq!mIjQ zUTM#_P=}dg1T{yNRm~V=4v2=DGZEdKOD0Djg#R--R`x3W#c7K#NwK$HhrrA+0h$vM z ( literal 0 HcmV?d00001 diff --git a/test/integration/forcePush/expected_remote/info/exclude b/test/integration/forcePush/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/forcePush/expected_remote/info/exclude rename to test/integration/forcePush/expected/repo/.git_keep/info/exclude diff --git a/test/integration/forcePush/expected/repo/.git_keep/logs/HEAD b/test/integration/forcePush/expected/repo/.git_keep/logs/HEAD new file mode 100644 index 000000000..bccf225e5 --- /dev/null +++ b/test/integration/forcePush/expected/repo/.git_keep/logs/HEAD @@ -0,0 +1,5 @@ +0000000000000000000000000000000000000000 5558e3589b913d8280499a5f9bf698971a83c5bd CI 1648352009 +1100 commit (initial): myfile1 +5558e3589b913d8280499a5f9bf698971a83c5bd 77ead8cf99f5fa1084e9ffa40eb18f37157b22c8 CI 1648352009 +1100 commit: myfile2 +77ead8cf99f5fa1084e9ffa40eb18f37157b22c8 b8568c2ecaef7e2f47647057ad47b040e8c5df53 CI 1648352009 +1100 commit: myfile3 +b8568c2ecaef7e2f47647057ad47b040e8c5df53 77ead8cf99f5fa1084e9ffa40eb18f37157b22c8 CI 1648352009 +1100 reset: moving to HEAD^ +77ead8cf99f5fa1084e9ffa40eb18f37157b22c8 e38b0dbe9634034957d8ebe0088587abd9ae938d CI 1648352009 +1100 commit: myfile4 diff --git a/test/integration/forcePush/expected/repo/.git_keep/logs/refs/heads/master b/test/integration/forcePush/expected/repo/.git_keep/logs/refs/heads/master new file mode 100644 index 000000000..bccf225e5 --- /dev/null +++ b/test/integration/forcePush/expected/repo/.git_keep/logs/refs/heads/master @@ -0,0 +1,5 @@ +0000000000000000000000000000000000000000 5558e3589b913d8280499a5f9bf698971a83c5bd CI 1648352009 +1100 commit (initial): myfile1 +5558e3589b913d8280499a5f9bf698971a83c5bd 77ead8cf99f5fa1084e9ffa40eb18f37157b22c8 CI 1648352009 +1100 commit: myfile2 +77ead8cf99f5fa1084e9ffa40eb18f37157b22c8 b8568c2ecaef7e2f47647057ad47b040e8c5df53 CI 1648352009 +1100 commit: myfile3 +b8568c2ecaef7e2f47647057ad47b040e8c5df53 77ead8cf99f5fa1084e9ffa40eb18f37157b22c8 CI 1648352009 +1100 reset: moving to HEAD^ +77ead8cf99f5fa1084e9ffa40eb18f37157b22c8 e38b0dbe9634034957d8ebe0088587abd9ae938d CI 1648352009 +1100 commit: myfile4 diff --git a/test/integration/forcePush/expected/repo/.git_keep/logs/refs/remotes/origin/master b/test/integration/forcePush/expected/repo/.git_keep/logs/refs/remotes/origin/master new file mode 100644 index 000000000..006c9dee8 --- /dev/null +++ b/test/integration/forcePush/expected/repo/.git_keep/logs/refs/remotes/origin/master @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 77ead8cf99f5fa1084e9ffa40eb18f37157b22c8 CI 1648352009 +1100 fetch origin: storing head +77ead8cf99f5fa1084e9ffa40eb18f37157b22c8 b8568c2ecaef7e2f47647057ad47b040e8c5df53 CI 1648352009 +1100 update by push +b8568c2ecaef7e2f47647057ad47b040e8c5df53 e38b0dbe9634034957d8ebe0088587abd9ae938d CI 1648352011 +1100 update by push diff --git a/test/integration/forcePush/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/forcePush/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/forcePush/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/forcePush/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/forcePush/expected_remote/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/forcePush/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/forcePush/expected_remote/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/forcePush/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/forcePush/expected_remote/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/forcePush/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce similarity index 100% rename from test/integration/forcePush/expected_remote/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce rename to test/integration/forcePush/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce diff --git a/test/integration/forcePush/expected/repo/.git_keep/objects/55/58e3589b913d8280499a5f9bf698971a83c5bd b/test/integration/forcePush/expected/repo/.git_keep/objects/55/58e3589b913d8280499a5f9bf698971a83c5bd new file mode 100644 index 0000000000000000000000000000000000000000..901f430029d2e4a3fe6ccfe3378f4c1b51549a7f GIT binary patch literal 121 zcmV-<0EYi~0gcT;3WG2ZK+qirE*+OdQ7ur4(FwjF?QQ;1H1%+S}J7bo+VmQ#D%~ z5X+? n~V3cJTHDqR`AUTkaR0dwS%fcn5-n;m2uX?~V!+n~c`iZu0dP~(FK*FKx bJ>m#gB1CuAbJFxr?(AFEP09TLFwrctScMzn7}yiC(dxA8Px`x4N~vhUn1+YfRQx0AtiiBIT>Z*NZS=p-}DwaCt Dn mY$*}+_T~s~AMe3iw$|3J zf&8f-BATP~z=5hMMWhmvAk~ZxlSM4nW>c*PR68H?8etVQf;k%N7&65GDVUlZFCiE9 zR7xQmlj3)OY=@p^eVyjJe7NmTxhz||X+Y=GC JV#kSZgYPH5!f?!LmQeqV{yit81cMVnH7&Sxdr}oC~pJBtw~j zU6vSxP^EW&Zik*`Jx=pOKB?`i+<0qu4TLTZ!F$kG0Ati?kd=Bj<`vI?pn7SB4i Dk%vNF diff --git a/test/integration/forcePush/expected_remote/objects/ae/d1af42535c9c6a27b9f660119452328fddd7cd b/test/integration/forcePush/expected_remote/objects/ae/d1af42535c9c6a27b9f660119452328fddd7cd deleted file mode 100644 index 3cd0bc9f7..000000000 --- a/test/integration/forcePush/expected_remote/objects/ae/d1af42535c9c6a27b9f660119452328fddd7cd +++ /dev/null @@ -1,3 +0,0 @@ -x嵨A -0@Q9澎$揑 -"BW=F2檅霖R"桧>粟谝:鮙Dm褄9荿stRB﹕f2ㄔ躺ly譝嘋j>臋漜荄1这賠*殺7譹弘'讽Y =!唨pF粗zLu37;/O%):e \ No newline at end of file diff --git a/test/integration/forcePush/expected_remote/packed-refs b/test/integration/forcePush/expected_remote/packed-refs deleted file mode 100644 index 7a7114a0a..000000000 --- a/test/integration/forcePush/expected_remote/packed-refs +++ /dev/null @@ -1,2 +0,0 @@ -# pack-refs with: peeled fully-peeled sorted -66bd8d357f6226ec264478db3606bc1c4be87e63 refs/heads/master diff --git a/test/integration/forcePush/expected_remote/refs/heads/master b/test/integration/forcePush/expected_remote/refs/heads/master deleted file mode 100644 index eaa7bcba3..000000000 --- a/test/integration/forcePush/expected_remote/refs/heads/master +++ /dev/null @@ -1 +0,0 @@ -aed1af42535c9c6a27b9f660119452328fddd7cd diff --git a/test/integration/forcePush/setup.sh b/test/integration/forcePush/setup.sh index 74192c316..2856859ca 100644 --- a/test/integration/forcePush/setup.sh +++ b/test/integration/forcePush/setup.sh @@ -19,11 +19,11 @@ git add . git commit -am "myfile2" cd .. -git clone --bare ./actual actual_remote +git clone --bare ./repo origin -cd actual +cd repo -git remote add origin ../actual_remote +git remote add origin ../origin git fetch origin git branch --set-upstream-to=origin/master master diff --git a/test/integration/forcePushMultiple/expected/.git_keep/FETCH_HEAD b/test/integration/forcePushMultiple/expected/.git_keep/FETCH_HEAD deleted file mode 100644 index d56304e09..000000000 --- a/test/integration/forcePushMultiple/expected/.git_keep/FETCH_HEAD +++ /dev/null @@ -1,2 +0,0 @@ -b82ed4a67bef9ef50807adf409f103ef7b0832ab branch 'master' of ../actual_remote -d3708eeec2b9d69acbe87862330e844e85f77de1 not-for-merge branch 'other_branch' of ../actual_remote diff --git a/test/integration/forcePushMultiple/expected/.git_keep/ORIG_HEAD b/test/integration/forcePushMultiple/expected/.git_keep/ORIG_HEAD deleted file mode 100644 index 3774ff3d1..000000000 --- a/test/integration/forcePushMultiple/expected/.git_keep/ORIG_HEAD +++ /dev/null @@ -1 +0,0 @@ -d3708eeec2b9d69acbe87862330e844e85f77de1 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/index b/test/integration/forcePushMultiple/expected/.git_keep/index deleted file mode 100644 index 375819d60017e3e32da674025180ba89508246c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 209 zcmZ?q402{*U|<5_B>Q#j8jJQmhtZ4-46ICZb>$cs8kaCIFn$H95dmVhrF$O#RZYF| zB_cG6C*SEpfLBZRRR;Fl%CyX!R70QwkbcdpmqK7P)ErZEb0m0v7&R#EJNI(cqVTHz zmRH*IE!1J=7y-=*337D>Qj!ct3I<%uO{5|}+ 1648340487 +1100 commit (initial): myfile1 -16d8875e19987b16f1991a41fd3f4536d16f7cb4 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 commit: myfile2 -42d408cffcc087da21115f9ebc29e9765a2beb83 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 checkout: moving from master to other_branch -42d408cffcc087da21115f9ebc29e9765a2beb83 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 checkout: moving from other_branch to master -42d408cffcc087da21115f9ebc29e9765a2beb83 b82ed4a67bef9ef50807adf409f103ef7b0832ab CI 1648340487 +1100 commit: myfile3 -b82ed4a67bef9ef50807adf409f103ef7b0832ab 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 reset: moving to HEAD^ -42d408cffcc087da21115f9ebc29e9765a2beb83 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 checkout: moving from master to other_branch -42d408cffcc087da21115f9ebc29e9765a2beb83 d3708eeec2b9d69acbe87862330e844e85f77de1 CI 1648340487 +1100 commit: myfile4 -d3708eeec2b9d69acbe87862330e844e85f77de1 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 reset: moving to HEAD^ -42d408cffcc087da21115f9ebc29e9765a2beb83 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 checkout: moving from other_branch to master diff --git a/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/master b/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/master deleted file mode 100644 index 15de170c8..000000000 --- a/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/master +++ /dev/null @@ -1,4 +0,0 @@ -0000000000000000000000000000000000000000 16d8875e19987b16f1991a41fd3f4536d16f7cb4 CI 1648340487 +1100 commit (initial): myfile1 -16d8875e19987b16f1991a41fd3f4536d16f7cb4 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 commit: myfile2 -42d408cffcc087da21115f9ebc29e9765a2beb83 b82ed4a67bef9ef50807adf409f103ef7b0832ab CI 1648340487 +1100 commit: myfile3 -b82ed4a67bef9ef50807adf409f103ef7b0832ab 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 reset: moving to HEAD^ diff --git a/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/other_branch b/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/other_branch deleted file mode 100644 index 78ea80b06..000000000 --- a/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/heads/other_branch +++ /dev/null @@ -1,3 +0,0 @@ -0000000000000000000000000000000000000000 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 branch: Created from HEAD -42d408cffcc087da21115f9ebc29e9765a2beb83 d3708eeec2b9d69acbe87862330e844e85f77de1 CI 1648340487 +1100 commit: myfile4 -d3708eeec2b9d69acbe87862330e844e85f77de1 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 reset: moving to HEAD^ diff --git a/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/master b/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/master deleted file mode 100644 index dd0a1b736..000000000 --- a/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/master +++ /dev/null @@ -1,3 +0,0 @@ -0000000000000000000000000000000000000000 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 fetch origin: storing head -42d408cffcc087da21115f9ebc29e9765a2beb83 b82ed4a67bef9ef50807adf409f103ef7b0832ab CI 1648340487 +1100 update by push -b82ed4a67bef9ef50807adf409f103ef7b0832ab 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340489 +1100 update by push diff --git a/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/other_branch b/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/other_branch deleted file mode 100644 index ca4e1389e..000000000 --- a/test/integration/forcePushMultiple/expected/.git_keep/logs/refs/remotes/origin/other_branch +++ /dev/null @@ -1,3 +0,0 @@ -0000000000000000000000000000000000000000 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340487 +1100 fetch origin: storing head -42d408cffcc087da21115f9ebc29e9765a2beb83 d3708eeec2b9d69acbe87862330e844e85f77de1 CI 1648340487 +1100 update by push -d3708eeec2b9d69acbe87862330e844e85f77de1 42d408cffcc087da21115f9ebc29e9765a2beb83 CI 1648340489 +1100 update by push diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/16/d8875e19987b16f1991a41fd3f4536d16f7cb4 b/test/integration/forcePushMultiple/expected/.git_keep/objects/16/d8875e19987b16f1991a41fd3f4536d16f7cb4 deleted file mode 100644 index b72fd3fa1..000000000 --- a/test/integration/forcePushMultiple/expected/.git_keep/objects/16/d8875e19987b16f1991a41fd3f4536d16f7cb4 +++ /dev/null @@ -1,2 +0,0 @@ -x嵧A -0@旬s娰蕦N'))蛤c2!")刿#t鹹餭-ei@,椂毮*XH蘁AR燦){灩O耏憬s鷌锖8羢淾vh賄慌Z 嵝3r餻%Btg='威洚|蟛3, \ No newline at end of file diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 b/test/integration/forcePushMultiple/expected/.git_keep/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 deleted file mode 100644 index 31d3fad7a..000000000 --- a/test/integration/forcePushMultiple/expected/.git_keep/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 +++ /dev/null @@ -1,3 +0,0 @@ -x崕A - E祸叛扫J!C &眄蝴<黣痷m"^谏瑩wi坆Ja朒)J&Gk婡闔'亢H%?0| !Hq們R慱2n淆杂i~'誧阚沧{呃嘈`瘊 -`岅礋j黦]寨[屷9 \ No newline at end of file diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/b8/2ed4a67bef9ef50807adf409f103ef7b0832ab b/test/integration/forcePushMultiple/expected/.git_keep/objects/b8/2ed4a67bef9ef50807adf409f103ef7b0832ab deleted file mode 100644 index 55c8270daa81e5e4cdcaa1b2eeeabcb4f7b732e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149 zcmV;G0BZku0gaA93c@fD06pgwxeJobrp*RKgr540WV4F}V@rvkzqe2DG%(Czcx`Rz z7E(C%UBvnV5t&A)8W1%HRLvDo$uSiK&%;3$v*lf0-3DKSBUWX06l?YXFlds(K1qt> zkbRLtX!5&1*4<9Cy-xF8KDljAx$xR<7REprT%c&r0M41i9#dWZ%uW01@)R^bRRB9O DRux1N diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/d3/708eeec2b9d69acbe87862330e844e85f77de1 b/test/integration/forcePushMultiple/expected/.git_keep/objects/d3/708eeec2b9d69acbe87862330e844e85f77de1 deleted file mode 100644 index e36f500bdd0daf555f8c0a188d92b5d2cc80531d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149 zcmV;G0BZku0gaAJ3c@fDKwak)*$a|MCO;4ny6Q0|lL;1#EhU29-X6j2 b`B2}Ua^bb#Gz3fz&5_k-0AtiakEtPl>Z*U+@)T4*8fiM= D)tx}L diff --git a/test/integration/forcePushMultiple/expected/.git_keep/refs/heads/master b/test/integration/forcePushMultiple/expected/.git_keep/refs/heads/master deleted file mode 100644 index f9339e7e2..000000000 --- a/test/integration/forcePushMultiple/expected/.git_keep/refs/heads/master +++ /dev/null @@ -1 +0,0 @@ -42d408cffcc087da21115f9ebc29e9765a2beb83 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/refs/heads/other_branch b/test/integration/forcePushMultiple/expected/.git_keep/refs/heads/other_branch deleted file mode 100644 index f9339e7e2..000000000 --- a/test/integration/forcePushMultiple/expected/.git_keep/refs/heads/other_branch +++ /dev/null @@ -1 +0,0 @@ -42d408cffcc087da21115f9ebc29e9765a2beb83 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/master b/test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/master deleted file mode 100644 index f9339e7e2..000000000 --- a/test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/master +++ /dev/null @@ -1 +0,0 @@ -42d408cffcc087da21115f9ebc29e9765a2beb83 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/other_branch b/test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/other_branch deleted file mode 100644 index f9339e7e2..000000000 --- a/test/integration/forcePushMultiple/expected/.git_keep/refs/remotes/origin/other_branch +++ /dev/null @@ -1 +0,0 @@ -42d408cffcc087da21115f9ebc29e9765a2beb83 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/16/d8875e19987b16f1991a41fd3f4536d16f7cb4 b/test/integration/forcePushMultiple/expected_remote/objects/16/d8875e19987b16f1991a41fd3f4536d16f7cb4 deleted file mode 100644 index b72fd3fa1..000000000 --- a/test/integration/forcePushMultiple/expected_remote/objects/16/d8875e19987b16f1991a41fd3f4536d16f7cb4 +++ /dev/null @@ -1,2 +0,0 @@ -x嵧A -0@旬s娰蕦N'))蛤c2!")刿#t鹹餭-ei@,椂毮*XH蘁AR燦){灩O耏憬s鷌锖8羢淾vh賄慌Z 嵝3r餻%Btg='威洚|蟛3, \ No newline at end of file diff --git a/test/integration/forcePushMultiple/expected_remote/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 b/test/integration/forcePushMultiple/expected_remote/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 deleted file mode 100644 index 31d3fad7a..000000000 --- a/test/integration/forcePushMultiple/expected_remote/objects/42/d408cffcc087da21115f9ebc29e9765a2beb83 +++ /dev/null @@ -1,3 +0,0 @@ -x崕A - E祸叛扫J!C &眄蝴<黣痷m"^谏瑩wi坆Ja朒)J&Gk婡闔'亢H%?0| !Hq們R慱2n淆杂i~'誧阚沧{呃嘈`瘊 -`岅礋j黦]寨[屷9 \ No newline at end of file diff --git a/test/integration/forcePushMultiple/expected_remote/objects/b8/2ed4a67bef9ef50807adf409f103ef7b0832ab b/test/integration/forcePushMultiple/expected_remote/objects/b8/2ed4a67bef9ef50807adf409f103ef7b0832ab deleted file mode 100644 index 55c8270daa81e5e4cdcaa1b2eeeabcb4f7b732e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149 zcmV;G0BZku0gaA93c@fD06pgwxeJobrp*RKgr540WV4F}V@rvkzqe2DG%(Czcx`Rz z7E(C%UBvnV5t&A)8W1%HRLvDo$uSiK&%;3$v*lf0-3DKSBUWX06l?YXFlds(K1qt> zkbRLtX!5&1*4<9Cy-xF8KDljAx$xR<7REprT%c&r0M41i9#dWZ%uW01@)R^bRRB9O DRux1N diff --git a/test/integration/forcePushMultiple/expected_remote/objects/d3/708eeec2b9d69acbe87862330e844e85f77de1 b/test/integration/forcePushMultiple/expected_remote/objects/d3/708eeec2b9d69acbe87862330e844e85f77de1 deleted file mode 100644 index e36f500bdd0daf555f8c0a188d92b5d2cc80531d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149 zcmV;G0BZku0gaAJ3c@fDKwak)*$a|MCO;4ny6Q0|lL;1#EhU29-X6j2 b`B2}Ua^bb#Gz3fz&5_k-0AtiakEtPl>Z*U+@)T4*8fiM= D)tx}L diff --git a/test/integration/forcePushMultiple/expected_remote/packed-refs b/test/integration/forcePushMultiple/expected_remote/packed-refs deleted file mode 100644 index 07ff7e761..000000000 --- a/test/integration/forcePushMultiple/expected_remote/packed-refs +++ /dev/null @@ -1,3 +0,0 @@ -# pack-refs with: peeled fully-peeled sorted -42d408cffcc087da21115f9ebc29e9765a2beb83 refs/heads/master -42d408cffcc087da21115f9ebc29e9765a2beb83 refs/heads/other_branch diff --git a/test/integration/forcePushMultiple/expected_remote/refs/heads/master b/test/integration/forcePushMultiple/expected_remote/refs/heads/master deleted file mode 100644 index f9339e7e2..000000000 --- a/test/integration/forcePushMultiple/expected_remote/refs/heads/master +++ /dev/null @@ -1 +0,0 @@ -42d408cffcc087da21115f9ebc29e9765a2beb83 diff --git a/test/integration/forcePushMultiple/expected_remote/refs/heads/other_branch b/test/integration/forcePushMultiple/expected_remote/refs/heads/other_branch deleted file mode 100644 index f9339e7e2..000000000 --- a/test/integration/forcePushMultiple/expected_remote/refs/heads/other_branch +++ /dev/null @@ -1 +0,0 @@ -42d408cffcc087da21115f9ebc29e9765a2beb83 diff --git a/test/integration/forcePushMultiple/recording.json b/test/integration/forcePushMultiple/recording.json deleted file mode 100644 index dd0070f15..000000000 --- a/test/integration/forcePushMultiple/recording.json +++ /dev/null @@ -1 +0,0 @@ -{"KeyEvents":[{"Timestamp":591,"Mod":0,"Key":256,"Ch":80},{"Timestamp":1207,"Mod":0,"Key":13,"Ch":13},{"Timestamp":1990,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":272,"Height":74}]} \ No newline at end of file diff --git a/test/integration/forcePushMultiple/expected/.git_keep/HEAD b/test/integration/forcePushMultipleMatching/expected/origin/HEAD similarity index 100% rename from test/integration/forcePushMultiple/expected/.git_keep/HEAD rename to test/integration/forcePushMultipleMatching/expected/origin/HEAD diff --git a/test/integration/forcePushMultipleMatching/expected/origin/config b/test/integration/forcePushMultipleMatching/expected/origin/config new file mode 100644 index 000000000..41711784a --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/origin/config @@ -0,0 +1,8 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true + ignorecase = true + precomposeunicode = true +[remote "origin"] + url = /Users/jesseduffieldduffield/go/src/github.com/jesseduffield/lazygit/test/integration/forcePushMultiple/actual/./repo diff --git a/test/integration/forcePushMultiple/expected/.git_keep/description b/test/integration/forcePushMultipleMatching/expected/origin/description similarity index 100% rename from test/integration/forcePushMultiple/expected/.git_keep/description rename to test/integration/forcePushMultipleMatching/expected/origin/description diff --git a/test/integration/forcePushMultiple/expected/.git_keep/info/exclude b/test/integration/forcePushMultipleMatching/expected/origin/info/exclude similarity index 100% rename from test/integration/forcePushMultiple/expected/.git_keep/info/exclude rename to test/integration/forcePushMultipleMatching/expected/origin/info/exclude diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/forcePushMultipleMatching/expected/origin/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/forcePushMultiple/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/forcePushMultipleMatching/expected/origin/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/forcePushMultipleMatching/expected/origin/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/forcePushMultiple/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/forcePushMultipleMatching/expected/origin/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/forcePushMultipleMatching/expected/origin/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce similarity index 100% rename from test/integration/forcePushMultiple/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce rename to test/integration/forcePushMultipleMatching/expected/origin/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce diff --git a/test/integration/forcePushMultipleMatching/expected/origin/objects/7a/35f0bb6bd8dc18ae462465e51f02362ba6babe b/test/integration/forcePushMultipleMatching/expected/origin/objects/7a/35f0bb6bd8dc18ae462465e51f02362ba6babe new file mode 100644 index 000000000..c58bcbe9b --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/origin/objects/7a/35f0bb6bd8dc18ae462465e51f02362ba6babe @@ -0,0 +1,2 @@ +x嵧A +0@旬s娰J&N\y1橮!ER雄#t鹹餝5[ 癀m昐衤s?h藾姂s Xz毄薒E=8w輅溹1N/菖>R' S靐爛pE艮濙4龘;;什*2K, \ No newline at end of file diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/forcePushMultipleMatching/expected/origin/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/forcePushMultiple/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/forcePushMultipleMatching/expected/origin/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 b/test/integration/forcePushMultipleMatching/expected/origin/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 similarity index 100% rename from test/integration/forcePushMultiple/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 rename to test/integration/forcePushMultipleMatching/expected/origin/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 diff --git a/test/integration/forcePushMultipleMatching/expected/origin/objects/bd/739fb752ed02ccd49422196e31599c87ff90ad b/test/integration/forcePushMultipleMatching/expected/origin/objects/bd/739fb752ed02ccd49422196e31599c87ff90ad new file mode 100644 index 0000000000000000000000000000000000000000..fcaa0a8780d24739d5ad11f70a44f6b751a3e800 GIT binary patch literal 149 zcmV;G0BZku0gaAJ3c@fH0A1%4*$a~QX+9t#bk$>|$$MBZwv-5ZdwT>|1H&w)tgS8G zLgG{3MJ&z`s6-D{nMgB}YOX*UU5PURmf>I#v*lf0-HH!N%*vRx&LNc;@{pV&4ivyU zWT>%vF!|jd>u$%%UdQP!pWL>mT*}&R7CcAd#0d5b;G8+^G1cYI+_bMQPa*RI@IE?2 DVyi~F literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 b/test/integration/forcePushMultipleMatching/expected/origin/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 similarity index 100% rename from test/integration/forcePushMultiple/expected/.git_keep/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 rename to test/integration/forcePushMultipleMatching/expected/origin/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/forcePushMultipleMatching/expected/origin/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 similarity index 100% rename from test/integration/forcePushMultiple/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename to test/integration/forcePushMultipleMatching/expected/origin/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/forcePushMultipleMatching/expected/origin/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/forcePushMultiple/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/forcePushMultipleMatching/expected/origin/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/forcePushMultipleMatching/expected/origin/objects/e6/7f344f42afdb79c87a590f22537160241d8d61 b/test/integration/forcePushMultipleMatching/expected/origin/objects/e6/7f344f42afdb79c87a590f22537160241d8d61 new file mode 100644 index 0000000000000000000000000000000000000000..e1d86f23c77acd71d78937ead55b7b794285b9ff GIT binary patch literal 150 zcmV;H0BQet0gcW<3c@fDKvCB@MfQSZCdo7b5uvLdW2Tv4!PrtF= 4Sa&;4_Bu{?{czi!dYRXDvp^yFkOP7}12|`ndQ5fwlbiOf%Tv+(00iJV Eq{C-O9{>OV literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultipleMatching/expected/origin/objects/fe/67c3eaf819025990d3688d5f147a064e669ca5 b/test/integration/forcePushMultipleMatching/expected/origin/objects/fe/67c3eaf819025990d3688d5f147a064e669ca5 new file mode 100644 index 0000000000000000000000000000000000000000..114e72ec5c45d8d5f3a8a642b646b236307422c1 GIT binary patch literal 150 zcmV;H0BQet0gcW<3d0}}K+&!}h5JHrbQ~2*DP)ynj5^XlZ9=fn-o80Px1YE8W$k?# z8WNtyE~1N=h%tb1=s0*wPB_?-eXfm(C?_eEDXNWkc?~TTnnP@8xz!v}iGh7G&06mQ zkg*6gRszNE@mO~~&H6gcclmJNo^mN`ziA+h4ij3?X8>c=QIDx1e{$8oZFvf+AGN1B E^6vXZ4*&oF literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultipleMatching/expected/origin/packed-refs b/test/integration/forcePushMultipleMatching/expected/origin/packed-refs new file mode 100644 index 000000000..970c0dc0b --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/origin/packed-refs @@ -0,0 +1,3 @@ +# pack-refs with: peeled fully-peeled sorted +e67f344f42afdb79c87a590f22537160241d8d61 refs/heads/master +e67f344f42afdb79c87a590f22537160241d8d61 refs/heads/other_branch diff --git a/test/integration/forcePushMultipleMatching/expected/origin/refs/heads/master b/test/integration/forcePushMultipleMatching/expected/origin/refs/heads/master new file mode 100644 index 000000000..51eb490a4 --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/origin/refs/heads/master @@ -0,0 +1 @@ +e67f344f42afdb79c87a590f22537160241d8d61 diff --git a/test/integration/forcePushMultipleMatching/expected/origin/refs/heads/other_branch b/test/integration/forcePushMultipleMatching/expected/origin/refs/heads/other_branch new file mode 100644 index 000000000..51eb490a4 --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/origin/refs/heads/other_branch @@ -0,0 +1 @@ +e67f344f42afdb79c87a590f22537160241d8d61 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/COMMIT_EDITMSG b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/forcePushMultiple/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/forcePushMultipleMatching/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/FETCH_HEAD b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/FETCH_HEAD new file mode 100644 index 000000000..0a4e5da7e --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/FETCH_HEAD @@ -0,0 +1,2 @@ +bd739fb752ed02ccd49422196e31599c87ff90ad branch 'master' of ../origin +fe67c3eaf819025990d3688d5f147a064e669ca5 not-for-merge branch 'other_branch' of ../origin diff --git a/test/integration/forcePushMultiple/expected_remote/HEAD b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/forcePushMultiple/expected_remote/HEAD rename to test/integration/forcePushMultipleMatching/expected/repo/.git_keep/HEAD diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/ORIG_HEAD b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/ORIG_HEAD new file mode 100644 index 000000000..e7aee65c4 --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/ORIG_HEAD @@ -0,0 +1 @@ +fe67c3eaf819025990d3688d5f147a064e669ca5 diff --git a/test/integration/forcePushMultiple/expected/.git_keep/config b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/config similarity index 94% rename from test/integration/forcePushMultiple/expected/.git_keep/config rename to test/integration/forcePushMultipleMatching/expected/repo/.git_keep/config index 740ff301f..2be68507e 100644 --- a/test/integration/forcePushMultiple/expected/.git_keep/config +++ b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/config @@ -11,7 +11,7 @@ [push] default = matching [remote "origin"] - url = ../actual_remote + url = ../origin fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin diff --git a/test/integration/forcePushMultiple/expected_remote/description b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/description similarity index 100% rename from test/integration/forcePushMultiple/expected_remote/description rename to test/integration/forcePushMultipleMatching/expected/repo/.git_keep/description diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/index b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/index new file mode 100644 index 0000000000000000000000000000000000000000..5c83b42dcdec4a11995f594f24a2642f6a783553 GIT binary patch literal 209 zcmZ?q402{*U|<5_B>M|*b!IP`45Jwt7+9I+xfnArG%jIaVEhVHBLc*1OZPnftD1V_ zOGIcCPrlQI0I!zrs|@V9m1&tdsfIuWApN=(`@g_ws5xHf=1B1TFltcRckbn?Md4Nb zEw8laTd2d#F#?(s66ER%q$C-P6b!hQn@B}|xclyB=Ck?R%$m|JY4fXyDb>H&;-*~t SdW!pwS2n-fS#x%kRsaA`97+%X literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected_remote/info/exclude b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/forcePushMultiple/expected_remote/info/exclude rename to test/integration/forcePushMultipleMatching/expected/repo/.git_keep/info/exclude diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/HEAD b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/HEAD new file mode 100644 index 000000000..fa818156f --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/HEAD @@ -0,0 +1,10 @@ +0000000000000000000000000000000000000000 7a35f0bb6bd8dc18ae462465e51f02362ba6babe CI 1648349421 +1100 commit (initial): myfile1 +7a35f0bb6bd8dc18ae462465e51f02362ba6babe e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349421 +1100 commit: myfile2 +e67f344f42afdb79c87a590f22537160241d8d61 e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349421 +1100 checkout: moving from master to other_branch +e67f344f42afdb79c87a590f22537160241d8d61 e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349421 +1100 checkout: moving from other_branch to master +e67f344f42afdb79c87a590f22537160241d8d61 bd739fb752ed02ccd49422196e31599c87ff90ad CI 1648349421 +1100 commit: myfile3 +bd739fb752ed02ccd49422196e31599c87ff90ad e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349421 +1100 reset: moving to HEAD^ +e67f344f42afdb79c87a590f22537160241d8d61 e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349421 +1100 checkout: moving from master to other_branch +e67f344f42afdb79c87a590f22537160241d8d61 fe67c3eaf819025990d3688d5f147a064e669ca5 CI 1648349421 +1100 commit: myfile4 +fe67c3eaf819025990d3688d5f147a064e669ca5 e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349422 +1100 reset: moving to HEAD^ +e67f344f42afdb79c87a590f22537160241d8d61 e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349422 +1100 checkout: moving from other_branch to master diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/heads/master b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/heads/master new file mode 100644 index 000000000..7c4a7732c --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/heads/master @@ -0,0 +1,4 @@ +0000000000000000000000000000000000000000 7a35f0bb6bd8dc18ae462465e51f02362ba6babe CI 1648349421 +1100 commit (initial): myfile1 +7a35f0bb6bd8dc18ae462465e51f02362ba6babe e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349421 +1100 commit: myfile2 +e67f344f42afdb79c87a590f22537160241d8d61 bd739fb752ed02ccd49422196e31599c87ff90ad CI 1648349421 +1100 commit: myfile3 +bd739fb752ed02ccd49422196e31599c87ff90ad e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349421 +1100 reset: moving to HEAD^ diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/heads/other_branch b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/heads/other_branch new file mode 100644 index 000000000..76c0be40c --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/heads/other_branch @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349421 +1100 branch: Created from HEAD +e67f344f42afdb79c87a590f22537160241d8d61 fe67c3eaf819025990d3688d5f147a064e669ca5 CI 1648349421 +1100 commit: myfile4 +fe67c3eaf819025990d3688d5f147a064e669ca5 e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349422 +1100 reset: moving to HEAD^ diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/remotes/origin/master b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/remotes/origin/master new file mode 100644 index 000000000..f6e6b60bd --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/remotes/origin/master @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349421 +1100 fetch origin: storing head +e67f344f42afdb79c87a590f22537160241d8d61 bd739fb752ed02ccd49422196e31599c87ff90ad CI 1648349421 +1100 update by push +bd739fb752ed02ccd49422196e31599c87ff90ad e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349423 +1100 update by push diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/remotes/origin/other_branch b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/remotes/origin/other_branch new file mode 100644 index 000000000..5672ee50e --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/logs/refs/remotes/origin/other_branch @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349421 +1100 fetch origin: storing head +e67f344f42afdb79c87a590f22537160241d8d61 fe67c3eaf819025990d3688d5f147a064e669ca5 CI 1648349421 +1100 update by push +fe67c3eaf819025990d3688d5f147a064e669ca5 e67f344f42afdb79c87a590f22537160241d8d61 CI 1648349423 +1100 update by push diff --git a/test/integration/forcePushMultiple/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/forcePushMultiple/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/forcePushMultiple/expected_remote/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce similarity index 100% rename from test/integration/forcePushMultiple/expected_remote/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce rename to test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/7a/35f0bb6bd8dc18ae462465e51f02362ba6babe b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/7a/35f0bb6bd8dc18ae462465e51f02362ba6babe new file mode 100644 index 000000000..c58bcbe9b --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/7a/35f0bb6bd8dc18ae462465e51f02362ba6babe @@ -0,0 +1,2 @@ +x嵧A +0@旬s娰J&N\y1橮!ER雄#t鹹餝5[ 癀m昐衤s?h藾姂s Xz毄薒E=8w輅溹1N/菖>R' S靐爛pE艮濙4龘;;什*2K, \ No newline at end of file diff --git a/test/integration/forcePushMultiple/expected_remote/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/forcePushMultiple/expected_remote/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 similarity index 100% rename from test/integration/forcePushMultiple/expected_remote/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 rename to test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/bd/739fb752ed02ccd49422196e31599c87ff90ad b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/bd/739fb752ed02ccd49422196e31599c87ff90ad new file mode 100644 index 0000000000000000000000000000000000000000..fcaa0a8780d24739d5ad11f70a44f6b751a3e800 GIT binary patch literal 149 zcmV;G0BZku0gaAJ3c@fH0A1%4*$a~QX+9t#bk$>|$$MBZwv-5ZdwT>|1H&w)tgS8G zLgG{3MJ&z`s6-D{nMgB}YOX*UU5PURmf>I#v*lf0-HH!N%*vRx&LNc;@{pV&4ivyU zWT>%vF!|jd>u$%%UdQP!pWL>mT*}&R7CcAd#0d5b;G8+^G1cYI+_bMQPa*RI@IE?2 DVyi~F literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 similarity index 100% rename from test/integration/forcePushMultiple/expected_remote/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 rename to test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 similarity index 100% rename from test/integration/forcePushMultiple/expected_remote/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename to test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 diff --git a/test/integration/forcePushMultiple/expected_remote/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/forcePushMultiple/expected_remote/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/e6/7f344f42afdb79c87a590f22537160241d8d61 b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/e6/7f344f42afdb79c87a590f22537160241d8d61 new file mode 100644 index 0000000000000000000000000000000000000000..e1d86f23c77acd71d78937ead55b7b794285b9ff GIT binary patch literal 150 zcmV;H0BQet0gcW<3c@fDKvCB@MfQSZCdo7b5uvLdW2Tv4!PrtF= 4Sa&;4_Bu{?{czi!dYRXDvp^yFkOP7}12|`ndQ5fwlbiOf%Tv+(00iJV Eq{C-O9{>OV literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/fe/67c3eaf819025990d3688d5f147a064e669ca5 b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/objects/fe/67c3eaf819025990d3688d5f147a064e669ca5 new file mode 100644 index 0000000000000000000000000000000000000000..114e72ec5c45d8d5f3a8a642b646b236307422c1 GIT binary patch literal 150 zcmV;H0BQet0gcW<3d0}}K+&!}h5JHrbQ~2*DP)ynj5^XlZ9=fn-o80Px1YE8W$k?# z8WNtyE~1N=h%tb1=s0*wPB_?-eXfm(C?_eEDXNWkc?~TTnnP@8xz!v}iGh7G&06mQ zkg*6gRszNE@mO~~&H6gcclmJNo^mN`ziA+h4ij3?X8>c=QIDx1e{$8oZFvf+AGN1B E^6vXZ4*&oF literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/heads/master b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/heads/master new file mode 100644 index 000000000..51eb490a4 --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/heads/master @@ -0,0 +1 @@ +e67f344f42afdb79c87a590f22537160241d8d61 diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/heads/other_branch b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/heads/other_branch new file mode 100644 index 000000000..51eb490a4 --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/heads/other_branch @@ -0,0 +1 @@ +e67f344f42afdb79c87a590f22537160241d8d61 diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/remotes/origin/master b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/remotes/origin/master new file mode 100644 index 000000000..51eb490a4 --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/remotes/origin/master @@ -0,0 +1 @@ +e67f344f42afdb79c87a590f22537160241d8d61 diff --git a/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/remotes/origin/other_branch b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/remotes/origin/other_branch new file mode 100644 index 000000000..51eb490a4 --- /dev/null +++ b/test/integration/forcePushMultipleMatching/expected/repo/.git_keep/refs/remotes/origin/other_branch @@ -0,0 +1 @@ +e67f344f42afdb79c87a590f22537160241d8d61 diff --git a/test/integration/forcePushMultiple/expected/myfile1 b/test/integration/forcePushMultipleMatching/expected/repo/myfile1 similarity index 100% rename from test/integration/forcePushMultiple/expected/myfile1 rename to test/integration/forcePushMultipleMatching/expected/repo/myfile1 diff --git a/test/integration/forcePushMultiple/expected/myfile2 b/test/integration/forcePushMultipleMatching/expected/repo/myfile2 similarity index 100% rename from test/integration/forcePushMultiple/expected/myfile2 rename to test/integration/forcePushMultipleMatching/expected/repo/myfile2 diff --git a/test/integration/forcePushMultipleMatching/recording.json b/test/integration/forcePushMultipleMatching/recording.json new file mode 100644 index 000000000..ae367f16d --- /dev/null +++ b/test/integration/forcePushMultipleMatching/recording.json @@ -0,0 +1 @@ +{"KeyEvents":[{"Timestamp":892,"Mod":0,"Key":256,"Ch":80},{"Timestamp":1379,"Mod":0,"Key":13,"Ch":13},{"Timestamp":2132,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":135,"Height":36}]} \ No newline at end of file diff --git a/test/integration/forcePushMultiple/setup.sh b/test/integration/forcePushMultipleMatching/setup.sh similarity index 90% rename from test/integration/forcePushMultiple/setup.sh rename to test/integration/forcePushMultipleMatching/setup.sh index 3c599991f..185ea46e9 100644 --- a/test/integration/forcePushMultiple/setup.sh +++ b/test/integration/forcePushMultipleMatching/setup.sh @@ -23,11 +23,11 @@ git checkout -b other_branch git checkout master cd .. -git clone --bare ./actual actual_remote +git clone --bare ./repo origin -cd actual +cd repo -git remote add origin ../actual_remote +git remote add origin ../origin git fetch origin git branch --set-upstream-to=origin/master master git branch --set-upstream-to=origin/other_branch other_branch diff --git a/test/integration/forcePushMultiple/test.json b/test/integration/forcePushMultipleMatching/test.json similarity index 65% rename from test/integration/forcePushMultiple/test.json rename to test/integration/forcePushMultipleMatching/test.json index f939494e9..e62caa40f 100644 --- a/test/integration/forcePushMultiple/test.json +++ b/test/integration/forcePushMultipleMatching/test.json @@ -1,4 +1,4 @@ { - "description": "Force push to multiple branches because the user hasn't configured git to do otherwise", + "description": "Force push to multiple branches because the user has push.default matching", "speed": 10 } diff --git a/test/integration/initialOpen/expected/.git_keep/HEAD b/test/integration/forcePushMultipleUpstream/expected/origin/HEAD similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/HEAD rename to test/integration/forcePushMultipleUpstream/expected/origin/HEAD diff --git a/test/integration/forcePushMultipleUpstream/expected/origin/config b/test/integration/forcePushMultipleUpstream/expected/origin/config new file mode 100644 index 000000000..6504f87b4 --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/origin/config @@ -0,0 +1,8 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true + ignorecase = true + precomposeunicode = true +[remote "origin"] + url = /Users/jesseduffieldduffield/go/src/github.com/jesseduffield/lazygit/test/integration/forcePushMultipleUpstream/actual/./repo diff --git a/test/integration/initialOpen/expected/.git_keep/description b/test/integration/forcePushMultipleUpstream/expected/origin/description similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/description rename to test/integration/forcePushMultipleUpstream/expected/origin/description diff --git a/test/integration/initialOpen/expected/.git_keep/info/exclude b/test/integration/forcePushMultipleUpstream/expected/origin/info/exclude similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/info/exclude rename to test/integration/forcePushMultipleUpstream/expected/origin/info/exclude diff --git a/test/integration/initialOpen/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/forcePushMultipleUpstream/expected/origin/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/forcePushMultipleUpstream/expected/origin/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/forcePushMultipleUpstream/expected/origin/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/forcePushMultipleUpstream/expected/origin/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/pull/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/forcePushMultipleUpstream/expected/origin/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce similarity index 100% rename from test/integration/pull/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce rename to test/integration/forcePushMultipleUpstream/expected/origin/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce diff --git a/test/integration/forcePushMultipleUpstream/expected/origin/objects/48/6301f318c84045827013a3c3246b8c6a319eb8 b/test/integration/forcePushMultipleUpstream/expected/origin/objects/48/6301f318c84045827013a3c3246b8c6a319eb8 new file mode 100644 index 0000000000000000000000000000000000000000..c1564b80fe29af50d9b0c2337fd1383aee76549d GIT binary patch literal 148 zcmV;F0Biqv0gaA93c@fD06pgwxeJobZkq&(2tD-~>2? X z7!vku^1D9w(~grJ#_1uST#ij{yqCL$o+47}$lEJ`bEergRprmzl&`Lvp!os3pgHL6 Cnn^7H literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultipleUpstream/expected/origin/objects/49/ea44f3ec1792142714930c8e4c3073f137936c b/test/integration/forcePushMultipleUpstream/expected/origin/objects/49/ea44f3ec1792142714930c8e4c3073f137936c new file mode 100644 index 0000000000000000000000000000000000000000..52bacd10573bc907dbf03369ffb3d858a9a362cc GIT binary patch literal 150 zcmV;H0BQet0gcX03c@fDKw;N8MfQTsB-3dIM1-z-jQmWnU~DN7^!D}$ZXe&`<+Zh? zTNFC=UDd|X6UIR*l%iUNMOkWM&%rSl=Mq#$$YzVXzPb&VN=9S|J{L;F!{EKIq)Dh` z@D5N$2+qWJf2_NmW_z9HyMAKZo_fh^yIEuko@5|r&xio#sK->-Ke=h&x;)jHA91KT EV2qwhr2qf` literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultipleUpstream/expected/origin/objects/81/bdc116083cd4b4655333f4eb94dc0320197082 b/test/integration/forcePushMultipleUpstream/expected/origin/objects/81/bdc116083cd4b4655333f4eb94dc0320197082 new file mode 100644 index 000000000..b9233622d --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/origin/objects/81/bdc116083cd4b4655333f4eb94dc0320197082 @@ -0,0 +1,3 @@ +x嵧A +0@旬s娰J&巆凴 +<茦Lㄠ谯#t鹹餝5[ 癀昐衤0j藾姂s XZㄋLER溂郢0蚿熸啮Mo┶)v4鄪杞;9i'w-毽鑯3, \ No newline at end of file diff --git a/test/integration/initialOpen/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/forcePushMultipleUpstream/expected/origin/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/forcePushMultipleUpstream/expected/origin/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/pull/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 b/test/integration/forcePushMultipleUpstream/expected/origin/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 similarity index 100% rename from test/integration/pull/expected/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 rename to test/integration/forcePushMultipleUpstream/expected/origin/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 diff --git a/test/integration/forcePushMultipleUpstream/expected/origin/objects/c8/4375dda9d81c1f2103defe4384e31f859dac86 b/test/integration/forcePushMultipleUpstream/expected/origin/objects/c8/4375dda9d81c1f2103defe4384e31f859dac86 new file mode 100644 index 000000000..3054cb14b --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/origin/objects/c8/4375dda9d81c1f2103defe4384e31f859dac86 @@ -0,0 +1,5 @@ +x嵨M +0@岙s婌%R +<8N╜狧 +眄簘|'[璌硱橐U+ 9v>爎2u覾80e暀C2;鷍柌2QA堎斞IRt`酿=访m囻7訇軧爠;蝣 +鄿99蒸On攴,珤 9 \ No newline at end of file diff --git a/test/integration/pullMerge/expected/.git_keep/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 b/test/integration/forcePushMultipleUpstream/expected/origin/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 similarity index 100% rename from test/integration/pullMerge/expected/.git_keep/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 rename to test/integration/forcePushMultipleUpstream/expected/origin/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/forcePushMultipleUpstream/expected/origin/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename to test/integration/forcePushMultipleUpstream/expected/origin/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/forcePushMultipleUpstream/expected/origin/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/forcePushMultipleUpstream/expected/origin/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/forcePushMultipleUpstream/expected/origin/packed-refs b/test/integration/forcePushMultipleUpstream/expected/origin/packed-refs new file mode 100644 index 000000000..06b105db2 --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/origin/packed-refs @@ -0,0 +1,3 @@ +# pack-refs with: peeled fully-peeled sorted +49ea44f3ec1792142714930c8e4c3073f137936c refs/heads/master +49ea44f3ec1792142714930c8e4c3073f137936c refs/heads/other_branch diff --git a/test/integration/forcePushMultipleUpstream/expected/origin/refs/heads/master b/test/integration/forcePushMultipleUpstream/expected/origin/refs/heads/master new file mode 100644 index 000000000..f29b96944 --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/origin/refs/heads/master @@ -0,0 +1 @@ +49ea44f3ec1792142714930c8e4c3073f137936c diff --git a/test/integration/forcePushMultipleUpstream/expected/origin/refs/heads/other_branch b/test/integration/forcePushMultipleUpstream/expected/origin/refs/heads/other_branch new file mode 100644 index 000000000..7c9ad8321 --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/origin/refs/heads/other_branch @@ -0,0 +1 @@ +c84375dda9d81c1f2103defe4384e31f859dac86 diff --git a/test/integration/pull/expected/.git_keep/COMMIT_EDITMSG b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/pull/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/FETCH_HEAD b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/FETCH_HEAD new file mode 100644 index 000000000..e799afa43 --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/FETCH_HEAD @@ -0,0 +1,2 @@ +486301f318c84045827013a3c3246b8c6a319eb8 branch 'master' of ../origin +c84375dda9d81c1f2103defe4384e31f859dac86 not-for-merge branch 'other_branch' of ../origin diff --git a/test/integration/patchBuilding/expected/.git_keep/HEAD b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/HEAD rename to test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/HEAD diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/ORIG_HEAD b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/ORIG_HEAD new file mode 100644 index 000000000..7c9ad8321 --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/ORIG_HEAD @@ -0,0 +1 @@ +c84375dda9d81c1f2103defe4384e31f859dac86 diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/config b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/config new file mode 100644 index 000000000..3d6ea6c8d --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/config @@ -0,0 +1,21 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true +[user] + email = CI@example.com + name = CI +[push] + default = upstream +[remote "origin"] + url = ../origin + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "master"] + remote = origin + merge = refs/heads/master +[branch "other_branch"] + remote = origin + merge = refs/heads/other_branch diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/description b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/description similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/description rename to test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/description diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/index b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/index new file mode 100644 index 0000000000000000000000000000000000000000..9ec36686f295f0bfd322aeb21c9020e317ac7760 GIT binary patch literal 209 zcmZ?q402{*U|<5_B>Ri0)}9<+VKgHH11r-!kE;v}jY}997{3D5hyXF$(mjv=s;1uf z5)m53lkapPz^kSEDg%3NWm;xVsv%GTP=6Z3rW3DWG}N3o=;lc9{4i=z+IQ~dszu>d z{VlJw=Ub@5%rOF*6B6X=3Zx_%j1&yGmYYaLez^PYXXdl{+svBME@|_ti23|f@Y)=| Tj#2f{$=R2=OMZz7I6MRZ3PVRz literal 0 HcmV?d00001 diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/info/exclude b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/info/exclude rename to test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/info/exclude diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/HEAD b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/HEAD new file mode 100644 index 000000000..e6ba4297a --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/HEAD @@ -0,0 +1,10 @@ +0000000000000000000000000000000000000000 81bdc116083cd4b4655333f4eb94dc0320197082 CI 1648349542 +1100 commit (initial): myfile1 +81bdc116083cd4b4655333f4eb94dc0320197082 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349542 +1100 commit: myfile2 +49ea44f3ec1792142714930c8e4c3073f137936c 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349542 +1100 checkout: moving from master to other_branch +49ea44f3ec1792142714930c8e4c3073f137936c 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349542 +1100 checkout: moving from other_branch to master +49ea44f3ec1792142714930c8e4c3073f137936c 486301f318c84045827013a3c3246b8c6a319eb8 CI 1648349542 +1100 commit: myfile3 +486301f318c84045827013a3c3246b8c6a319eb8 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349542 +1100 reset: moving to HEAD^ +49ea44f3ec1792142714930c8e4c3073f137936c 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349542 +1100 checkout: moving from master to other_branch +49ea44f3ec1792142714930c8e4c3073f137936c c84375dda9d81c1f2103defe4384e31f859dac86 CI 1648349542 +1100 commit: myfile4 +c84375dda9d81c1f2103defe4384e31f859dac86 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349542 +1100 reset: moving to HEAD^ +49ea44f3ec1792142714930c8e4c3073f137936c 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349542 +1100 checkout: moving from other_branch to master diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/heads/master b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/heads/master new file mode 100644 index 000000000..4e2739b8e --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/heads/master @@ -0,0 +1,4 @@ +0000000000000000000000000000000000000000 81bdc116083cd4b4655333f4eb94dc0320197082 CI 1648349542 +1100 commit (initial): myfile1 +81bdc116083cd4b4655333f4eb94dc0320197082 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349542 +1100 commit: myfile2 +49ea44f3ec1792142714930c8e4c3073f137936c 486301f318c84045827013a3c3246b8c6a319eb8 CI 1648349542 +1100 commit: myfile3 +486301f318c84045827013a3c3246b8c6a319eb8 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349542 +1100 reset: moving to HEAD^ diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/heads/other_branch b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/heads/other_branch new file mode 100644 index 000000000..efd57e6fd --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/heads/other_branch @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349542 +1100 branch: Created from HEAD +49ea44f3ec1792142714930c8e4c3073f137936c c84375dda9d81c1f2103defe4384e31f859dac86 CI 1648349542 +1100 commit: myfile4 +c84375dda9d81c1f2103defe4384e31f859dac86 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349542 +1100 reset: moving to HEAD^ diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/remotes/origin/master b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/remotes/origin/master new file mode 100644 index 000000000..c08c7c66b --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/remotes/origin/master @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349542 +1100 fetch origin: storing head +49ea44f3ec1792142714930c8e4c3073f137936c 486301f318c84045827013a3c3246b8c6a319eb8 CI 1648349542 +1100 update by push +486301f318c84045827013a3c3246b8c6a319eb8 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349543 +1100 update by push diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/remotes/origin/other_branch b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/remotes/origin/other_branch new file mode 100644 index 000000000..fd6564f9b --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/logs/refs/remotes/origin/other_branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 49ea44f3ec1792142714930c8e4c3073f137936c CI 1648349542 +1100 fetch origin: storing head +49ea44f3ec1792142714930c8e4c3073f137936c c84375dda9d81c1f2103defe4384e31f859dac86 CI 1648349542 +1100 update by push diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/pull/expected_remote/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce similarity index 100% rename from test/integration/pull/expected_remote/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce rename to test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/48/6301f318c84045827013a3c3246b8c6a319eb8 b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/48/6301f318c84045827013a3c3246b8c6a319eb8 new file mode 100644 index 0000000000000000000000000000000000000000..c1564b80fe29af50d9b0c2337fd1383aee76549d GIT binary patch literal 148 zcmV;F0Biqv0gaA93c@fD06pgwxeJobZkq&(2tD-~>2? X z7!vku^1D9w(~grJ#_1uST#ij{yqCL$o+47}$lEJ`bEergRprmzl&`Lvp!os3pgHL6 Cnn^7H literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/49/ea44f3ec1792142714930c8e4c3073f137936c b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/49/ea44f3ec1792142714930c8e4c3073f137936c new file mode 100644 index 0000000000000000000000000000000000000000..52bacd10573bc907dbf03369ffb3d858a9a362cc GIT binary patch literal 150 zcmV;H0BQet0gcX03c@fDKw;N8MfQTsB-3dIM1-z-jQmWnU~DN7^!D}$ZXe&`<+Zh? zTNFC=UDd|X6UIR*l%iUNMOkWM&%rSl=Mq#$$YzVXzPb&VN=9S|J{L;F!{EKIq)Dh` z@D5N$2+qWJf2_NmW_z9HyMAKZo_fh^yIEuko@5|r&xio#sK->-Ke=h&x;)jHA91KT EV2qwhr2qf` literal 0 HcmV?d00001 diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/81/bdc116083cd4b4655333f4eb94dc0320197082 b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/81/bdc116083cd4b4655333f4eb94dc0320197082 new file mode 100644 index 000000000..b9233622d --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/81/bdc116083cd4b4655333f4eb94dc0320197082 @@ -0,0 +1,3 @@ +x嵧A +0@旬s娰J&巆凴 +<茦Lㄠ谯#t鹹餝5[ 癀昐衤0j藾姂s XZㄋLER溂郢0蚿熸啮Mo┶)v4鄪杞;9i'w-毽鑯3, \ No newline at end of file diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/pull/expected_remote/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 similarity index 100% rename from test/integration/pull/expected_remote/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 rename to test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/c8/4375dda9d81c1f2103defe4384e31f859dac86 b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/c8/4375dda9d81c1f2103defe4384e31f859dac86 new file mode 100644 index 000000000..3054cb14b --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/c8/4375dda9d81c1f2103defe4384e31f859dac86 @@ -0,0 +1,5 @@ +x嵨M +0@岙s婌%R +<8N╜狧 +眄簘|'[璌硱橐U+ 9v>爎2u覾80e暀C2;鷍柌2QA堎斞IRt`酿=访m囻7訇軧爠;蝣 +鄿99蒸On攴,珤 9 \ No newline at end of file diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/ce/0848710343a75263ea72cb5bdfa666b9ecda68 new file mode 100644 index 0000000000000000000000000000000000000000..5e9361d3548aa14bca5d35e0871b31e326387c70 GIT binary patch literal 103 zcmV-t0GR)H0V^p=O;s>7Fl8__FfcPQQOK=K%gjkNWLUcA@n6-{8($(qqj>V2E(CbB zbYDeLV#FZ9^TVh?Y2Ue*s}_Y<^|!pzo^PR!qQr#ZlF88r;s1<|mAy)TaoXZbQtYkQ JApo0YFGO2mGTHzD literal 0 HcmV?d00001 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename to test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/heads/master b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/heads/master new file mode 100644 index 000000000..f29b96944 --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/heads/master @@ -0,0 +1 @@ +49ea44f3ec1792142714930c8e4c3073f137936c diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/heads/other_branch b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/heads/other_branch new file mode 100644 index 000000000..f29b96944 --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/heads/other_branch @@ -0,0 +1 @@ +49ea44f3ec1792142714930c8e4c3073f137936c diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/remotes/origin/master b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/remotes/origin/master new file mode 100644 index 000000000..f29b96944 --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/remotes/origin/master @@ -0,0 +1 @@ +49ea44f3ec1792142714930c8e4c3073f137936c diff --git a/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/remotes/origin/other_branch b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/remotes/origin/other_branch new file mode 100644 index 000000000..7c9ad8321 --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/expected/repo/.git_keep/refs/remotes/origin/other_branch @@ -0,0 +1 @@ +c84375dda9d81c1f2103defe4384e31f859dac86 diff --git a/test/integration/initialOpen/expected/myfile1 b/test/integration/forcePushMultipleUpstream/expected/repo/myfile1 similarity index 100% rename from test/integration/initialOpen/expected/myfile1 rename to test/integration/forcePushMultipleUpstream/expected/repo/myfile1 diff --git a/test/integration/pull/expected/myfile2 b/test/integration/forcePushMultipleUpstream/expected/repo/myfile2 similarity index 100% rename from test/integration/pull/expected/myfile2 rename to test/integration/forcePushMultipleUpstream/expected/repo/myfile2 diff --git a/test/integration/forcePushMultipleUpstream/recording.json b/test/integration/forcePushMultipleUpstream/recording.json new file mode 100644 index 000000000..ae367f16d --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/recording.json @@ -0,0 +1 @@ +{"KeyEvents":[{"Timestamp":892,"Mod":0,"Key":256,"Ch":80},{"Timestamp":1379,"Mod":0,"Key":13,"Ch":13},{"Timestamp":2132,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":135,"Height":36}]} \ No newline at end of file diff --git a/test/integration/forcePushMultipleUpstream/setup.sh b/test/integration/forcePushMultipleUpstream/setup.sh new file mode 100644 index 000000000..f31f24041 --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/setup.sh @@ -0,0 +1,54 @@ +#!/bin/sh + +set -e + +set -e + +cd $1 + +git init + +git config user.email "CI@example.com" +git config user.name "CI" +git config push.default upstream + +echo test1 > myfile1 +git add . +git commit -am "myfile1" +echo test2 > myfile2 +git add . +git commit -am "myfile2" + +git checkout -b other_branch +git checkout master + +cd .. +git clone --bare ./repo origin + +cd repo + +git remote add origin ../origin +git fetch origin +git branch --set-upstream-to=origin/master master +git branch --set-upstream-to=origin/other_branch other_branch + +echo test3 > myfile3 +git add . +git commit -am "myfile3" + +git push origin master +git reset --hard HEAD^ + +git checkout other_branch + +echo test4 > myfile4 +git add . +git commit -am "myfile4" + +git push origin other_branch +git reset --hard HEAD^ + +git checkout master + +# at this point, both branches have diverged from their remote counterparts, meaning if you +# attempt to push either, it'll ask if you want to force push. diff --git a/test/integration/forcePushMultipleUpstream/test.json b/test/integration/forcePushMultipleUpstream/test.json new file mode 100644 index 000000000..4569d3cc9 --- /dev/null +++ b/test/integration/forcePushMultipleUpstream/test.json @@ -0,0 +1,4 @@ +{ + "description": "Force push to only one branch because the user has push.default upstream", + "speed": 10 +} diff --git a/test/integration/initialOpen/expected/.git_keep/COMMIT_EDITMSG b/test/integration/initialOpen/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/initialOpen/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/initialOpen/expected/.git_keep/FETCH_HEAD b/test/integration/initialOpen/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/FETCH_HEAD rename to test/integration/initialOpen/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/patchBuilding2/expected/.git_keep/HEAD b/test/integration/initialOpen/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/HEAD rename to test/integration/initialOpen/expected/repo/.git_keep/HEAD diff --git a/test/integration/initialOpen/expected/.git_keep/config b/test/integration/initialOpen/expected/repo/.git_keep/config similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/config rename to test/integration/initialOpen/expected/repo/.git_keep/config diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/description b/test/integration/initialOpen/expected/repo/.git_keep/description similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/description rename to test/integration/initialOpen/expected/repo/.git_keep/description diff --git a/test/integration/initialOpen/expected/.git_keep/index b/test/integration/initialOpen/expected/repo/.git_keep/index similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/index rename to test/integration/initialOpen/expected/repo/.git_keep/index diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/info/exclude b/test/integration/initialOpen/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/info/exclude rename to test/integration/initialOpen/expected/repo/.git_keep/info/exclude diff --git a/test/integration/initialOpen/expected/.git_keep/logs/HEAD b/test/integration/initialOpen/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/logs/HEAD rename to test/integration/initialOpen/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/initialOpen/expected/.git_keep/logs/refs/heads/master b/test/integration/initialOpen/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/logs/refs/heads/master rename to test/integration/initialOpen/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/initialOpen/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/initialOpen/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/initialOpen/expected/.git_keep/objects/46/f86259c48ec60496e43d9c962e32f40e7cdefb b/test/integration/initialOpen/expected/repo/.git_keep/objects/46/f86259c48ec60496e43d9c962e32f40e7cdefb similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/objects/46/f86259c48ec60496e43d9c962e32f40e7cdefb rename to test/integration/initialOpen/expected/repo/.git_keep/objects/46/f86259c48ec60496e43d9c962e32f40e7cdefb diff --git a/test/integration/initialOpen/expected/.git_keep/objects/62/b35f5751dd871e0908247223d276b5efeb4cb4 b/test/integration/initialOpen/expected/repo/.git_keep/objects/62/b35f5751dd871e0908247223d276b5efeb4cb4 similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/objects/62/b35f5751dd871e0908247223d276b5efeb4cb4 rename to test/integration/initialOpen/expected/repo/.git_keep/objects/62/b35f5751dd871e0908247223d276b5efeb4cb4 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/initialOpen/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/initialOpen/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/initialOpen/expected/.git_keep/objects/e4/776798a2a73374b45e6321b60b5578b9fb590c b/test/integration/initialOpen/expected/repo/.git_keep/objects/e4/776798a2a73374b45e6321b60b5578b9fb590c similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/objects/e4/776798a2a73374b45e6321b60b5578b9fb590c rename to test/integration/initialOpen/expected/repo/.git_keep/objects/e4/776798a2a73374b45e6321b60b5578b9fb590c diff --git a/test/integration/initialOpen/expected/.git_keep/refs/heads/master b/test/integration/initialOpen/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/initialOpen/expected/.git_keep/refs/heads/master rename to test/integration/initialOpen/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/patchBuilding/expected/myfile1 b/test/integration/initialOpen/expected/repo/myfile1 similarity index 100% rename from test/integration/patchBuilding/expected/myfile1 rename to test/integration/initialOpen/expected/repo/myfile1 diff --git a/test/integration/initialOpen/expected/myfile2 b/test/integration/initialOpen/expected/repo/myfile2 similarity index 100% rename from test/integration/initialOpen/expected/myfile2 rename to test/integration/initialOpen/expected/repo/myfile2 diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/COMMIT_EDITMSG b/test/integration/mergeConflictRevert/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/FETCH_HEAD b/test/integration/mergeConflictRevert/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/FETCH_HEAD rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/HEAD b/test/integration/mergeConflictRevert/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/HEAD rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/HEAD diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/ORIG_HEAD b/test/integration/mergeConflictRevert/expected/repo/.git_keep/ORIG_HEAD similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/ORIG_HEAD rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/ORIG_HEAD diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/config b/test/integration/mergeConflictRevert/expected/repo/.git_keep/config similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/config rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/config diff --git a/test/integration/mergeConflicts/expected/.git_keep/description b/test/integration/mergeConflictRevert/expected/repo/.git_keep/description similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/description rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/description diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/index b/test/integration/mergeConflictRevert/expected/repo/.git_keep/index similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/index rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/index diff --git a/test/integration/mergeConflicts/expected/.git_keep/info/exclude b/test/integration/mergeConflictRevert/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/info/exclude rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/info/exclude diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/logs/HEAD b/test/integration/mergeConflictRevert/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/logs/HEAD rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/logs/refs/heads/another b/test/integration/mergeConflictRevert/expected/repo/.git_keep/logs/refs/heads/another similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/logs/refs/heads/another rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/logs/refs/heads/another diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/logs/refs/heads/master b/test/integration/mergeConflictRevert/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/logs/refs/heads/master rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/logs/refs/heads/other b/test/integration/mergeConflictRevert/expected/repo/.git_keep/logs/refs/heads/other similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/logs/refs/heads/other rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/logs/refs/heads/other diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/1e/7d643e0db24ebee10f92aa2f8099d50dbe0f0f b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/1e/7d643e0db24ebee10f92aa2f8099d50dbe0f0f similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/1e/7d643e0db24ebee10f92aa2f8099d50dbe0f0f rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/1e/7d643e0db24ebee10f92aa2f8099d50dbe0f0f diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/3c/3594b2fd655fb7ffe36077ee8a9c3f79fb5fc6 b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/3c/3594b2fd655fb7ffe36077ee8a9c3f79fb5fc6 similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/3c/3594b2fd655fb7ffe36077ee8a9c3f79fb5fc6 rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/3c/3594b2fd655fb7ffe36077ee8a9c3f79fb5fc6 diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/41/bed9f222cc54e68d7846dc010bea6d23bea33e b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/41/bed9f222cc54e68d7846dc010bea6d23bea33e similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/41/bed9f222cc54e68d7846dc010bea6d23bea33e rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/41/bed9f222cc54e68d7846dc010bea6d23bea33e diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/61/3e54e7fd6e080d53ef44c18ecd33c545ac0e08 b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/61/3e54e7fd6e080d53ef44c18ecd33c545ac0e08 similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/61/3e54e7fd6e080d53ef44c18ecd33c545ac0e08 rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/61/3e54e7fd6e080d53ef44c18ecd33c545ac0e08 diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/89/8618af3fef6edf472d0f4a483ed8010d7bcfbb b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/89/8618af3fef6edf472d0f4a483ed8010d7bcfbb similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/89/8618af3fef6edf472d0f4a483ed8010d7bcfbb rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/89/8618af3fef6edf472d0f4a483ed8010d7bcfbb diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/98/f656b294e5f3b447e3fd66814a80d0d4080627 b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/98/f656b294e5f3b447e3fd66814a80d0d4080627 similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/98/f656b294e5f3b447e3fd66814a80d0d4080627 rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/98/f656b294e5f3b447e3fd66814a80d0d4080627 diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/9d/aeafb9864cf43055ae93beb0afd6c7d144bfa4 diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/a4/942a576eec3a1a15fb790c942b6860331bee32 b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/a4/942a576eec3a1a15fb790c942b6860331bee32 similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/a4/942a576eec3a1a15fb790c942b6860331bee32 rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/a4/942a576eec3a1a15fb790c942b6860331bee32 diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/a7/fd052c52f174943cdea637f2d11f5ab7d090cd b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/a7/fd052c52f174943cdea637f2d11f5ab7d090cd similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/a7/fd052c52f174943cdea637f2d11f5ab7d090cd rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/a7/fd052c52f174943cdea637f2d11f5ab7d090cd diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/ba/4581dc53b5b2ff56803651dfd79245203d546b b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/ba/4581dc53b5b2ff56803651dfd79245203d546b similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/ba/4581dc53b5b2ff56803651dfd79245203d546b rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/ba/4581dc53b5b2ff56803651dfd79245203d546b diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/be/5b46b808c9c808be26710daeb2ce9ed2c7a070 b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/be/5b46b808c9c808be26710daeb2ce9ed2c7a070 similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/be/5b46b808c9c808be26710daeb2ce9ed2c7a070 rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/be/5b46b808c9c808be26710daeb2ce9ed2c7a070 diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/c5/af43f6cc1d51ebb3ab4800347595541f81799c b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/c5/af43f6cc1d51ebb3ab4800347595541f81799c similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/c5/af43f6cc1d51ebb3ab4800347595541f81799c rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/c5/af43f6cc1d51ebb3ab4800347595541f81799c diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/d3/b35176a575d48743900b1f0863cefbc198f84c b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/d3/b35176a575d48743900b1f0863cefbc198f84c similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/d3/b35176a575d48743900b1f0863cefbc198f84c rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/d3/b35176a575d48743900b1f0863cefbc198f84c diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/dd/ad764e9e78b555cd41e5e81f8ce969cfa3972c b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/dd/ad764e9e78b555cd41e5e81f8ce969cfa3972c similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/dd/ad764e9e78b555cd41e5e81f8ce969cfa3972c rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/dd/ad764e9e78b555cd41e5e81f8ce969cfa3972c diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/e5/265503c8aea2860fc4754c1025e4597530ce0e b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/e5/265503c8aea2860fc4754c1025e4597530ce0e similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/e5/265503c8aea2860fc4754c1025e4597530ce0e rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/e5/265503c8aea2860fc4754c1025e4597530ce0e diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/objects/fa/0b6bf64815f57729716334319596c926b6564a b/test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/fa/0b6bf64815f57729716334319596c926b6564a similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/objects/fa/0b6bf64815f57729716334319596c926b6564a rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/objects/fa/0b6bf64815f57729716334319596c926b6564a diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/refs/heads/another b/test/integration/mergeConflictRevert/expected/repo/.git_keep/refs/heads/another similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/refs/heads/another rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/refs/heads/another diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/refs/heads/master b/test/integration/mergeConflictRevert/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/refs/heads/master rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/mergeConflictRevert/expected/.git_keep/refs/heads/other b/test/integration/mergeConflictRevert/expected/repo/.git_keep/refs/heads/other similarity index 100% rename from test/integration/mergeConflictRevert/expected/.git_keep/refs/heads/other rename to test/integration/mergeConflictRevert/expected/repo/.git_keep/refs/heads/other diff --git a/test/integration/mergeConflictRevert/expected/file1 b/test/integration/mergeConflictRevert/expected/repo/file1 similarity index 100% rename from test/integration/mergeConflictRevert/expected/file1 rename to test/integration/mergeConflictRevert/expected/repo/file1 diff --git a/test/integration/mergeConflictRevert/expected/file2 b/test/integration/mergeConflictRevert/expected/repo/file2 similarity index 100% rename from test/integration/mergeConflictRevert/expected/file2 rename to test/integration/mergeConflictRevert/expected/repo/file2 diff --git a/test/integration/mergeConflictRevert/expected/file4 b/test/integration/mergeConflictRevert/expected/repo/file4 similarity index 100% rename from test/integration/mergeConflictRevert/expected/file4 rename to test/integration/mergeConflictRevert/expected/repo/file4 diff --git a/test/integration/mergeConflictRevert/expected/file5 b/test/integration/mergeConflictRevert/expected/repo/file5 similarity index 100% rename from test/integration/mergeConflictRevert/expected/file5 rename to test/integration/mergeConflictRevert/expected/repo/file5 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/COMMIT_EDITMSG b/test/integration/mergeConflictUndo/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/FETCH_HEAD b/test/integration/mergeConflictUndo/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/FETCH_HEAD rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/HEAD b/test/integration/mergeConflictUndo/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/HEAD rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/HEAD diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/MERGE_HEAD b/test/integration/mergeConflictUndo/expected/repo/.git_keep/MERGE_HEAD similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/MERGE_HEAD rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/MERGE_HEAD diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/MERGE_MODE b/test/integration/mergeConflictUndo/expected/repo/.git_keep/MERGE_MODE similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/MERGE_MODE rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/MERGE_MODE diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/MERGE_MSG b/test/integration/mergeConflictUndo/expected/repo/.git_keep/MERGE_MSG similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/MERGE_MSG rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/MERGE_MSG diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/ORIG_HEAD b/test/integration/mergeConflictUndo/expected/repo/.git_keep/ORIG_HEAD similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/ORIG_HEAD rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/ORIG_HEAD diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/config b/test/integration/mergeConflictUndo/expected/repo/.git_keep/config similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/config rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/config diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/description b/test/integration/mergeConflictUndo/expected/repo/.git_keep/description similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/description rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/description diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/index b/test/integration/mergeConflictUndo/expected/repo/.git_keep/index similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/index rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/index diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/info/exclude b/test/integration/mergeConflictUndo/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/info/exclude rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/info/exclude diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/logs/HEAD b/test/integration/mergeConflictUndo/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/logs/HEAD rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/logs/refs/heads/base_branch b/test/integration/mergeConflictUndo/expected/repo/.git_keep/logs/refs/heads/base_branch similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/logs/refs/heads/base_branch rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/logs/refs/heads/base_branch diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/logs/refs/heads/develop b/test/integration/mergeConflictUndo/expected/repo/.git_keep/logs/refs/heads/develop similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/logs/refs/heads/develop rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/logs/refs/heads/develop diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/logs/refs/heads/feature/cherry-picking b/test/integration/mergeConflictUndo/expected/repo/.git_keep/logs/refs/heads/feature/cherry-picking similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/logs/refs/heads/feature/cherry-picking rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/logs/refs/heads/feature/cherry-picking diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/logs/refs/heads/master b/test/integration/mergeConflictUndo/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/logs/refs/heads/master rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/logs/refs/heads/other_branch b/test/integration/mergeConflictUndo/expected/repo/.git_keep/logs/refs/heads/other_branch similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/logs/refs/heads/other_branch rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/logs/refs/heads/other_branch diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/08/e2576bb7cd0dd9be54f9a523c4bedea0643557 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/08/e2576bb7cd0dd9be54f9a523c4bedea0643557 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/08/e2576bb7cd0dd9be54f9a523c4bedea0643557 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/08/e2576bb7cd0dd9be54f9a523c4bedea0643557 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/17/dc45dd142947e06cf7e635d62f2c0acbb86da7 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/17/dc45dd142947e06cf7e635d62f2c0acbb86da7 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/17/dc45dd142947e06cf7e635d62f2c0acbb86da7 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/17/dc45dd142947e06cf7e635d62f2c0acbb86da7 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/18/c07ac9568c564ececb199f78f64babc92214cb b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/18/c07ac9568c564ececb199f78f64babc92214cb similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/18/c07ac9568c564ececb199f78f64babc92214cb rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/18/c07ac9568c564ececb199f78f64babc92214cb diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/24/10ee12b940bade9d9e99413732faa6dc60adb1 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/24/10ee12b940bade9d9e99413732faa6dc60adb1 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/24/10ee12b940bade9d9e99413732faa6dc60adb1 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/24/10ee12b940bade9d9e99413732faa6dc60adb1 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/27/94411aa7b73b44f533fb862cdb9dbfd13c5d92 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/27/94411aa7b73b44f533fb862cdb9dbfd13c5d92 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/27/94411aa7b73b44f533fb862cdb9dbfd13c5d92 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/27/94411aa7b73b44f533fb862cdb9dbfd13c5d92 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/27/9f068805e089660f7ddd17ff32f66100e0dca5 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/27/9f068805e089660f7ddd17ff32f66100e0dca5 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/27/9f068805e089660f7ddd17ff32f66100e0dca5 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/27/9f068805e089660f7ddd17ff32f66100e0dca5 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/31/f2a971f823279ba1ef877be7599da288f6e24b b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/31/f2a971f823279ba1ef877be7599da288f6e24b similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/31/f2a971f823279ba1ef877be7599da288f6e24b rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/31/f2a971f823279ba1ef877be7599da288f6e24b diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/3d/1213374cd86b841f034768571d0b5f2c870a16 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/3d/1213374cd86b841f034768571d0b5f2c870a16 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/3d/1213374cd86b841f034768571d0b5f2c870a16 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/3d/1213374cd86b841f034768571d0b5f2c870a16 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/44/2a53c1b023b4816085fdc4eaa85d0c5fd897e2 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/44/2a53c1b023b4816085fdc4eaa85d0c5fd897e2 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/44/2a53c1b023b4816085fdc4eaa85d0c5fd897e2 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/44/2a53c1b023b4816085fdc4eaa85d0c5fd897e2 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/4e/5d3ae0b6e865073bcbd79531a75c55bf7bfcb4 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/4e/5d3ae0b6e865073bcbd79531a75c55bf7bfcb4 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/4e/5d3ae0b6e865073bcbd79531a75c55bf7bfcb4 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/4e/5d3ae0b6e865073bcbd79531a75c55bf7bfcb4 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/5d/c2e019349371e9b3e4f1be99754ba70094cad6 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/5d/c2e019349371e9b3e4f1be99754ba70094cad6 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/5d/c2e019349371e9b3e4f1be99754ba70094cad6 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/5d/c2e019349371e9b3e4f1be99754ba70094cad6 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/68/7ff9526e0d56fafe1445ee4c182a83afc3cc35 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/68/7ff9526e0d56fafe1445ee4c182a83afc3cc35 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/68/7ff9526e0d56fafe1445ee4c182a83afc3cc35 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/68/7ff9526e0d56fafe1445ee4c182a83afc3cc35 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/6d/fbfa4bd19cb38608681df40ebb3a78bd13a824 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/6d/fbfa4bd19cb38608681df40ebb3a78bd13a824 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/6d/fbfa4bd19cb38608681df40ebb3a78bd13a824 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/6d/fbfa4bd19cb38608681df40ebb3a78bd13a824 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/7b/c178be031c4645110e9accb4accf16902d2d7f b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/7b/c178be031c4645110e9accb4accf16902d2d7f similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/7b/c178be031c4645110e9accb4accf16902d2d7f rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/7b/c178be031c4645110e9accb4accf16902d2d7f diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/82/db6d0e4502f489719ea0f3dbe7e14413c6d28a b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/82/db6d0e4502f489719ea0f3dbe7e14413c6d28a similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/82/db6d0e4502f489719ea0f3dbe7e14413c6d28a rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/82/db6d0e4502f489719ea0f3dbe7e14413c6d28a diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/8c/d762c119834784fdbf97e9bb3b4c15e804ebaa b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/8c/d762c119834784fdbf97e9bb3b4c15e804ebaa similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/8c/d762c119834784fdbf97e9bb3b4c15e804ebaa rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/8c/d762c119834784fdbf97e9bb3b4c15e804ebaa diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/c2/7ef6b4964209a875191eca7e56605c8efa5eee b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/c2/7ef6b4964209a875191eca7e56605c8efa5eee similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/c2/7ef6b4964209a875191eca7e56605c8efa5eee rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/c2/7ef6b4964209a875191eca7e56605c8efa5eee diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/c5/0f7e1375a30118c2886d4b31318579f3419231 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/c5/0f7e1375a30118c2886d4b31318579f3419231 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/c5/0f7e1375a30118c2886d4b31318579f3419231 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/c5/0f7e1375a30118c2886d4b31318579f3419231 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/c9/b473bec307b18fd94a913658f4d759be63ca47 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/c9/b473bec307b18fd94a913658f4d759be63ca47 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/c9/b473bec307b18fd94a913658f4d759be63ca47 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/c9/b473bec307b18fd94a913658f4d759be63ca47 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/ce/d01df5f1a270490c1b9d4efe5ceb0c53626279 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/ce/d01df5f1a270490c1b9d4efe5ceb0c53626279 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/ce/d01df5f1a270490c1b9d4efe5ceb0c53626279 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/ce/d01df5f1a270490c1b9d4efe5ceb0c53626279 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/d2/5721fffa7dc911ff2a9102bef201db225e2f16 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/d2/5721fffa7dc911ff2a9102bef201db225e2f16 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/d2/5721fffa7dc911ff2a9102bef201db225e2f16 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/d2/5721fffa7dc911ff2a9102bef201db225e2f16 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/db/f5ab9a4fa3f976d266f3be50670aa83121b420 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/db/f5ab9a4fa3f976d266f3be50670aa83121b420 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/db/f5ab9a4fa3f976d266f3be50670aa83121b420 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/db/f5ab9a4fa3f976d266f3be50670aa83121b420 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 b/test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/refs/heads/base_branch b/test/integration/mergeConflictUndo/expected/repo/.git_keep/refs/heads/base_branch similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/refs/heads/base_branch rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/refs/heads/base_branch diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/refs/heads/develop b/test/integration/mergeConflictUndo/expected/repo/.git_keep/refs/heads/develop similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/refs/heads/develop rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/refs/heads/develop diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/refs/heads/feature/cherry-picking b/test/integration/mergeConflictUndo/expected/repo/.git_keep/refs/heads/feature/cherry-picking similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/refs/heads/feature/cherry-picking rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/refs/heads/feature/cherry-picking diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/refs/heads/master b/test/integration/mergeConflictUndo/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/refs/heads/master rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/mergeConflictUndo/expected/.git_keep/refs/heads/other_branch b/test/integration/mergeConflictUndo/expected/repo/.git_keep/refs/heads/other_branch similarity index 100% rename from test/integration/mergeConflictUndo/expected/.git_keep/refs/heads/other_branch rename to test/integration/mergeConflictUndo/expected/repo/.git_keep/refs/heads/other_branch diff --git a/test/integration/mergeConflictUndo/expected/cherrypicking1 b/test/integration/mergeConflictUndo/expected/repo/cherrypicking1 similarity index 100% rename from test/integration/mergeConflictUndo/expected/cherrypicking1 rename to test/integration/mergeConflictUndo/expected/repo/cherrypicking1 diff --git a/test/integration/mergeConflictUndo/expected/cherrypicking2 b/test/integration/mergeConflictUndo/expected/repo/cherrypicking2 similarity index 100% rename from test/integration/mergeConflictUndo/expected/cherrypicking2 rename to test/integration/mergeConflictUndo/expected/repo/cherrypicking2 diff --git a/test/integration/mergeConflictUndo/expected/cherrypicking3 b/test/integration/mergeConflictUndo/expected/repo/cherrypicking3 similarity index 100% rename from test/integration/mergeConflictUndo/expected/cherrypicking3 rename to test/integration/mergeConflictUndo/expected/repo/cherrypicking3 diff --git a/test/integration/mergeConflictUndo/expected/cherrypicking4 b/test/integration/mergeConflictUndo/expected/repo/cherrypicking4 similarity index 100% rename from test/integration/mergeConflictUndo/expected/cherrypicking4 rename to test/integration/mergeConflictUndo/expected/repo/cherrypicking4 diff --git a/test/integration/mergeConflictUndo/expected/cherrypicking5 b/test/integration/mergeConflictUndo/expected/repo/cherrypicking5 similarity index 100% rename from test/integration/mergeConflictUndo/expected/cherrypicking5 rename to test/integration/mergeConflictUndo/expected/repo/cherrypicking5 diff --git a/test/integration/mergeConflictUndo/expected/cherrypicking6 b/test/integration/mergeConflictUndo/expected/repo/cherrypicking6 similarity index 100% rename from test/integration/mergeConflictUndo/expected/cherrypicking6 rename to test/integration/mergeConflictUndo/expected/repo/cherrypicking6 diff --git a/test/integration/mergeConflictUndo/expected/cherrypicking7 b/test/integration/mergeConflictUndo/expected/repo/cherrypicking7 similarity index 100% rename from test/integration/mergeConflictUndo/expected/cherrypicking7 rename to test/integration/mergeConflictUndo/expected/repo/cherrypicking7 diff --git a/test/integration/mergeConflictUndo/expected/cherrypicking8 b/test/integration/mergeConflictUndo/expected/repo/cherrypicking8 similarity index 100% rename from test/integration/mergeConflictUndo/expected/cherrypicking8 rename to test/integration/mergeConflictUndo/expected/repo/cherrypicking8 diff --git a/test/integration/mergeConflictUndo/expected/cherrypicking9 b/test/integration/mergeConflictUndo/expected/repo/cherrypicking9 similarity index 100% rename from test/integration/mergeConflictUndo/expected/cherrypicking9 rename to test/integration/mergeConflictUndo/expected/repo/cherrypicking9 diff --git a/test/integration/mergeConflictUndo/expected/directory/file b/test/integration/mergeConflictUndo/expected/repo/directory/file similarity index 100% rename from test/integration/mergeConflictUndo/expected/directory/file rename to test/integration/mergeConflictUndo/expected/repo/directory/file diff --git a/test/integration/mergeConflictUndo/expected/directory/file2 b/test/integration/mergeConflictUndo/expected/repo/directory/file2 similarity index 100% rename from test/integration/mergeConflictUndo/expected/directory/file2 rename to test/integration/mergeConflictUndo/expected/repo/directory/file2 diff --git a/test/integration/mergeConflictUndo/expected/file b/test/integration/mergeConflictUndo/expected/repo/file similarity index 100% rename from test/integration/mergeConflictUndo/expected/file rename to test/integration/mergeConflictUndo/expected/repo/file diff --git a/test/integration/mergeConflictUndo/expected/file1 b/test/integration/mergeConflictUndo/expected/repo/file1 similarity index 100% rename from test/integration/mergeConflictUndo/expected/file1 rename to test/integration/mergeConflictUndo/expected/repo/file1 diff --git a/test/integration/mergeConflictUndo/expected/file3 b/test/integration/mergeConflictUndo/expected/repo/file3 similarity index 100% rename from test/integration/mergeConflictUndo/expected/file3 rename to test/integration/mergeConflictUndo/expected/repo/file3 diff --git a/test/integration/mergeConflictUndo/expected/file4 b/test/integration/mergeConflictUndo/expected/repo/file4 similarity index 100% rename from test/integration/mergeConflictUndo/expected/file4 rename to test/integration/mergeConflictUndo/expected/repo/file4 diff --git a/test/integration/mergeConflictUndo/expected/file5 b/test/integration/mergeConflictUndo/expected/repo/file5 similarity index 100% rename from test/integration/mergeConflictUndo/expected/file5 rename to test/integration/mergeConflictUndo/expected/repo/file5 diff --git a/test/integration/mergeConflicts/expected/.git_keep/COMMIT_EDITMSG b/test/integration/mergeConflicts/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/mergeConflicts/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/mergeConflicts/expected/.git_keep/FETCH_HEAD b/test/integration/mergeConflicts/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/FETCH_HEAD rename to test/integration/mergeConflicts/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/mergeConflicts/expected/.git_keep/HEAD b/test/integration/mergeConflicts/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/HEAD rename to test/integration/mergeConflicts/expected/repo/.git_keep/HEAD diff --git a/test/integration/mergeConflicts/expected/.git_keep/ORIG_HEAD b/test/integration/mergeConflicts/expected/repo/.git_keep/ORIG_HEAD similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/ORIG_HEAD rename to test/integration/mergeConflicts/expected/repo/.git_keep/ORIG_HEAD diff --git a/test/integration/mergeConflicts/expected/.git_keep/config b/test/integration/mergeConflicts/expected/repo/.git_keep/config similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/config rename to test/integration/mergeConflicts/expected/repo/.git_keep/config diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/description b/test/integration/mergeConflicts/expected/repo/.git_keep/description similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/description rename to test/integration/mergeConflicts/expected/repo/.git_keep/description diff --git a/test/integration/mergeConflicts/expected/.git_keep/index b/test/integration/mergeConflicts/expected/repo/.git_keep/index similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/index rename to test/integration/mergeConflicts/expected/repo/.git_keep/index diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/info/exclude b/test/integration/mergeConflicts/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/info/exclude rename to test/integration/mergeConflicts/expected/repo/.git_keep/info/exclude diff --git a/test/integration/mergeConflicts/expected/.git_keep/logs/HEAD b/test/integration/mergeConflicts/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/logs/HEAD rename to test/integration/mergeConflicts/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/mergeConflicts/expected/.git_keep/logs/refs/heads/base_branch b/test/integration/mergeConflicts/expected/repo/.git_keep/logs/refs/heads/base_branch similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/logs/refs/heads/base_branch rename to test/integration/mergeConflicts/expected/repo/.git_keep/logs/refs/heads/base_branch diff --git a/test/integration/mergeConflicts/expected/.git_keep/logs/refs/heads/develop b/test/integration/mergeConflicts/expected/repo/.git_keep/logs/refs/heads/develop similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/logs/refs/heads/develop rename to test/integration/mergeConflicts/expected/repo/.git_keep/logs/refs/heads/develop diff --git a/test/integration/mergeConflicts/expected/.git_keep/logs/refs/heads/feature/cherry-picking b/test/integration/mergeConflicts/expected/repo/.git_keep/logs/refs/heads/feature/cherry-picking similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/logs/refs/heads/feature/cherry-picking rename to test/integration/mergeConflicts/expected/repo/.git_keep/logs/refs/heads/feature/cherry-picking diff --git a/test/integration/mergeConflicts/expected/.git_keep/logs/refs/heads/master b/test/integration/mergeConflicts/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/logs/refs/heads/master rename to test/integration/mergeConflicts/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/mergeConflicts/expected/.git_keep/logs/refs/heads/other_branch b/test/integration/mergeConflicts/expected/repo/.git_keep/logs/refs/heads/other_branch similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/logs/refs/heads/other_branch rename to test/integration/mergeConflicts/expected/repo/.git_keep/logs/refs/heads/other_branch diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/0b/2387a3f67ec050f6d4e08f379e3cbb0a9913f1 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/0b/2387a3f67ec050f6d4e08f379e3cbb0a9913f1 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/0b/2387a3f67ec050f6d4e08f379e3cbb0a9913f1 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/0b/2387a3f67ec050f6d4e08f379e3cbb0a9913f1 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/16/18ce1085acb41fd710e279ac38911aadfb0a09 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/16/18ce1085acb41fd710e279ac38911aadfb0a09 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/16/18ce1085acb41fd710e279ac38911aadfb0a09 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/16/18ce1085acb41fd710e279ac38911aadfb0a09 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/1f/bc3eb4b11cb89b204a593572c2e01462ca5a89 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/1f/bc3eb4b11cb89b204a593572c2e01462ca5a89 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/1f/bc3eb4b11cb89b204a593572c2e01462ca5a89 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/1f/bc3eb4b11cb89b204a593572c2e01462ca5a89 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/24/10ee12b940bade9d9e99413732faa6dc60adb1 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/24/10ee12b940bade9d9e99413732faa6dc60adb1 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/24/10ee12b940bade9d9e99413732faa6dc60adb1 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/24/10ee12b940bade9d9e99413732faa6dc60adb1 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/27/94411aa7b73b44f533fb862cdb9dbfd13c5d92 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/27/94411aa7b73b44f533fb862cdb9dbfd13c5d92 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/27/94411aa7b73b44f533fb862cdb9dbfd13c5d92 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/27/94411aa7b73b44f533fb862cdb9dbfd13c5d92 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/34/1cf8213827614a274c750cd7dec4307eb41de7 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/34/1cf8213827614a274c750cd7dec4307eb41de7 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/34/1cf8213827614a274c750cd7dec4307eb41de7 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/34/1cf8213827614a274c750cd7dec4307eb41de7 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/49/7b1e236588f0e2674c9a5787abeb226abf3680 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/49/7b1e236588f0e2674c9a5787abeb226abf3680 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/49/7b1e236588f0e2674c9a5787abeb226abf3680 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/49/7b1e236588f0e2674c9a5787abeb226abf3680 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/55/9043765dc6c32c943b6278b4abbff1e6f52839 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/55/9043765dc6c32c943b6278b4abbff1e6f52839 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/55/9043765dc6c32c943b6278b4abbff1e6f52839 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/55/9043765dc6c32c943b6278b4abbff1e6f52839 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/55/f688e6b47b7a5ca8ffc4e25b77c1af6222b503 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/55/f688e6b47b7a5ca8ffc4e25b77c1af6222b503 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/55/f688e6b47b7a5ca8ffc4e25b77c1af6222b503 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/55/f688e6b47b7a5ca8ffc4e25b77c1af6222b503 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/56/2af0640203fb5a6e92c090d8d1ded26806d2c4 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/56/2af0640203fb5a6e92c090d8d1ded26806d2c4 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/56/2af0640203fb5a6e92c090d8d1ded26806d2c4 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/56/2af0640203fb5a6e92c090d8d1ded26806d2c4 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/5d/874a902548f753e50944827e572a7470aa9731 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/61/db24350a92fa37b2fe35f13eb3dd3f7655f6cf b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/61/db24350a92fa37b2fe35f13eb3dd3f7655f6cf similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/61/db24350a92fa37b2fe35f13eb3dd3f7655f6cf rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/61/db24350a92fa37b2fe35f13eb3dd3f7655f6cf diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/a1/9ec0b99e516795f349033f09383f87be0b74e9 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/a1/9ec0b99e516795f349033f09383f87be0b74e9 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/a1/9ec0b99e516795f349033f09383f87be0b74e9 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/a1/9ec0b99e516795f349033f09383f87be0b74e9 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/a1/e00cd67130c6f7e2b9bb7f23f0cda2b37eb30b b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/a1/e00cd67130c6f7e2b9bb7f23f0cda2b37eb30b similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/a1/e00cd67130c6f7e2b9bb7f23f0cda2b37eb30b rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/a1/e00cd67130c6f7e2b9bb7f23f0cda2b37eb30b diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/b0/753bdba91b84e3f406e21dbc7deba8e98f1fc8 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/b0/753bdba91b84e3f406e21dbc7deba8e98f1fc8 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/b0/753bdba91b84e3f406e21dbc7deba8e98f1fc8 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/b0/753bdba91b84e3f406e21dbc7deba8e98f1fc8 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/b2/d5312a06a9c56e9ada21c48a12f57ce8dd4c4a b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/b2/d5312a06a9c56e9ada21c48a12f57ce8dd4c4a similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/b2/d5312a06a9c56e9ada21c48a12f57ce8dd4c4a rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/b2/d5312a06a9c56e9ada21c48a12f57ce8dd4c4a diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/cc/19bee93215b6c20ab129fb2c006762d4ae1497 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/cc/19bee93215b6c20ab129fb2c006762d4ae1497 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/cc/19bee93215b6c20ab129fb2c006762d4ae1497 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/cc/19bee93215b6c20ab129fb2c006762d4ae1497 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/d3/e2708327280097b5e1f8ab69309934b24f8b64 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/d3/e2708327280097b5e1f8ab69309934b24f8b64 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/d3/e2708327280097b5e1f8ab69309934b24f8b64 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/d3/e2708327280097b5e1f8ab69309934b24f8b64 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/dd/259e90c3748e269bdf1ee3ce537a006d2394aa b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/dd/259e90c3748e269bdf1ee3ce537a006d2394aa similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/dd/259e90c3748e269bdf1ee3ce537a006d2394aa rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/dd/259e90c3748e269bdf1ee3ce537a006d2394aa diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/df/2c0daa40dcba0dded361a25ff7806b13db59a6 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/df/2c0daa40dcba0dded361a25ff7806b13db59a6 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/df/2c0daa40dcba0dded361a25ff7806b13db59a6 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/df/2c0daa40dcba0dded361a25ff7806b13db59a6 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/e5/63585cb87cc39b553ca421902d631ea8890118 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/e5/63585cb87cc39b553ca421902d631ea8890118 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/e5/63585cb87cc39b553ca421902d631ea8890118 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/e5/63585cb87cc39b553ca421902d631ea8890118 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/ed/d4e2e50eb82125428b045c540a9194d934e180 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/ed/d4e2e50eb82125428b045c540a9194d934e180 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/ed/d4e2e50eb82125428b045c540a9194d934e180 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/ed/d4e2e50eb82125428b045c540a9194d934e180 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/f7/f30ea7f84d4521d3ce9cc08b780c7a1bf7cc5e b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/f7/f30ea7f84d4521d3ce9cc08b780c7a1bf7cc5e similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/f7/f30ea7f84d4521d3ce9cc08b780c7a1bf7cc5e rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/f7/f30ea7f84d4521d3ce9cc08b780c7a1bf7cc5e diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/f8/9097f0bd23eda6d8977c0edfae7f913ffc5db3 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/f8/9097f0bd23eda6d8977c0edfae7f913ffc5db3 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/f8/9097f0bd23eda6d8977c0edfae7f913ffc5db3 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/f8/9097f0bd23eda6d8977c0edfae7f913ffc5db3 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/f8/dd12b796f400be7f59d9471670c3080f9c90a1 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/f8/dd12b796f400be7f59d9471670c3080f9c90a1 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/f8/dd12b796f400be7f59d9471670c3080f9c90a1 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/f8/dd12b796f400be7f59d9471670c3080f9c90a1 diff --git a/test/integration/mergeConflicts/expected/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 b/test/integration/mergeConflicts/expected/repo/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 rename to test/integration/mergeConflicts/expected/repo/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 diff --git a/test/integration/mergeConflicts/expected/.git_keep/refs/heads/base_branch b/test/integration/mergeConflicts/expected/repo/.git_keep/refs/heads/base_branch similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/refs/heads/base_branch rename to test/integration/mergeConflicts/expected/repo/.git_keep/refs/heads/base_branch diff --git a/test/integration/mergeConflicts/expected/.git_keep/refs/heads/develop b/test/integration/mergeConflicts/expected/repo/.git_keep/refs/heads/develop similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/refs/heads/develop rename to test/integration/mergeConflicts/expected/repo/.git_keep/refs/heads/develop diff --git a/test/integration/mergeConflicts/expected/.git_keep/refs/heads/feature/cherry-picking b/test/integration/mergeConflicts/expected/repo/.git_keep/refs/heads/feature/cherry-picking similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/refs/heads/feature/cherry-picking rename to test/integration/mergeConflicts/expected/repo/.git_keep/refs/heads/feature/cherry-picking diff --git a/test/integration/mergeConflicts/expected/.git_keep/refs/heads/master b/test/integration/mergeConflicts/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/refs/heads/master rename to test/integration/mergeConflicts/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/mergeConflicts/expected/.git_keep/refs/heads/other_branch b/test/integration/mergeConflicts/expected/repo/.git_keep/refs/heads/other_branch similarity index 100% rename from test/integration/mergeConflicts/expected/.git_keep/refs/heads/other_branch rename to test/integration/mergeConflicts/expected/repo/.git_keep/refs/heads/other_branch diff --git a/test/integration/mergeConflicts/expected/cherrypicking1 b/test/integration/mergeConflicts/expected/repo/cherrypicking1 similarity index 100% rename from test/integration/mergeConflicts/expected/cherrypicking1 rename to test/integration/mergeConflicts/expected/repo/cherrypicking1 diff --git a/test/integration/mergeConflicts/expected/cherrypicking2 b/test/integration/mergeConflicts/expected/repo/cherrypicking2 similarity index 100% rename from test/integration/mergeConflicts/expected/cherrypicking2 rename to test/integration/mergeConflicts/expected/repo/cherrypicking2 diff --git a/test/integration/mergeConflicts/expected/cherrypicking3 b/test/integration/mergeConflicts/expected/repo/cherrypicking3 similarity index 100% rename from test/integration/mergeConflicts/expected/cherrypicking3 rename to test/integration/mergeConflicts/expected/repo/cherrypicking3 diff --git a/test/integration/mergeConflicts/expected/cherrypicking4 b/test/integration/mergeConflicts/expected/repo/cherrypicking4 similarity index 100% rename from test/integration/mergeConflicts/expected/cherrypicking4 rename to test/integration/mergeConflicts/expected/repo/cherrypicking4 diff --git a/test/integration/mergeConflicts/expected/cherrypicking5 b/test/integration/mergeConflicts/expected/repo/cherrypicking5 similarity index 100% rename from test/integration/mergeConflicts/expected/cherrypicking5 rename to test/integration/mergeConflicts/expected/repo/cherrypicking5 diff --git a/test/integration/mergeConflicts/expected/cherrypicking6 b/test/integration/mergeConflicts/expected/repo/cherrypicking6 similarity index 100% rename from test/integration/mergeConflicts/expected/cherrypicking6 rename to test/integration/mergeConflicts/expected/repo/cherrypicking6 diff --git a/test/integration/mergeConflicts/expected/cherrypicking7 b/test/integration/mergeConflicts/expected/repo/cherrypicking7 similarity index 100% rename from test/integration/mergeConflicts/expected/cherrypicking7 rename to test/integration/mergeConflicts/expected/repo/cherrypicking7 diff --git a/test/integration/mergeConflicts/expected/cherrypicking8 b/test/integration/mergeConflicts/expected/repo/cherrypicking8 similarity index 100% rename from test/integration/mergeConflicts/expected/cherrypicking8 rename to test/integration/mergeConflicts/expected/repo/cherrypicking8 diff --git a/test/integration/mergeConflicts/expected/cherrypicking9 b/test/integration/mergeConflicts/expected/repo/cherrypicking9 similarity index 100% rename from test/integration/mergeConflicts/expected/cherrypicking9 rename to test/integration/mergeConflicts/expected/repo/cherrypicking9 diff --git a/test/integration/mergeConflicts/expected/directory/file b/test/integration/mergeConflicts/expected/repo/directory/file similarity index 100% rename from test/integration/mergeConflicts/expected/directory/file rename to test/integration/mergeConflicts/expected/repo/directory/file diff --git a/test/integration/mergeConflicts/expected/directory/file2 b/test/integration/mergeConflicts/expected/repo/directory/file2 similarity index 100% rename from test/integration/mergeConflicts/expected/directory/file2 rename to test/integration/mergeConflicts/expected/repo/directory/file2 diff --git a/test/integration/mergeConflicts/expected/file b/test/integration/mergeConflicts/expected/repo/file similarity index 100% rename from test/integration/mergeConflicts/expected/file rename to test/integration/mergeConflicts/expected/repo/file diff --git a/test/integration/mergeConflicts/expected/file1 b/test/integration/mergeConflicts/expected/repo/file1 similarity index 100% rename from test/integration/mergeConflicts/expected/file1 rename to test/integration/mergeConflicts/expected/repo/file1 diff --git a/test/integration/mergeConflicts/expected/file3 b/test/integration/mergeConflicts/expected/repo/file3 similarity index 100% rename from test/integration/mergeConflicts/expected/file3 rename to test/integration/mergeConflicts/expected/repo/file3 diff --git a/test/integration/mergeConflicts/expected/file4 b/test/integration/mergeConflicts/expected/repo/file4 similarity index 100% rename from test/integration/mergeConflicts/expected/file4 rename to test/integration/mergeConflicts/expected/repo/file4 diff --git a/test/integration/mergeConflicts/expected/file5 b/test/integration/mergeConflicts/expected/repo/file5 similarity index 100% rename from test/integration/mergeConflicts/expected/file5 rename to test/integration/mergeConflicts/expected/repo/file5 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/COMMIT_EDITMSG b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/FETCH_HEAD b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/FETCH_HEAD rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/HEAD b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/HEAD rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/HEAD diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/ORIG_HEAD b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/ORIG_HEAD similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/ORIG_HEAD rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/ORIG_HEAD diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/config b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/config similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/config rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/config diff --git a/test/integration/patchBuilding/expected/.git_keep/description b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/description similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/description rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/description diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/index b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/index similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/index rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/index diff --git a/test/integration/patchBuilding/expected/.git_keep/info/exclude b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/info/exclude rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/info/exclude diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/HEAD b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/logs/HEAD rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/base_branch b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/logs/refs/heads/base_branch similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/base_branch rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/logs/refs/heads/base_branch diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/develop b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/logs/refs/heads/develop similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/develop rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/logs/refs/heads/develop diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/feature/cherry-picking b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/logs/refs/heads/feature/cherry-picking similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/feature/cherry-picking rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/logs/refs/heads/feature/cherry-picking diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/master b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/master rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/other_branch b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/logs/refs/heads/other_branch similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/logs/refs/heads/other_branch rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/logs/refs/heads/other_branch diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/09/cbe8c6717c06a61876b7b641a46a62bf3c585d diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/0f/8c9b8f1cac20c63e92e8df34f6d8b3fa74accd b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/0f/8c9b8f1cac20c63e92e8df34f6d8b3fa74accd similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/0f/8c9b8f1cac20c63e92e8df34f6d8b3fa74accd rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/0f/8c9b8f1cac20c63e92e8df34f6d8b3fa74accd diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/17/3a40ed58e33060166ccbfb7d0ccc0387be5f09 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/17/4a8c9444cfa700682d74059d9fa9be5749242c diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/18/f469bc737f6c2a589205e2ddefceb32a7cc3a7 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/1b/9ae5f5dff631baaa180a30afd9983f83dc27ca diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/20/85c8dd0a80e95ed959e4db2ab98f66b970ad77 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/21/730e75ee0eec374cc54eb1140d24e03db834fc b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/21/730e75ee0eec374cc54eb1140d24e03db834fc similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/21/730e75ee0eec374cc54eb1140d24e03db834fc rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/21/730e75ee0eec374cc54eb1140d24e03db834fc diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/21/78af7503938665881174069be4d48fa483e4af diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/22/b0fd807dd5e428c2d818aef6a2311d7c11e885 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/24/6f7487e08e6330ccbec4053e701145d53f64d4 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/2e/cced19ece4424e0d3f26eb3ea2ccb6bfeafaa8 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/32/d15fd4451b6693a93d6420c8af6cfc99348e71 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/34/c74161eef968fc951cf170a011fa8abfeddbcd diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/34/d20faa891d1857610dce8f790a35b702ebd7ee b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/34/d20faa891d1857610dce8f790a35b702ebd7ee similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/34/d20faa891d1857610dce8f790a35b702ebd7ee rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/34/d20faa891d1857610dce8f790a35b702ebd7ee diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/36/e0ef3e52c6e29e64980c71defbab6064d2da8c diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/38/08a710b52a152bb73805fe274e0d877cf61800 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/41/893d444283aa0c46aa7b5ee01811522cca473d b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/41/893d444283aa0c46aa7b5ee01811522cca473d similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/41/893d444283aa0c46aa7b5ee01811522cca473d rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/41/893d444283aa0c46aa7b5ee01811522cca473d diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4b/6f90d670c40e5ac78d9c405a5bc40932a0980b b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/4b/6f90d670c40e5ac78d9c405a5bc40932a0980b similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4b/6f90d670c40e5ac78d9c405a5bc40932a0980b rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/4b/6f90d670c40e5ac78d9c405a5bc40932a0980b diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/4f/80ec0c7b09eeeb580d0c19947477c02bc88c25 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/5d/a4d9200457542d875fe4def54ac98c16332db0 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/5e/66799d4a5a3fed89757f3df445a962c9ce2d4f b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/5e/66799d4a5a3fed89757f3df445a962c9ce2d4f similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/5e/66799d4a5a3fed89757f3df445a962c9ce2d4f rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/5e/66799d4a5a3fed89757f3df445a962c9ce2d4f diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/5f/3e4598b46a912f0f95a4898743e979343c82f3 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/60/91d709b275e712111d016d9b3a4fb44e63f1f6 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/61/01e935461d4cd862ae4a720846e87880d198b9 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/67/b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/67/b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/67/b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/67/b2eea3191ca9a6efc8c1685aadd8e6dbae2b45 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/6c/590c6a21f4e6d335528b5ecf6c52993b914996 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/6c/590c6a21f4e6d335528b5ecf6c52993b914996 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/6c/590c6a21f4e6d335528b5ecf6c52993b914996 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/6c/590c6a21f4e6d335528b5ecf6c52993b914996 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/72/c9bf1e687e81778850d517953c64f03adbaa1b b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/72/c9bf1e687e81778850d517953c64f03adbaa1b similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/72/c9bf1e687e81778850d517953c64f03adbaa1b rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/72/c9bf1e687e81778850d517953c64f03adbaa1b diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/72/df4fceb0be99deb091ece3f501ef80b39a876a b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/72/df4fceb0be99deb091ece3f501ef80b39a876a similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/72/df4fceb0be99deb091ece3f501ef80b39a876a rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/72/df4fceb0be99deb091ece3f501ef80b39a876a diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/78/3666de4acbb22a9efc205197667f5136118c54 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/79/6a5a2670ccb2d08db89b9cfcaa07e9be5358e6 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/79/6a5a2670ccb2d08db89b9cfcaa07e9be5358e6 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/79/6a5a2670ccb2d08db89b9cfcaa07e9be5358e6 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/79/6a5a2670ccb2d08db89b9cfcaa07e9be5358e6 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/88/9b0fdfe5f2ae3d7df3066f3bc1e181fa712c8d diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/88/c39cdc29c995f8e1a63ccd48e7bbd6d96cb8b8 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/90/a84fd62f8033027fab3e567a81d5ed2a6a71cd diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/91/65a12a95d3b2b9b8a0374de787af169b2c339e diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/95/9d7a10da71acf97b17300b40a3b4f30903e09c diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/9a/92a03fdc6eb492ea1ac7acf4fdb04962092f81 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/9a/92a03fdc6eb492ea1ac7acf4fdb04962092f81 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/9a/92a03fdc6eb492ea1ac7acf4fdb04962092f81 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/9a/92a03fdc6eb492ea1ac7acf4fdb04962092f81 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/9d/e8260b738a34a74533df54f2e404276aa96242 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/a5/1a44d96e13555215619b32065d0a22d95b8476 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/a5/1a44d96e13555215619b32065d0a22d95b8476 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/a5/1a44d96e13555215619b32065d0a22d95b8476 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/a5/1a44d96e13555215619b32065d0a22d95b8476 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/ab/daa06b758aa198cc4afb9c406c87c5690d0ca0 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/ab/daa06b758aa198cc4afb9c406c87c5690d0ca0 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/ab/daa06b758aa198cc4afb9c406c87c5690d0ca0 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/ab/daa06b758aa198cc4afb9c406c87c5690d0ca0 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/af/a76754c933269d7cd45630a7184a20849dbe9c diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/b2/afb2548f2d143fdd691058f2283b03933a1749 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/b2/afb2548f2d143fdd691058f2283b03933a1749 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/b2/afb2548f2d143fdd691058f2283b03933a1749 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/b2/afb2548f2d143fdd691058f2283b03933a1749 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/b4/121e2d6aa156227b6541431ddfb8594904b520 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/c1/dd146476a4a37fff75b88612a718281ea83b58 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/c6/2b5bc94e327ddb9b545213ff77b207ade48aba b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/c6/2b5bc94e327ddb9b545213ff77b207ade48aba similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/c6/2b5bc94e327ddb9b545213ff77b207ade48aba rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/c6/2b5bc94e327ddb9b545213ff77b207ade48aba diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/d0/60f7226715ca55b04e91fad2b8aca01badd993 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/d4/f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/d4/f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/d4/f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/d4/f8ef9f7c7602e92d2b2c7228bdaf3c7314d802 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/d7/d52ecd690fe82c7d820ddb437e82d78b0fa7b2 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/d7/d52ecd690fe82c7d820ddb437e82d78b0fa7b2 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/d7/d52ecd690fe82c7d820ddb437e82d78b0fa7b2 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/d7/d52ecd690fe82c7d820ddb437e82d78b0fa7b2 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/d8/8617710499a59992caf98d6df1b5f981c58ab1 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/d8/8617710499a59992caf98d6df1b5f981c58ab1 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/d8/8617710499a59992caf98d6df1b5f981c58ab1 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/d8/8617710499a59992caf98d6df1b5f981c58ab1 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/d8/a7c50dcab42b2b62e5c77cdcece620d3964bd4 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/da/72a6dd6fbaaa4a2803a3c867437ab81a1a99a0 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/dc/d348507ba1da8f6479b9d964daa302b2fb9d9c diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/dd/401e3ee3d58b648207cee7f737364a37139bea b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/dd/401e3ee3d58b648207cee7f737364a37139bea similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/dd/401e3ee3d58b648207cee7f737364a37139bea rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/dd/401e3ee3d58b648207cee7f737364a37139bea diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/e3/ae5c6d8407e8307b9bc77923be78c901408f6e diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/e4/48ae5bf6371d80ebee24a22b6df341797a6511 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/e4/666ba294866d5c16f9afebcacf8f4adfee7439 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/ea/a48cb1e3d47e1b8b8df47bdc248e991207cc3d diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/eb/90e8d7b137a1d89480c9b22fd03199da77c9c7 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/f1/46c7f7b874778c1ad0cf9aebe45ec2427c7de2 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/f3/7ec566036d715d6995f55dbc82a4fb3cf56f2f b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/f3/7ec566036d715d6995f55dbc82a4fb3cf56f2f similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/f3/7ec566036d715d6995f55dbc82a4fb3cf56f2f rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/f3/7ec566036d715d6995f55dbc82a4fb3cf56f2f diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/f3/f762af4429ae89fa0dae3d0a5b500ca11630c4 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/fa/5c5dac095b577173e47b4a0c139525eced009f b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/fa/5c5dac095b577173e47b4a0c139525eced009f similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/fa/5c5dac095b577173e47b4a0c139525eced009f rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/fa/5c5dac095b577173e47b4a0c139525eced009f diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/objects/fd/31cea7e0b6e8d334280be34db8dd86cdda3007 diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/base_branch b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/refs/heads/base_branch similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/base_branch rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/refs/heads/base_branch diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/develop b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/refs/heads/develop similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/develop rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/refs/heads/develop diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/feature/cherry-picking b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/refs/heads/feature/cherry-picking similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/feature/cherry-picking rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/refs/heads/feature/cherry-picking diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/master b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/master rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/other_branch b/test/integration/mergeConflictsFiltered/expected/repo/.git_keep/refs/heads/other_branch similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/.git_keep/refs/heads/other_branch rename to test/integration/mergeConflictsFiltered/expected/repo/.git_keep/refs/heads/other_branch diff --git a/test/integration/mergeConflictsFiltered/expected/cherrypicking1 b/test/integration/mergeConflictsFiltered/expected/repo/cherrypicking1 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/cherrypicking1 rename to test/integration/mergeConflictsFiltered/expected/repo/cherrypicking1 diff --git a/test/integration/mergeConflictsFiltered/expected/cherrypicking2 b/test/integration/mergeConflictsFiltered/expected/repo/cherrypicking2 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/cherrypicking2 rename to test/integration/mergeConflictsFiltered/expected/repo/cherrypicking2 diff --git a/test/integration/mergeConflictsFiltered/expected/cherrypicking3 b/test/integration/mergeConflictsFiltered/expected/repo/cherrypicking3 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/cherrypicking3 rename to test/integration/mergeConflictsFiltered/expected/repo/cherrypicking3 diff --git a/test/integration/mergeConflictsFiltered/expected/cherrypicking4 b/test/integration/mergeConflictsFiltered/expected/repo/cherrypicking4 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/cherrypicking4 rename to test/integration/mergeConflictsFiltered/expected/repo/cherrypicking4 diff --git a/test/integration/mergeConflictsFiltered/expected/cherrypicking5 b/test/integration/mergeConflictsFiltered/expected/repo/cherrypicking5 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/cherrypicking5 rename to test/integration/mergeConflictsFiltered/expected/repo/cherrypicking5 diff --git a/test/integration/mergeConflictsFiltered/expected/cherrypicking6 b/test/integration/mergeConflictsFiltered/expected/repo/cherrypicking6 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/cherrypicking6 rename to test/integration/mergeConflictsFiltered/expected/repo/cherrypicking6 diff --git a/test/integration/mergeConflictsFiltered/expected/cherrypicking7 b/test/integration/mergeConflictsFiltered/expected/repo/cherrypicking7 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/cherrypicking7 rename to test/integration/mergeConflictsFiltered/expected/repo/cherrypicking7 diff --git a/test/integration/mergeConflictsFiltered/expected/cherrypicking8 b/test/integration/mergeConflictsFiltered/expected/repo/cherrypicking8 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/cherrypicking8 rename to test/integration/mergeConflictsFiltered/expected/repo/cherrypicking8 diff --git a/test/integration/mergeConflictsFiltered/expected/cherrypicking9 b/test/integration/mergeConflictsFiltered/expected/repo/cherrypicking9 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/cherrypicking9 rename to test/integration/mergeConflictsFiltered/expected/repo/cherrypicking9 diff --git a/test/integration/mergeConflictsFiltered/expected/directory/file b/test/integration/mergeConflictsFiltered/expected/repo/directory/file similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/directory/file rename to test/integration/mergeConflictsFiltered/expected/repo/directory/file diff --git a/test/integration/mergeConflictsFiltered/expected/directory/file2 b/test/integration/mergeConflictsFiltered/expected/repo/directory/file2 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/directory/file2 rename to test/integration/mergeConflictsFiltered/expected/repo/directory/file2 diff --git a/test/integration/mergeConflictsFiltered/expected/file b/test/integration/mergeConflictsFiltered/expected/repo/file similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/file rename to test/integration/mergeConflictsFiltered/expected/repo/file diff --git a/test/integration/mergeConflictsFiltered/expected/file1 b/test/integration/mergeConflictsFiltered/expected/repo/file1 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/file1 rename to test/integration/mergeConflictsFiltered/expected/repo/file1 diff --git a/test/integration/mergeConflictsFiltered/expected/file3 b/test/integration/mergeConflictsFiltered/expected/repo/file3 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/file3 rename to test/integration/mergeConflictsFiltered/expected/repo/file3 diff --git a/test/integration/mergeConflictsFiltered/expected/file4 b/test/integration/mergeConflictsFiltered/expected/repo/file4 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/file4 rename to test/integration/mergeConflictsFiltered/expected/repo/file4 diff --git a/test/integration/mergeConflictsFiltered/expected/file5 b/test/integration/mergeConflictsFiltered/expected/repo/file5 similarity index 100% rename from test/integration/mergeConflictsFiltered/expected/file5 rename to test/integration/mergeConflictsFiltered/expected/repo/file5 diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/COMMIT_EDITMSG b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/FETCH_HEAD b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/FETCH_HEAD rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/HEAD b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/HEAD rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/HEAD diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/ORIG_HEAD b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/ORIG_HEAD similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/ORIG_HEAD rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/ORIG_HEAD diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/config b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/config similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/config rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/config diff --git a/test/integration/patchBuilding2/expected/.git_keep/description b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/description similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/description rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/description diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/index b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/index similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/index rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/index diff --git a/test/integration/patchBuilding2/expected/.git_keep/info/exclude b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/info/exclude rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/info/exclude diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/logs/HEAD b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/logs/HEAD rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/logs/refs/heads/master b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/logs/refs/heads/master rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/logs/refs/heads/other b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/logs/refs/heads/other similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/logs/refs/heads/other rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/logs/refs/heads/other diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/03/959db9f70fcb4a8f0931e4ad64e1c9ec1016a4 b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/03/959db9f70fcb4a8f0931e4ad64e1c9ec1016a4 similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/03/959db9f70fcb4a8f0931e4ad64e1c9ec1016a4 rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/03/959db9f70fcb4a8f0931e4ad64e1c9ec1016a4 diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/08/84a47e04257f4c85435a8b10ff4f15fffa63fc b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/08/84a47e04257f4c85435a8b10ff4f15fffa63fc similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/08/84a47e04257f4c85435a8b10ff4f15fffa63fc rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/08/84a47e04257f4c85435a8b10ff4f15fffa63fc diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/0b/e6e80a67f6276c5ede28dd6b8fa8873f1b23c5 b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/0b/e6e80a67f6276c5ede28dd6b8fa8873f1b23c5 similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/0b/e6e80a67f6276c5ede28dd6b8fa8873f1b23c5 rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/0b/e6e80a67f6276c5ede28dd6b8fa8873f1b23c5 diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/2d/8021ed8803ed6142d31b331850ef46246391a7 b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/2d/8021ed8803ed6142d31b331850ef46246391a7 similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/2d/8021ed8803ed6142d31b331850ef46246391a7 rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/2d/8021ed8803ed6142d31b331850ef46246391a7 diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/53/502c7023f80c046a1b00b45614d5ffef8977d9 b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/53/502c7023f80c046a1b00b45614d5ffef8977d9 similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/53/502c7023f80c046a1b00b45614d5ffef8977d9 rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/53/502c7023f80c046a1b00b45614d5ffef8977d9 diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/69/1ee9e9d9c654c81214f56c514ff725f46cb9e4 b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/69/1ee9e9d9c654c81214f56c514ff725f46cb9e4 similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/69/1ee9e9d9c654c81214f56c514ff725f46cb9e4 rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/69/1ee9e9d9c654c81214f56c514ff725f46cb9e4 diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/6b/03bc7537ecf00b48a0ea57ce1edf388ed3f1ad b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/6b/03bc7537ecf00b48a0ea57ce1edf388ed3f1ad similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/6b/03bc7537ecf00b48a0ea57ce1edf388ed3f1ad rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/6b/03bc7537ecf00b48a0ea57ce1edf388ed3f1ad diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/76/9c8b8d89700f6f196b8331159150746a839662 b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/76/9c8b8d89700f6f196b8331159150746a839662 similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/76/9c8b8d89700f6f196b8331159150746a839662 rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/76/9c8b8d89700f6f196b8331159150746a839662 diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/bd/2b32f02abf86a2bb79a12ab09758e44b204b34 b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/bd/2b32f02abf86a2bb79a12ab09758e44b204b34 similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/bd/2b32f02abf86a2bb79a12ab09758e44b204b34 rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/bd/2b32f02abf86a2bb79a12ab09758e44b204b34 diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/c0/565d7cfcf1039c969105f2e1c86ca5eff64381 b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/c0/565d7cfcf1039c969105f2e1c86ca5eff64381 similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/c0/565d7cfcf1039c969105f2e1c86ca5eff64381 rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/c0/565d7cfcf1039c969105f2e1c86ca5eff64381 diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/f2/df244fb87b6ba1d2ab484d76c66baba168a867 b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/f2/df244fb87b6ba1d2ab484d76c66baba168a867 similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/objects/f2/df244fb87b6ba1d2ab484d76c66baba168a867 rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/objects/f2/df244fb87b6ba1d2ab484d76c66baba168a867 diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/refs/heads/master b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/refs/heads/master rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/mergeConflictsResolvedExternally/expected/.git_keep/refs/heads/other b/test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/refs/heads/other similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/.git_keep/refs/heads/other rename to test/integration/mergeConflictsResolvedExternally/expected/repo/.git_keep/refs/heads/other diff --git a/test/integration/mergeConflictsResolvedExternally/expected/file b/test/integration/mergeConflictsResolvedExternally/expected/repo/file similarity index 100% rename from test/integration/mergeConflictsResolvedExternally/expected/file rename to test/integration/mergeConflictsResolvedExternally/expected/repo/file diff --git a/test/integration/patchBuilding/expected/.git_keep/COMMIT_EDITMSG b/test/integration/patchBuilding/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/patchBuilding/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/patchBuilding/expected/.git_keep/FETCH_HEAD b/test/integration/patchBuilding/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/FETCH_HEAD rename to test/integration/patchBuilding/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/HEAD b/test/integration/patchBuilding/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/HEAD rename to test/integration/patchBuilding/expected/repo/.git_keep/HEAD diff --git a/test/integration/patchBuilding/expected/.git_keep/ORIG_HEAD b/test/integration/patchBuilding/expected/repo/.git_keep/ORIG_HEAD similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/ORIG_HEAD rename to test/integration/patchBuilding/expected/repo/.git_keep/ORIG_HEAD diff --git a/test/integration/patchBuilding/expected/.git_keep/config b/test/integration/patchBuilding/expected/repo/.git_keep/config similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/config rename to test/integration/patchBuilding/expected/repo/.git_keep/config diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/description b/test/integration/patchBuilding/expected/repo/.git_keep/description similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/description rename to test/integration/patchBuilding/expected/repo/.git_keep/description diff --git a/test/integration/patchBuilding/expected/.git_keep/index b/test/integration/patchBuilding/expected/repo/.git_keep/index similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/index rename to test/integration/patchBuilding/expected/repo/.git_keep/index diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/info/exclude b/test/integration/patchBuilding/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/info/exclude rename to test/integration/patchBuilding/expected/repo/.git_keep/info/exclude diff --git a/test/integration/patchBuilding/expected/.git_keep/logs/HEAD b/test/integration/patchBuilding/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/logs/HEAD rename to test/integration/patchBuilding/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/patchBuilding/expected/.git_keep/logs/refs/heads/master b/test/integration/patchBuilding/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/logs/refs/heads/master rename to test/integration/patchBuilding/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/01/5689313279311c9356ea3fd3628f73ca4ea797 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/01/5689313279311c9356ea3fd3628f73ca4ea797 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/01/5689313279311c9356ea3fd3628f73ca4ea797 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/01/5689313279311c9356ea3fd3628f73ca4ea797 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/01/ed22faef05591076721466e07fb10962642887 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/01/ed22faef05591076721466e07fb10962642887 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/01/ed22faef05591076721466e07fb10962642887 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/01/ed22faef05591076721466e07fb10962642887 diff --git a/test/integration/pull/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/pull/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/24/4cec6fa9704d5dc61fc5e60faba4125dfe3baa b/test/integration/patchBuilding/expected/repo/.git_keep/objects/24/4cec6fa9704d5dc61fc5e60faba4125dfe3baa similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/24/4cec6fa9704d5dc61fc5e60faba4125dfe3baa rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/24/4cec6fa9704d5dc61fc5e60faba4125dfe3baa diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/24/79abfe7bd6b64a753d3c3797f614bbb422f627 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/24/79abfe7bd6b64a753d3c3797f614bbb422f627 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/24/79abfe7bd6b64a753d3c3797f614bbb422f627 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/24/79abfe7bd6b64a753d3c3797f614bbb422f627 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/47/5a06b7978eef6509efdd2a86e341992d9f2908 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/47/5a06b7978eef6509efdd2a86e341992d9f2908 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/47/5a06b7978eef6509efdd2a86e341992d9f2908 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/47/5a06b7978eef6509efdd2a86e341992d9f2908 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/52/863675692b53d9e34dd72da8c35a72bf0a5b51 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/52/863675692b53d9e34dd72da8c35a72bf0a5b51 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/52/863675692b53d9e34dd72da8c35a72bf0a5b51 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/52/863675692b53d9e34dd72da8c35a72bf0a5b51 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/7a/40dadc0814bf7f1418d005eae184848a9f1c94 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/7a/40dadc0814bf7f1418d005eae184848a9f1c94 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/7a/40dadc0814bf7f1418d005eae184848a9f1c94 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/7a/40dadc0814bf7f1418d005eae184848a9f1c94 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/92/2fc2ed1965fe8436ce7837c634379f14faf3c3 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/92/2fc2ed1965fe8436ce7837c634379f14faf3c3 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/92/2fc2ed1965fe8436ce7837c634379f14faf3c3 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/92/2fc2ed1965fe8436ce7837c634379f14faf3c3 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/92/571130f37c70766612048271f1d4dca63ef0b5 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/92/571130f37c70766612048271f1d4dca63ef0b5 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/92/571130f37c70766612048271f1d4dca63ef0b5 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/92/571130f37c70766612048271f1d4dca63ef0b5 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/93/96d8d0c471661257f6c16c1957452912c0c6f5 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/93/96d8d0c471661257f6c16c1957452912c0c6f5 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/93/96d8d0c471661257f6c16c1957452912c0c6f5 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/93/96d8d0c471661257f6c16c1957452912c0c6f5 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/a3/2f90adf7ee0f14ae300e49cdf8779507746c27 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/a3/2f90adf7ee0f14ae300e49cdf8779507746c27 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/a3/2f90adf7ee0f14ae300e49cdf8779507746c27 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/a3/2f90adf7ee0f14ae300e49cdf8779507746c27 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/ad/e030587c8ae5d240ad7669bff9030b24bd6385 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/ad/e030587c8ae5d240ad7669bff9030b24bd6385 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/ad/e030587c8ae5d240ad7669bff9030b24bd6385 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/ad/e030587c8ae5d240ad7669bff9030b24bd6385 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/c6/9e35e8cae5688bbfcf8278c20ab43c1b8dbae3 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/c6/9e35e8cae5688bbfcf8278c20ab43c1b8dbae3 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/c6/9e35e8cae5688bbfcf8278c20ab43c1b8dbae3 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/c6/9e35e8cae5688bbfcf8278c20ab43c1b8dbae3 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/ce/024fc694fd464cfb5b43cb7702f0bd7345d882 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/ce/024fc694fd464cfb5b43cb7702f0bd7345d882 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/ce/024fc694fd464cfb5b43cb7702f0bd7345d882 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/ce/024fc694fd464cfb5b43cb7702f0bd7345d882 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/patchBuilding/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/e3/31050363ceb0b12d9d042e37879d892d867ea0 b/test/integration/patchBuilding/expected/repo/.git_keep/objects/e3/31050363ceb0b12d9d042e37879d892d867ea0 similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/e3/31050363ceb0b12d9d042e37879d892d867ea0 rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/e3/31050363ceb0b12d9d042e37879d892d867ea0 diff --git a/test/integration/patchBuilding/expected/.git_keep/objects/f3/c8a074e65b02d1bc364caf0b4c1516abf9eb5a b/test/integration/patchBuilding/expected/repo/.git_keep/objects/f3/c8a074e65b02d1bc364caf0b4c1516abf9eb5a similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/objects/f3/c8a074e65b02d1bc364caf0b4c1516abf9eb5a rename to test/integration/patchBuilding/expected/repo/.git_keep/objects/f3/c8a074e65b02d1bc364caf0b4c1516abf9eb5a diff --git a/test/integration/patchBuilding/expected/.git_keep/refs/heads/master b/test/integration/patchBuilding/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/patchBuilding/expected/.git_keep/refs/heads/master rename to test/integration/patchBuilding/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/patchBuilding2/expected/myfile1 b/test/integration/patchBuilding/expected/repo/myfile1 similarity index 100% rename from test/integration/patchBuilding2/expected/myfile1 rename to test/integration/patchBuilding/expected/repo/myfile1 diff --git a/test/integration/patchBuilding/expected/myfile2 b/test/integration/patchBuilding/expected/repo/myfile2 similarity index 100% rename from test/integration/patchBuilding/expected/myfile2 rename to test/integration/patchBuilding/expected/repo/myfile2 diff --git a/test/integration/patchBuilding/expected/myfile3 b/test/integration/patchBuilding/expected/repo/myfile3 similarity index 100% rename from test/integration/patchBuilding/expected/myfile3 rename to test/integration/patchBuilding/expected/repo/myfile3 diff --git a/test/integration/patchBuilding2/expected/.git_keep/COMMIT_EDITMSG b/test/integration/patchBuilding2/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/patchBuilding2/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/patchBuilding2/expected/.git_keep/FETCH_HEAD b/test/integration/patchBuilding2/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/FETCH_HEAD rename to test/integration/patchBuilding2/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/HEAD b/test/integration/patchBuilding2/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/HEAD rename to test/integration/patchBuilding2/expected/repo/.git_keep/HEAD diff --git a/test/integration/patchBuilding2/expected/.git_keep/ORIG_HEAD b/test/integration/patchBuilding2/expected/repo/.git_keep/ORIG_HEAD similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/ORIG_HEAD rename to test/integration/patchBuilding2/expected/repo/.git_keep/ORIG_HEAD diff --git a/test/integration/patchBuilding2/expected/.git_keep/config b/test/integration/patchBuilding2/expected/repo/.git_keep/config similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/config rename to test/integration/patchBuilding2/expected/repo/.git_keep/config diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/description b/test/integration/patchBuilding2/expected/repo/.git_keep/description similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/description rename to test/integration/patchBuilding2/expected/repo/.git_keep/description diff --git a/test/integration/patchBuilding2/expected/.git_keep/index b/test/integration/patchBuilding2/expected/repo/.git_keep/index similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/index rename to test/integration/patchBuilding2/expected/repo/.git_keep/index diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/info/exclude b/test/integration/patchBuilding2/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/info/exclude rename to test/integration/patchBuilding2/expected/repo/.git_keep/info/exclude diff --git a/test/integration/patchBuilding2/expected/.git_keep/logs/HEAD b/test/integration/patchBuilding2/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/logs/HEAD rename to test/integration/patchBuilding2/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/patchBuilding2/expected/.git_keep/logs/refs/heads/master b/test/integration/patchBuilding2/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/logs/refs/heads/master rename to test/integration/patchBuilding2/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/patchBuilding2/expected/.git_keep/logs/refs/stash b/test/integration/patchBuilding2/expected/repo/.git_keep/logs/refs/stash similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/logs/refs/stash rename to test/integration/patchBuilding2/expected/repo/.git_keep/logs/refs/stash diff --git a/test/integration/pull/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/pull/expected_remote/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/1a/b6a62ed874b19c1191ba2b0106741ca4ca4b50 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/1a/b6a62ed874b19c1191ba2b0106741ca4ca4b50 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/1a/b6a62ed874b19c1191ba2b0106741ca4ca4b50 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/1a/b6a62ed874b19c1191ba2b0106741ca4ca4b50 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/2c/60d208ba3ec966b77ca756237843af7584cf93 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/2c/60d208ba3ec966b77ca756237843af7584cf93 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/2c/60d208ba3ec966b77ca756237843af7584cf93 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/2c/60d208ba3ec966b77ca756237843af7584cf93 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/47/5a06b7978eef6509efdd2a86e341992d9f2908 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/47/5a06b7978eef6509efdd2a86e341992d9f2908 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/47/5a06b7978eef6509efdd2a86e341992d9f2908 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/47/5a06b7978eef6509efdd2a86e341992d9f2908 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/50/63202049f1980e035c390732a7e6da8783357f b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/50/63202049f1980e035c390732a7e6da8783357f similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/50/63202049f1980e035c390732a7e6da8783357f rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/50/63202049f1980e035c390732a7e6da8783357f diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/52/863675692b53d9e34dd72da8c35a72bf0a5b51 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/52/863675692b53d9e34dd72da8c35a72bf0a5b51 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/52/863675692b53d9e34dd72da8c35a72bf0a5b51 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/52/863675692b53d9e34dd72da8c35a72bf0a5b51 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/9a/939087472cfaf305396d4b177ee888ced193d9 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/9a/939087472cfaf305396d4b177ee888ced193d9 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/9a/939087472cfaf305396d4b177ee888ced193d9 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/9a/939087472cfaf305396d4b177ee888ced193d9 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/a3/2f90adf7ee0f14ae300e49cdf8779507746c27 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/a3/2f90adf7ee0f14ae300e49cdf8779507746c27 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/a3/2f90adf7ee0f14ae300e49cdf8779507746c27 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/a3/2f90adf7ee0f14ae300e49cdf8779507746c27 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/ad/27dd25048bff07da92d2d9d829e4dd75472da4 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/ad/27dd25048bff07da92d2d9d829e4dd75472da4 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/ad/27dd25048bff07da92d2d9d829e4dd75472da4 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/ad/27dd25048bff07da92d2d9d829e4dd75472da4 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/ad/e030587c8ae5d240ad7669bff9030b24bd6385 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/ad/e030587c8ae5d240ad7669bff9030b24bd6385 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/ad/e030587c8ae5d240ad7669bff9030b24bd6385 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/ad/e030587c8ae5d240ad7669bff9030b24bd6385 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/ce/024fc694fd464cfb5b43cb7702f0bd7345d882 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/ce/024fc694fd464cfb5b43cb7702f0bd7345d882 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/ce/024fc694fd464cfb5b43cb7702f0bd7345d882 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/ce/024fc694fd464cfb5b43cb7702f0bd7345d882 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/d0/ec73019f9c5e426c9b37fa58757855367580a5 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/d0/ec73019f9c5e426c9b37fa58757855367580a5 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/d0/ec73019f9c5e426c9b37fa58757855367580a5 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/d0/ec73019f9c5e426c9b37fa58757855367580a5 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/d3/4fc4a9c0c675a5cb11d848e5afef4c89160dc0 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/d3/4fc4a9c0c675a5cb11d848e5afef4c89160dc0 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/d3/4fc4a9c0c675a5cb11d848e5afef4c89160dc0 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/d3/4fc4a9c0c675a5cb11d848e5afef4c89160dc0 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/e3/31050363ceb0b12d9d042e37879d892d867ea0 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/e3/31050363ceb0b12d9d042e37879d892d867ea0 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/e3/31050363ceb0b12d9d042e37879d892d867ea0 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/e3/31050363ceb0b12d9d042e37879d892d867ea0 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/e4/74bc2d1712ed5fdf14fb7223392f1b0dcc8d37 b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/e4/74bc2d1712ed5fdf14fb7223392f1b0dcc8d37 similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/e4/74bc2d1712ed5fdf14fb7223392f1b0dcc8d37 rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/e4/74bc2d1712ed5fdf14fb7223392f1b0dcc8d37 diff --git a/test/integration/patchBuilding2/expected/.git_keep/objects/f3/c8a074e65b02d1bc364caf0b4c1516abf9eb5a b/test/integration/patchBuilding2/expected/repo/.git_keep/objects/f3/c8a074e65b02d1bc364caf0b4c1516abf9eb5a similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/objects/f3/c8a074e65b02d1bc364caf0b4c1516abf9eb5a rename to test/integration/patchBuilding2/expected/repo/.git_keep/objects/f3/c8a074e65b02d1bc364caf0b4c1516abf9eb5a diff --git a/test/integration/patchBuilding2/expected/.git_keep/refs/heads/master b/test/integration/patchBuilding2/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/refs/heads/master rename to test/integration/patchBuilding2/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/patchBuilding2/expected/.git_keep/refs/stash b/test/integration/patchBuilding2/expected/repo/.git_keep/refs/stash similarity index 100% rename from test/integration/patchBuilding2/expected/.git_keep/refs/stash rename to test/integration/patchBuilding2/expected/repo/.git_keep/refs/stash diff --git a/test/integration/pull/expected/myfile1 b/test/integration/patchBuilding2/expected/repo/myfile1 similarity index 100% rename from test/integration/pull/expected/myfile1 rename to test/integration/patchBuilding2/expected/repo/myfile1 diff --git a/test/integration/patchBuilding2/expected/myfile2 b/test/integration/patchBuilding2/expected/repo/myfile2 similarity index 100% rename from test/integration/patchBuilding2/expected/myfile2 rename to test/integration/patchBuilding2/expected/repo/myfile2 diff --git a/test/integration/patchBuilding2/expected/myfile3 b/test/integration/patchBuilding2/expected/repo/myfile3 similarity index 100% rename from test/integration/patchBuilding2/expected/myfile3 rename to test/integration/patchBuilding2/expected/repo/myfile3 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/COMMIT_EDITMSG b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/FETCH_HEAD b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/FETCH_HEAD rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/pull/expected/.git_keep/HEAD b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/pull/expected/.git_keep/HEAD rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/HEAD diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/config b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/config similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/config rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/config diff --git a/test/integration/pull/expected/.git_keep/description b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/description similarity index 100% rename from test/integration/pull/expected/.git_keep/description rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/description diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/index b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/index similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/index rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/index diff --git a/test/integration/pull/expected/.git_keep/info/exclude b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/pull/expected/.git_keep/info/exclude rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/info/exclude diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/logs/HEAD b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/logs/HEAD rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/logs/refs/heads/master b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/logs/refs/heads/master rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/pull/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/pull/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/41/05b6da4ccc191a4abd24b1ffac6a2031534c0b b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/41/05b6da4ccc191a4abd24b1ffac6a2031534c0b similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/objects/41/05b6da4ccc191a4abd24b1ffac6a2031534c0b rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/41/05b6da4ccc191a4abd24b1ffac6a2031534c0b diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/44/eb4bd0e7419049a8e4176945786c20dae60d7c b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/44/eb4bd0e7419049a8e4176945786c20dae60d7c similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/objects/44/eb4bd0e7419049a8e4176945786c20dae60d7c rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/44/eb4bd0e7419049a8e4176945786c20dae60d7c diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/68/bbd52379d849022495dcfd11b13f2fb3103d37 b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/68/bbd52379d849022495dcfd11b13f2fb3103d37 similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/objects/68/bbd52379d849022495dcfd11b13f2fb3103d37 rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/68/bbd52379d849022495dcfd11b13f2fb3103d37 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/70/28eaec19b2723b62690974057c92ba7d8c1b11 b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/70/28eaec19b2723b62690974057c92ba7d8c1b11 similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/objects/70/28eaec19b2723b62690974057c92ba7d8c1b11 rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/70/28eaec19b2723b62690974057c92ba7d8c1b11 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/98/1651deb012f8e684dd306c1f5bf8edd5c3db67 b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/98/1651deb012f8e684dd306c1f5bf8edd5c3db67 similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/objects/98/1651deb012f8e684dd306c1f5bf8edd5c3db67 rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/98/1651deb012f8e684dd306c1f5bf8edd5c3db67 diff --git a/test/integration/pull/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/pull/expected/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/objects/cf/149a94a18c990b2c5cdd0cf15ec4880f51c8b0 b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/cf/149a94a18c990b2c5cdd0cf15ec4880f51c8b0 similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/objects/cf/149a94a18c990b2c5cdd0cf15ec4880f51c8b0 rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/cf/149a94a18c990b2c5cdd0cf15ec4880f51c8b0 diff --git a/test/integration/pull/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 similarity index 100% rename from test/integration/pull/expected/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 diff --git a/test/integration/pull/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/pull/expected/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/patchBuildingToggleAll/expected/.git_keep/refs/heads/master b/test/integration/patchBuildingToggleAll/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/.git_keep/refs/heads/master rename to test/integration/patchBuildingToggleAll/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/patchBuildingToggleAll/expected/one/two/three/file3 b/test/integration/patchBuildingToggleAll/expected/repo/one/two/three/file3 similarity index 100% rename from test/integration/patchBuildingToggleAll/expected/one/two/three/file3 rename to test/integration/patchBuildingToggleAll/expected/repo/one/two/three/file3 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/COMMIT_EDITMSG b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/COMMIT_EDITMSG similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/COMMIT_EDITMSG rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/COMMIT_EDITMSG diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/FETCH_HEAD b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/FETCH_HEAD similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/FETCH_HEAD rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/FETCH_HEAD diff --git a/test/integration/pull/expected_remote/HEAD b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/HEAD similarity index 100% rename from test/integration/pull/expected_remote/HEAD rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/HEAD diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/config b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/config similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/config rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/config diff --git a/test/integration/pull/expected_remote/description b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/description similarity index 100% rename from test/integration/pull/expected_remote/description rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/description diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/index b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/index similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/index rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/index diff --git a/test/integration/pull/expected_remote/info/exclude b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/pull/expected_remote/info/exclude rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/info/exclude diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/logs/HEAD b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/logs/HEAD similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/logs/HEAD rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/logs/HEAD diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/logs/refs/heads/master b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/logs/refs/heads/master similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/logs/refs/heads/master rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/logs/refs/heads/master diff --git a/test/integration/pull/expected_remote/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/pull/expected_remote/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/41/05b6da4ccc191a4abd24b1ffac6a2031534c0b b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/41/05b6da4ccc191a4abd24b1ffac6a2031534c0b similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/41/05b6da4ccc191a4abd24b1ffac6a2031534c0b rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/41/05b6da4ccc191a4abd24b1ffac6a2031534c0b diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/43/9a6f2a3c627cd37ba1c5eda6a49c26a85ad610 b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/43/9a6f2a3c627cd37ba1c5eda6a49c26a85ad610 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/43/9a6f2a3c627cd37ba1c5eda6a49c26a85ad610 rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/43/9a6f2a3c627cd37ba1c5eda6a49c26a85ad610 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/44/eb4bd0e7419049a8e4176945786c20dae60d7c b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/44/eb4bd0e7419049a8e4176945786c20dae60d7c similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/44/eb4bd0e7419049a8e4176945786c20dae60d7c rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/44/eb4bd0e7419049a8e4176945786c20dae60d7c diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/4f/346f1ad5ba2917da2109e2eaa2f2dfbb86f10f diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/54/57a1e78421c0c1bf9eb3bcc89f6c0996b9f89e b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/54/57a1e78421c0c1bf9eb3bcc89f6c0996b9f89e similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/54/57a1e78421c0c1bf9eb3bcc89f6c0996b9f89e rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/54/57a1e78421c0c1bf9eb3bcc89f6c0996b9f89e diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/5a/abb4aaf3d6cc113fec7f7a3c0a880988085c23 b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/5a/abb4aaf3d6cc113fec7f7a3c0a880988085c23 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/5a/abb4aaf3d6cc113fec7f7a3c0a880988085c23 rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/5a/abb4aaf3d6cc113fec7f7a3c0a880988085c23 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/68/bbd52379d849022495dcfd11b13f2fb3103d37 b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/68/bbd52379d849022495dcfd11b13f2fb3103d37 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/68/bbd52379d849022495dcfd11b13f2fb3103d37 rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/68/bbd52379d849022495dcfd11b13f2fb3103d37 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/83/90c32b5e687b97e242da46498b574ace0e1eb5 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/88/981dbb0664057b766113679127284f69f4fb69 b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/88/981dbb0664057b766113679127284f69f4fb69 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/88/981dbb0664057b766113679127284f69f4fb69 rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/88/981dbb0664057b766113679127284f69f4fb69 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/98/1651deb012f8e684dd306c1f5bf8edd5c3db67 b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/98/1651deb012f8e684dd306c1f5bf8edd5c3db67 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/98/1651deb012f8e684dd306c1f5bf8edd5c3db67 rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/98/1651deb012f8e684dd306c1f5bf8edd5c3db67 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/9f/aac09750995930a5d55eccf91ad6f802e8c66b b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/9f/aac09750995930a5d55eccf91ad6f802e8c66b similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/9f/aac09750995930a5d55eccf91ad6f802e8c66b rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/9f/aac09750995930a5d55eccf91ad6f802e8c66b diff --git a/test/integration/pull/expected_remote/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 similarity index 100% rename from test/integration/pull/expected_remote/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/b5/e8fb99b011265d28065d0d545ff6b0245b1fa1 b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/b5/e8fb99b011265d28065d0d545ff6b0245b1fa1 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/b5/e8fb99b011265d28065d0d545ff6b0245b1fa1 rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/b5/e8fb99b011265d28065d0d545ff6b0245b1fa1 diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/c1/7dc7400fbb649385064c27544ba1e6c4751566 b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/c1/7dc7400fbb649385064c27544ba1e6c4751566 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/objects/c1/7dc7400fbb649385064c27544ba1e6c4751566 rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/c1/7dc7400fbb649385064c27544ba1e6c4751566 diff --git a/test/integration/pull/expected_remote/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 similarity index 100% rename from test/integration/pull/expected_remote/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 diff --git a/test/integration/pull/expected_remote/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b similarity index 100% rename from test/integration/pull/expected_remote/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b diff --git a/test/integration/patchBuildingWithFiletree/expected/.git_keep/refs/heads/master b/test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/refs/heads/master similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/.git_keep/refs/heads/master rename to test/integration/patchBuildingWithFiletree/expected/repo/.git_keep/refs/heads/master diff --git a/test/integration/patchBuildingWithFiletree/expected/one/two/file2 b/test/integration/patchBuildingWithFiletree/expected/repo/one/two/file2 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/one/two/file2 rename to test/integration/patchBuildingWithFiletree/expected/repo/one/two/file2 diff --git a/test/integration/patchBuildingWithFiletree/expected/one/two/three/file3 b/test/integration/patchBuildingWithFiletree/expected/repo/one/two/three/file3 similarity index 100% rename from test/integration/patchBuildingWithFiletree/expected/one/two/three/file3 rename to test/integration/patchBuildingWithFiletree/expected/repo/one/two/three/file3 diff --git a/test/integration/pull/expected/.git_keep/FETCH_HEAD b/test/integration/pull/expected/.git_keep/FETCH_HEAD deleted file mode 100644 index d13b7c7d7..000000000 --- a/test/integration/pull/expected/.git_keep/FETCH_HEAD +++ /dev/null @@ -1 +0,0 @@ -6ad6c42187d356f4eab4f004cca17863746adec1 branch 'master' of ../actual_remote diff --git a/test/integration/pull/expected/.git_keep/ORIG_HEAD b/test/integration/pull/expected/.git_keep/ORIG_HEAD deleted file mode 100644 index 22c16cf39..000000000 --- a/test/integration/pull/expected/.git_keep/ORIG_HEAD +++ /dev/null @@ -1 +0,0 @@ -0c0f210a4e5ff3b58e4190501c2b755695f439fa diff --git a/test/integration/pull/expected/.git_keep/index b/test/integration/pull/expected/.git_keep/index deleted file mode 100644 index 97b14255604e7488b225a76c9b4f1d3073e16842..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 353 zcmZ?q402{*U|<4bmc$#ZX5x(p-oa=_1_oBfZ|s*D7#f!_Ffe`vsu2NVwxxR>|5Z)B z@g*WOiYMRcLV#CG_f-b=+{(1foK!=g0 1634896904 +1100 commit (initial): myfile1 -003527daa0801470151d8f93140a02fc306fea00 0c0f210a4e5ff3b58e4190501c2b755695f439fa CI 1634896904 +1100 commit: myfile2 -0c0f210a4e5ff3b58e4190501c2b755695f439fa 336826e035e431ac94eca7f3cb6dd3fb072f7a5a CI 1634896904 +1100 commit: myfile3 -336826e035e431ac94eca7f3cb6dd3fb072f7a5a 6ad6c42187d356f4eab4f004cca17863746adec1 CI 1634896904 +1100 commit: myfile4 -6ad6c42187d356f4eab4f004cca17863746adec1 0c0f210a4e5ff3b58e4190501c2b755695f439fa CI 1634896904 +1100 reset: moving to head^^ -0c0f210a4e5ff3b58e4190501c2b755695f439fa 6ad6c42187d356f4eab4f004cca17863746adec1 CI 1634896905 +1100 pull --no-edit: Fast-forward diff --git a/test/integration/pull/expected/.git_keep/logs/refs/heads/master b/test/integration/pull/expected/.git_keep/logs/refs/heads/master deleted file mode 100644 index f15401d8d..000000000 --- a/test/integration/pull/expected/.git_keep/logs/refs/heads/master +++ /dev/null @@ -1,6 +0,0 @@ -0000000000000000000000000000000000000000 003527daa0801470151d8f93140a02fc306fea00 CI 1634896904 +1100 commit (initial): myfile1 -003527daa0801470151d8f93140a02fc306fea00 0c0f210a4e5ff3b58e4190501c2b755695f439fa CI 1634896904 +1100 commit: myfile2 -0c0f210a4e5ff3b58e4190501c2b755695f439fa 336826e035e431ac94eca7f3cb6dd3fb072f7a5a CI 1634896904 +1100 commit: myfile3 -336826e035e431ac94eca7f3cb6dd3fb072f7a5a 6ad6c42187d356f4eab4f004cca17863746adec1 CI 1634896904 +1100 commit: myfile4 -6ad6c42187d356f4eab4f004cca17863746adec1 0c0f210a4e5ff3b58e4190501c2b755695f439fa CI 1634896904 +1100 reset: moving to head^^ -0c0f210a4e5ff3b58e4190501c2b755695f439fa 6ad6c42187d356f4eab4f004cca17863746adec1 CI 1634896905 +1100 pull --no-edit: Fast-forward diff --git a/test/integration/pull/expected/.git_keep/logs/refs/remotes/origin/master b/test/integration/pull/expected/.git_keep/logs/refs/remotes/origin/master deleted file mode 100644 index b254fcd0d..000000000 --- a/test/integration/pull/expected/.git_keep/logs/refs/remotes/origin/master +++ /dev/null @@ -1 +0,0 @@ -0000000000000000000000000000000000000000 6ad6c42187d356f4eab4f004cca17863746adec1 CI 1634896904 +1100 fetch origin: storing head diff --git a/test/integration/pull/expected/.git_keep/objects/00/3527daa0801470151d8f93140a02fc306fea00 b/test/integration/pull/expected/.git_keep/objects/00/3527daa0801470151d8f93140a02fc306fea00 deleted file mode 100644 index 0ed3c76d8..000000000 --- a/test/integration/pull/expected/.git_keep/objects/00/3527daa0801470151d8f93140a02fc306fea00 +++ /dev/null @@ -1,2 +0,0 @@ -x嵧A -0@旬s娰蕦NJ\y寴Lㄠ")捶#t鹹餝5[衰愍*ー攅3硳楈⿱T^赶%玮Ы廼斫-U{I>H@+;9i'w+毽4, \ No newline at end of file diff --git a/test/integration/pull/expected/.git_keep/objects/0c/0f210a4e5ff3b58e4190501c2b755695f439fa b/test/integration/pull/expected/.git_keep/objects/0c/0f210a4e5ff3b58e4190501c2b755695f439fa deleted file mode 100644 index a89fa981c845c83f34edbf8b4a788ba7dfd19d23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmV;F0Biqv0gaA93WG2Z0DI0WaxawKB(4caDR}Z3tJ$T3sUj(~zi*z<>o730?4_*L zVhWdfidgP_K<<)4&LWy92_>D$Q*=bxxf#?2By;d7uWA8&=laYH5is L*{_2Kb&eBNqZ zo5kc#?GUj;!I3xyT+|V1cBGmYB#pqa5Dx77vY0&|@@f_sbU?^XyebtR#bE*u$U_;u z56SmV(rog(J+{M6v%OC9T|T+)Pr2|`Zx#c&m_h<)&xin~(|)SSpSr1EU7tec2l=x) Eb1;WTR{#J2 diff --git a/test/integration/pull/expected/.git_keep/objects/6a/d6c42187d356f4eab4f004cca17863746adec1 b/test/integration/pull/expected/.git_keep/objects/6a/d6c42187d356f4eab4f004cca17863746adec1 deleted file mode 100644 index 335077711..000000000 --- a/test/integration/pull/expected/.git_keep/objects/6a/d6c42187d356f4eab4f004cca17863746adec1 +++ /dev/null @@ -1,2 +0,0 @@ -x嵨A -0@Q9E鰝d2揑"BW=4漙霖R"桧軂掴椀单[萾昊!#Lh鎼kdO妱f揮_"r颥倲LZ$V,3稚E_1蝾弖访hx讖错捕FJ櫝#{p鯓犏'7韀棫掶翕90 \ No newline at end of file diff --git a/test/integration/pull/expected/.git_keep/refs/heads/master b/test/integration/pull/expected/.git_keep/refs/heads/master deleted file mode 100644 index 120f0043b..000000000 --- a/test/integration/pull/expected/.git_keep/refs/heads/master +++ /dev/null @@ -1 +0,0 @@ -6ad6c42187d356f4eab4f004cca17863746adec1 diff --git a/test/integration/pull/expected/.git_keep/refs/remotes/origin/master b/test/integration/pull/expected/.git_keep/refs/remotes/origin/master deleted file mode 100644 index 120f0043b..000000000 --- a/test/integration/pull/expected/.git_keep/refs/remotes/origin/master +++ /dev/null @@ -1 +0,0 @@ -6ad6c42187d356f4eab4f004cca17863746adec1 diff --git a/test/integration/pullAndSetUpstream/expected/.git_keep/HEAD b/test/integration/pull/expected/origin/HEAD similarity index 100% rename from test/integration/pullAndSetUpstream/expected/.git_keep/HEAD rename to test/integration/pull/expected/origin/HEAD diff --git a/test/integration/push/expected_remote/config b/test/integration/pull/expected/origin/config similarity index 80% rename from test/integration/push/expected_remote/config rename to test/integration/pull/expected/origin/config index 26275994b..e92bfb417 100644 --- a/test/integration/push/expected_remote/config +++ b/test/integration/pull/expected/origin/config @@ -5,4 +5,4 @@ ignorecase = true precomposeunicode = true [remote "origin"] - url = /Users/jesseduffieldduffield/go/src/github.com/jesseduffield/lazygit/test/integration/push/./actual + url = /Users/jesseduffieldduffield/go/src/github.com/jesseduffield/lazygit/test/integration/pull/actual/./repo diff --git a/test/integration/pullAndSetUpstream/expected/.git_keep/description b/test/integration/pull/expected/origin/description similarity index 100% rename from test/integration/pullAndSetUpstream/expected/.git_keep/description rename to test/integration/pull/expected/origin/description diff --git a/test/integration/pullAndSetUpstream/expected/.git_keep/info/exclude b/test/integration/pull/expected/origin/info/exclude similarity index 100% rename from test/integration/pullAndSetUpstream/expected/.git_keep/info/exclude rename to test/integration/pull/expected/origin/info/exclude diff --git a/test/integration/pullAndSetUpstream/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 b/test/integration/pull/expected/origin/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 similarity index 100% rename from test/integration/pullAndSetUpstream/expected/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 rename to test/integration/pull/expected/origin/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 diff --git a/test/integration/pullAndSetUpstream/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 b/test/integration/pull/expected/origin/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 similarity index 100% rename from test/integration/pullAndSetUpstream/expected/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 rename to test/integration/pull/expected/origin/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 diff --git a/test/integration/pullAndSetUpstream/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/pull/expected/origin/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce similarity index 100% rename from test/integration/pullAndSetUpstream/expected/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce rename to test/integration/pull/expected/origin/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce diff --git a/test/integration/pull/expected/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 b/test/integration/pull/expected/origin/objects/2f/6174050380438f14b16658a356e762435ca591 similarity index 100% rename from test/integration/pull/expected/.git_keep/objects/2f/6174050380438f14b16658a356e762435ca591 rename to test/integration/pull/expected/origin/objects/2f/6174050380438f14b16658a356e762435ca591 diff --git a/test/integration/pull/expected/origin/objects/3e/a0c134bed03d0a2cb7eeaff586af277d137129 b/test/integration/pull/expected/origin/objects/3e/a0c134bed03d0a2cb7eeaff586af277d137129 new file mode 100644 index 000000000..a56e97735 --- /dev/null +++ b/test/integration/pull/expected/origin/objects/3e/a0c134bed03d0a2cb7eeaff586af277d137129 @@ -0,0 +1,2 @@ +x嵧A +0@旬s娰J茖J\y寴Lㄠ")捶#t鹹餝5[ 癀愍鄷S駪椺畳叧`碢萀%s裼^u噄喦4忷嶖摁柂=$恜鄪杞;9i'w+毽49, \ No newline at end of file diff --git a/test/integration/pull/expected/origin/objects/7b/9a91f4ecba02fd55dbf3f372bc3faee3897939 b/test/integration/pull/expected/origin/objects/7b/9a91f4ecba02fd55dbf3f372bc3faee3897939 new file mode 100644 index 0000000000000000000000000000000000000000..a03a86b26706a784656de159ea30b6edf8bef69d GIT binary patch literal 150 zcmV;H0BQet0gcW<3c@fDKvCB@MfQSZX3|LmB0^U^#w3|w!PrtF= @qnCLWQwASPGQ1Dj2DeRWGJE(7_b#ZhsBIR#azbr@MH zhERY4U^MdXk9D`xY_HRN*N?RAsh7OAn+5hG`H=^*X8`BSQIDyve{$2lb$Ke99}$r{ EvBB#|N&o-= literal 0 HcmV?d00001 diff --git a/test/integration/pull/expected/origin/objects/97/bf06c598032ab5ad0faf744c91545071f3cb38 b/test/integration/pull/expected/origin/objects/97/bf06c598032ab5ad0faf744c91545071f3cb38 new file mode 100644 index 0000000000000000000000000000000000000000..6921642c3c8e5631e76b2bb54f284dbf7d4d053b GIT binary patch literal 148 zcmV;F0Biqv0gaAJ3c@fH0A1%4*$a}F_h|$Xp{pJvpBF4Nwv-5ZdwT@8Gqaeywl;SQ zS331w)%q$hkYk6z5rztsK!ig?79GSBa*lijv&CIs-BzcGV&LSZGL#&$M@2|!s7!EJ zU!eHnOnmp}y4!KGw{d#tC$??TOJ3XEf>1yT!f4L`&Y6QAQ(gbeP5ah)Q8GUhnmJ9b C) |5Z)B z@g*WOiYMRcLV#CG_f-b=+{(1foK!=g0+4 (apJJa`Zv?Kci!1uhL(fw)m11d+T)w%p4P-IUzx=u0TqX!9>A; uOFyxMmAS#WUu0ui#Nx2$NzO4#Cw{C|%XeE)r)k2l%l95{DTCY9-`N1soOaOw literal 0 HcmV?d00001 diff --git a/test/integration/pullAndSetUpstream/expected_remote/info/exclude b/test/integration/pull/expected/repo/.git_keep/info/exclude similarity index 100% rename from test/integration/pullAndSetUpstream/expected_remote/info/exclude rename to test/integration/pull/expected/repo/.git_keep/info/exclude diff --git a/test/integration/pull/expected/repo/.git_keep/logs/HEAD b/test/integration/pull/expected/repo/.git_keep/logs/HEAD new file mode 100644 index 000000000..f67583b72 --- /dev/null +++ b/test/integration/pull/expected/repo/.git_keep/logs/HEAD @@ -0,0 +1,7 @@ +0000000000000000000000000000000000000000 3ea0c134bed03d0a2cb7eeaff586af277d137129 CI 1648348653 +1100 commit (initial): myfile1 +3ea0c134bed03d0a2cb7eeaff586af277d137129 7b9a91f4ecba02fd55dbf3f372bc3faee3897939 CI 1648348653 +1100 commit: myfile2 +7b9a91f4ecba02fd55dbf3f372bc3faee3897939 f0eb4a85b26f51dc8c23e31bb7f541f0e2d1d2d0 CI 1648348653 +1100 commit: myfile3 +f0eb4a85b26f51dc8c23e31bb7f541f0e2d1d2d0 97bf06c598032ab5ad0faf744c91545071f3cb38 CI 1648348653 +1100 commit: myfile4 +97bf06c598032ab5ad0faf744c91545071f3cb38 7b9a91f4ecba02fd55dbf3f372bc3faee3897939 CI 1648348653 +1100 reset: moving to HEAD~2 +7b9a91f4ecba02fd55dbf3f372bc3faee3897939 97bf06c598032ab5ad0faf744c91545071f3cb38 CI 1648348654 +1100 rebase -i (start): checkout 97bf06c598032ab5ad0faf744c91545071f3cb38 +97bf06c598032ab5ad0faf744c91545071f3cb38 97bf06c598032ab5ad0faf744c91545071f3cb38 CI