diff options
33 files changed, 871 insertions, 212 deletions
@@ -22,7 +22,7 @@ require ( github.com/integrii/flaggy v1.4.0 github.com/iriri/minimal/gitignore v0.3.2 // indirect github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 - github.com/jesseduffield/gocui v0.3.1-0.20211017220056-b2fc03c74a6f + github.com/jesseduffield/gocui v0.3.1-0.20211024041248-681a61c53ed0 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 @@ -43,7 +43,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-20211015200801-69063c4bb744 // indirect + golang.org/x/sys v0.0.0-20211023085530-d6a326fbbf70 // 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 @@ -84,6 +84,8 @@ github.com/jesseduffield/gocui v0.3.1-0.20211017091015-8bf4a4666b77 h1:MQUxSxVBT github.com/jesseduffield/gocui v0.3.1-0.20211017091015-8bf4a4666b77/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU= github.com/jesseduffield/gocui v0.3.1-0.20211017220056-b2fc03c74a6f h1:JHrb78pj+gYC3KiJKL1WW6lYzlatBIF46oREn68plTM= github.com/jesseduffield/gocui v0.3.1-0.20211017220056-b2fc03c74a6f/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU= +github.com/jesseduffield/gocui v0.3.1-0.20211024041248-681a61c53ed0 h1:To4mMbu6oQpbbyHa4WtMTc/DHa9dqiRWZpDLMNK+Hdk= +github.com/jesseduffield/gocui v0.3.1-0.20211024041248-681a61c53ed0/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU= github.com/jesseduffield/minimal v0.0.0-20211018110810-9cde264e6b1e h1:WZc73tBVMMhcO6zXyZBItLEF4jgBpBH0lFCZzDgrjDg= 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= @@ -195,6 +197,8 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211015200801-69063c4bb744 h1:KzbpndAYEM+4oHRp9JmB2ewj0NHHxO3Z0g7Gus2O1kk= golang.org/x/sys v0.0.0-20211015200801-69063c4bb744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211023085530-d6a326fbbf70 h1:SeSEfdIxyvwGJliREIJhRPPXvW6sDlLT+UQ3B0hD0NA= +golang.org/x/sys v0.0.0-20211023085530-d6a326fbbf70/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/pkg/app/app.go b/pkg/app/app.go index bb7485cca..f24af6e58 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -127,7 +127,13 @@ func NewApp(config config.AppConfigurer, filterPath string) (*App, error) { return app, err } - app.GitCommand, err = commands.NewGitCommand(app.Log, app.OSCommand, app.Tr, app.Config, git_config.NewStdCachedGitConfig(app.Log)) + app.GitCommand, err = commands.NewGitCommand( + app.Log, + app.OSCommand, + app.Tr, + app.Config, + git_config.NewStdCachedGitConfig(app.Log), + ) if err != nil { return app, err } diff --git a/pkg/commands/dummies.go b/pkg/commands/dummies.go index a8178385d..ba052fe9b 100644 --- a/pkg/commands/dummies.go +++ b/pkg/commands/dummies.go @@ -1,6 +1,9 @@ package commands import ( + "io" + "io/ioutil" + "github.com/jesseduffield/lazygit/pkg/commands/git_config" "github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/config" @@ -17,10 +20,11 @@ func NewDummyGitCommand() *GitCommand { func NewDummyGitCommandWithOSCommand(osCommand *oscommands.OSCommand) *GitCommand { newAppConfig := config.NewDummyAppConfig() return &GitCommand{ - Log: utils.NewDummyLog(), - OSCommand: osCommand, - Tr: i18n.NewTranslationSet(utils.NewDummyLog(), newAppConfig.GetUserConfig().Gui.Language), - Config: newAppConfig, - GitConfig: git_config.NewFakeGitConfig(map[string]string{}), + Log: utils.NewDummyLog(), + OSCommand: osCommand, + Tr: i18n.NewTranslationSet(utils.NewDummyLog(), newAppConfig.GetUserConfig().Gui.Language), + Config: newAppConfig, + GitConfig: git_config.NewFakeGitConfig(map[string]string{}), + GetCmdWriter: func() io.Writer { return ioutil.Discard }, } } diff --git a/pkg/commands/git.go b/pkg/commands/git.go index a1a925de7..8750ecf51 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -1,6 +1,7 @@ package commands import ( + "io" "io/ioutil" "os" "path/filepath" @@ -40,6 +41,11 @@ type GitCommand struct { // Push to current determines whether the user has configured to push to the remote branch of the same name as the current or not PushToCurrent bool + + // this is just a view that we write to when running certain commands. + // Coincidentally at the moment it's the same view that OnRunCommand logs to + // but that need not always be the case. + GetCmdWriter func() io.Writer } // NewGitCommand it runs git commands @@ -77,6 +83,7 @@ func NewGitCommand( DotGitDir: dotGitDir, PushToCurrent: pushToCurrent, GitConfig: gitConfig, + GetCmdWriter: func() io.Writer { return ioutil.Discard }, } gitCommand.PatchManager = patch.NewPatchManager(log, gitCommand.ApplyPatch, gitCommand.ShowFileDiff) diff --git a/pkg/commands/oscommands/exec_live.go b/pkg/commands/oscommands/exec_live.go new file mode 100644 index 000000000..6ca70a5ec --- /dev/null +++ b/pkg/commands/oscommands/exec_live.go @@ -0,0 +1,153 @@ +package oscommands + +import ( + "bufio" + "bytes" + "io" + "os/exec" + "regexp" + "strings" + "unicode/utf8" + + "github.com/go-errors/errors" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +// DetectUnamePass detect a username / password / passphrase question in a command +// promptUserForCredential is a function that gets executed when this function detect you need to fillin a password or passphrase +// The promptUserForCredential argument will be "username", "password" or "passphrase" and expects the user's password/passphrase or username back +func (c *OSCommand) DetectUnamePass(cmdObj ICmdObj, writer io.Writer, promptUserForCredential func(string) string) error { + ttyText := "" + errMessage := c.RunCommandWithOutputLive(cmdObj, writer, func(word string) string { + ttyText = ttyText + " " + word + + prompts := map[string]string{ + `.+'s password:`: "password", + `Password\s*for\s*'.+':`: "password", + `Username\s*for\s*'.+':`: "username", + `Enter\s*passphrase\s*for\s*key\s*'.+':`: "passphrase", + } + + for pattern, askFor := range prompts { + if match, _ := regexp.MatchString(pattern, ttyText); match { + ttyText = "" + return promptUserForCredential(askFor) + } + } + + return "" + }) + return errMessage +} + +// Due to a lack of pty support on windows we have RunCommandWithOutputLiveWrapper being defined +// separate for windows and other OS's +func (c *OSCommand) RunCommandWithOutputLive(cmdObj ICmdObj, writer io.Writer, handleOutput func(string) string) error { + return RunCommandWithOutputLiveWrapper(c, cmdObj, writer, handleOutput) +} + +type cmdHandler struct { + stdoutPipe io.Reader + stdinPipe io.Writer + close func() error +} + +// RunCommandWithOutputLiveAux runs a command and return every word that gets written in stdout +// Output is a function that executes by every word that gets read by bufio +// As return of output you need to give a string that will be written to stdin +// NOTE: If the return data is empty it won't write anything to stdin +func RunCommandWithOutputLiveAux( + c *OSCommand, + cmdObj ICmdObj, + writer io.Writer, + // handleOutput takes a word from stdout and returns a string to be written to stdin. + // See DetectUnamePass above for how this is used to check for a username/password request + handleOutput func(string) string, + startCmd func(cmd *exec.Cmd) (*cmdHandler, error), +) error { + c.Log.WithField("command", cmdObj.ToString()).Info("RunCommand") + c.LogCommand(cmdObj.ToString(), true) + cmd := cmdObj.AddEnvVars("LANG=en_US.UTF-8", "LC_ALL=en_US.UTF-8").GetCmd() + + var stderr bytes.Buffer + cmd.Stderr = io.MultiWriter(writer, &stderr) + + handler, err := startCmd(cmd) + if err != nil { + return err + } + + defer func() { + if closeErr := handler.close(); closeErr != nil { + c.Log.Error(closeErr) + } + }() + + tr := io.TeeReader(handler.stdoutPipe, writer) + + go utils.Safe(func() { + scanner := bufio.NewScanner(tr) + scanner.Split(scanWordsWithNewLines) + for scanner.Scan() { + text := scanner.Text() + output := strings.Trim(text, " ") + toInput := handleOutput(output) + if toInput != "" { + _, _ = handler.stdinPipe.Write([]byte(toInput)) + } + } + }) + + err = cmd.Wait() + if err != nil { + return errors.New(stderr.String()) + } + + return nil +} + +// scanWordsWithNewLines is a copy of bufio.ScanWords but this also captures new lines +// For specific comments about this function take a look at: bufio.ScanWords +func scanWordsWithNewLines(data []byte, atEOF bool) (advance int, token []byte, err error) { + start := 0 + for width := 0; start < len(data); start += width { + var r rune + r, width = utf8.DecodeRune(data[start:]) + if !isSpace(r) { + break + } + } + for width, i := 0, start; i < len(data); i += width { + var r rune + r, width = utf8.DecodeRune(data[i:]) + if isSpace(r) { + return i + width, data[start:i], nil + } + } + if atEOF && len(data) > start { + return len(data), data[start:], nil + } + return start, nil, nil +} + +// isSpace is also copied from the bufio package and has been modified to also captures new lines +// For specific comments about this function take a look at: bufio.isSpace +func isSpace(r rune) bool { + if r <= '\u00FF' { + switch r { + case ' ', '\t', '\v', '\f': + return true + case '\u0085', '\u00A0': + return true + } + return false + } + if '\u2000' <= r && r <= '\u200a' { + return true + } + switch r { + case '\u1680', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000': + return true + } + return false +} diff --git a/pkg/commands/oscommands/exec_live_default.go b/pkg/commands/oscommands/exec_live_default.go index 95d5d09fb..827db9ed3 100644 --- a/pkg/commands/oscommands/exec_live_default.go +++ b/pkg/commands/oscommands/exec_live_default.go @@ -4,95 +4,34 @@ package oscommands import ( - "bufio" - "bytes" - "strings" - "unicode/utf8" - - "github.com/go-errors/errors" - "github.com/jesseduffield/lazygit/pkg/utils" + "io" + "os/exec" "github.com/creack/pty" ) -// RunCommandWithOutputLiveWrapper runs a command and return every word that gets written in stdout -// Output is a function that executes by every word that gets read by bufio -// As return of output you need to give a string that will be written to stdin -// NOTE: If the return data is empty it won't written anything to stdin -func RunCommandWithOutputLiveWrapper(c *OSCommand, cmdObj ICmdObj, output func(string) string) error { - c.Log.WithField("command", cmdObj.ToString()).Info("RunCommand") - c.LogCommand(cmdObj.ToString(), true) - cmd := cmdObj.AddEnvVars("LANG=en_US.UTF-8", "LC_ALL=en_US.UTF-8").GetCmd() - - var stderr bytes.Buffer - cmd.Stderr = &stderr - - ptmx, err := pty.Start(cmd) - - if err != nil { - return err - } - - go utils.Safe(func() { - scanner := bufio.NewScanner(ptmx) - scanner.Split(scanWordsWithNewLines) - for scanner.Scan() { - toOutput := strings.Trim(scanner.Text(), " ") - _, _ = ptmx.WriteString(output(toOutput)) - } - }) - - err = cmd.Wait() - ptmx.Close() - if err != nil { - return errors.New(stderr.String()) - } - - return nil -} - -// scanWordsWithNewLines is a copy of bufio.ScanWords but this also captures new lines -// For specific comments about this function take a look at: bufio.ScanWords -func scanWordsWithNewLines(data []byte, atEOF bool) (advance int, token []byte, err error) { - start := 0 - for width := 0; start < len(data); start += width { - var r rune - r, width = utf8.DecodeRune(data[start:]) - if !isSpace(r) { - break - } - } - for width, i := 0, start; i < len(data); i += width { - var r rune - r, width = utf8.DecodeRune(data[i:]) - if isSpace(r) { - return i + width, data[start:i], nil - } - } - if atEOF && len(data) > start { - return len(data), data[start:], nil - } - return start, nil, nil -} - -// isSpace is also copied from the bufio package and has been modified to also captures new lines -// For specific comments about this function take a look at: bufio.isSpace -func isSpace(r rune) bool { - if r <= '\u00FF' { - switch r { - case ' ', '\t', '\v', '\f': - return true - case '\u0085', '\u00A0': - return true - } - return false - } - if '\u2000' <= r && r <= '\u200a' { - return true - } - switch r { - case '\u1680', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000': - return true - } - return false +func RunCommandWithOutputLiveWrapper( + c *OSCommand, + cmdObj ICmdObj, + writer io.Writer, + output func(string) string, +) error { + return RunCommandWithOutputLiveAux( + c, + cmdObj, + writer, + output, + func(cmd *exec.Cmd) (*cmdHandler, error) { + ptmx, err := pty.Start(cmd) + if err != nil { + return nil, err + } + + return &cmdHandler{ + stdoutPipe: ptmx, + stdinPipe: ptmx, + close: ptmx.Close, + }, nil + }, + ) } diff --git a/pkg/commands/oscommands/exec_live_win.go b/pkg/commands/oscommands/exec_live_win.go index aa17242e3..5b61e478b 100644 --- a/pkg/commands/oscommands/exec_live_win.go +++ b/pkg/commands/oscommands/exec_live_win.go @@ -3,8 +3,61 @@ package oscommands +import ( + "bytes" + "io" + "os/exec" + "sync" +) + +type Buffer struct { + b bytes.Buffer + m sync.Mutex +} + +func (b *Buffer) Read(p []byte) (n int, err error) { + b.m.Lock() + 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() + return b.b.Write(p) +} + // RunCommandWithOutputLiveWrapper runs a command live but because of windows compatibility this command can't be ran there -// TODO: Remove this hack and replace it with a proper way to run commands live on windows -func RunCommandWithOutputLiveWrapper(c *OSCommand, cmdObj ICmdObj, output func(string) string) error { - return c.RunCommand(cmdObj.ToString()) +// TODO: Remove this hack and replace it with a proper way to run commands live on windows. We still have an issue where if a password is requested, the request for a password is written straight to stdout because we can't control the stdout of a subprocess of a subprocess. Keep an eye on https://github.com/creack/pty/pull/109 +func RunCommandWithOutputLiveWrapper( + c *OSCommand, + cmdObj ICmdObj, + writer io.Writer, + output func(string) string, +) error { + return RunCommandWithOutputLiveAux( + c, + cmdObj, + writer, + output, + func(cmd *exec.Cmd) (*cmdHandler, error) { + stdoutReader, stdoutWriter := io.Pipe() + cmd.Stdout = stdoutWriter + + buf := &Buffer{} + cmd.Stdin = buf + + if err := cmd.Start(); err != nil { + return nil, err + } + + // because we don't yet have windows support for a pty, we instead just + // pass our standard stream handlers and because there's no pty to close + // we pass a no-op function for that. + return &cmdHandler{ + stdoutPipe: stdoutReader, + stdinPipe: buf, + close: func() error { return nil }, + }, nil + }, + ) } diff --git a/pkg/commands/oscommands/os.go b/pkg/commands/oscommands/os.go index f0c9525a5..cb41edff4 100644 --- a/pkg/commands/oscommands/os.go +++ b/pkg/commands/oscommands/os.go @@ -7,7 +7,6 @@ import ( "os" "os/exec" "path/filepath" - "regexp" "strings" "sync" @@ -217,38 +216,6 @@ func (c *OSCommand) ShellCommandFromString(commandStr string) *exec.Cmd { return c.ExecutableFromString(shellCommand) } -// RunCommandWithOutputLive runs RunCommandWithOutputLiveWrapper -func (c *OSCommand) RunCommandWithOutputLive(cmdObj ICmdObj, output func(string) string) error { - return RunCommandWithOutputLiveWrapper(c, cmdObj, output) -} - -// DetectUnamePass detect a username / password / passphrase question in a command -// promptUserForCredential is a function that gets executed when this function detect you need to fillin a password or passphrase -// The promptUserForCredential argument will be "username", "password" or "passphrase" and expects the user's password/passphrase or username back -func (c *OSCommand) DetectUnamePass(cmdObj ICmdObj, promptUserForCredential func(string) string) error { - ttyText := "" - errMessage := c.RunCommandWithOutputLive(cmdObj, func(word string) string { - ttyText = ttyText + " " + word - - prompts := map[string]string{ - `.+'s password:`: "password", - `Password\s*for\s*'.+':`: "password", - `Username\s*for\s*'.+':`: "username", - `Enter\s*passphrase\s*for\s*key\s*'.+':`: "passphrase", - } - - for pattern, askFor := range prompts { - if match, _ := regexp.MatchString(pattern, ttyText); match { - ttyText = "" - return promptUserForCredential(askFor) - } - } - - return "" - }) - return errMessage -} - // RunCommand runs a command and just returns the error func (c *OSCommand) RunCommand(formatString string, formatArgs ...interface{}) error { _, err := c.RunCommandWithOutput(formatString, formatArgs...) diff --git a/pkg/commands/remotes.go b/pkg/commands/remotes.go index 0839f9583..11e5dc26f 100644 --- a/pkg/commands/remotes.go +++ b/pkg/commands/remotes.go @@ -2,6 +2,8 @@ package commands import ( "fmt" + + "github.com/jesseduffield/lazygit/pkg/commands/oscommands" ) func (c *GitCommand) AddRemote(name string, url string) error { @@ -23,7 +25,11 @@ func (c *GitCommand) UpdateRemoteUrl(remoteName string, updatedUrl string) error func (c *GitCommand) DeleteRemoteBranch(remoteName string, branchName string, promptUserForCredential func(string) string) error { command := fmt.Sprintf("git push %s --delete %s", c.OSCommand.Quote(remoteName), c.OSCommand.Quote(branchName)) cmdObj := c.NewCmdObjFromStr(command) - return c.OSCommand.DetectUnamePass(cmdObj, promptUserForCredential) + return c.DetectUnamePass(cmdObj, promptUserForCredential) +} + +func (c *GitCommand) DetectUnamePass(cmdObj oscommands.ICmdObj, promptUserForCredential func(string) string) error { + return c.OSCommand.DetectUnamePass(cmdObj, c.GetCmdWriter(), promptUserForCredential) } // CheckRemoteBranchExists Returns remote branch diff --git a/pkg/commands/sync.go b/pkg/commands/sync.go index 3f94c5f4e..35f258f4b 100644 --- a/pkg/commands/sync.go +++ b/pkg/commands/sync.go @@ -38,7 +38,7 @@ func (c *GitCommand) Push(opts PushOpts) error { } cmdObj := c.NewCmdObjFromStr(cmdStr) - return c.OSCommand.DetectUnamePass(cmdObj, opts.PromptUserForCredential) + return c.DetectUnamePass(cmdObj, opts.PromptUserForCredential) } type FetchOptions struct { @@ -59,7 +59,7 @@ func (c *GitCommand) Fetch(opts FetchOptions) error { } cmdObj := c.NewCmdObjFromStr(cmdStr) - return c.OSCommand.DetectUnamePass(cmdObj, func(question string) string { + return c.DetectUnamePass(cmdObj, func(question string) string { if opts.PromptUserForCredential != nil { return opts.PromptUserForCredential(question) } @@ -95,17 +95,17 @@ func (c *GitCommand) Pull(opts PullOptions) error { // setting GIT_SEQUENCE_EDITOR to ':' as a way of skipping it, in case the user // has 'pull.rebase = interactive' configured. cmdObj := c.NewCmdObjFromStr(cmdStr).AddEnvVars("GIT_SEQUENCE_EDITOR=:") - return c.OSCommand.DetectUnamePass(cmdObj, opts.PromptUserForCredential) + return c.DetectUnamePass(cmdObj, opts.PromptUserForCredential) } func (c *GitCommand) FastForward(branchName string, remoteName string, remoteBranchName string, promptUserForCredential func(string) string) error { cmdStr := fmt.Sprintf("git fetch %s %s:%s", c.OSCommand.Quote(remoteName), c.OSCommand.Quote(remoteBranchName), c.OSCommand.Quote(branchName)) cmdObj := c.NewCmdObjFromStr(cmdStr) - return c.OSCommand.DetectUnamePass(cmdObj, promptUserForCredential) + return c.DetectUnamePass(cmdObj, promptUserForCredential) } func (c *GitCommand) FetchRemote(remoteName string, promptUserForCredential func(string) string) error { cmdStr := fmt.Sprintf("git fetch %s", c.OSCommand.Quote(remoteName)) cmdObj := c.NewCmdObjFromStr(cmdStr) - return c.OSCommand.DetectUnamePass(cmdObj, promptUserForCredential) + return c.DetectUnamePass(cmdObj, promptUserForCredential) } diff --git a/pkg/commands/tags.go b/pkg/commands/tags.go index af40ae603..9aa327dd3 100644 --- a/pkg/commands/tags.go +++ b/pkg/commands/tags.go @@ -15,5 +15,5 @@ func (c *GitCommand) DeleteTag(tagName string) error { func (c *GitCommand) PushTag(remoteName string, tagName string, promptUserForCredential func(string) string) error { cmdStr := fmt.Sprintf("git push %s %s", c.OSCommand.Quote(remoteName), c.OSCommand.Quote(tagName)) cmdObj := c.NewCmdObjFromStr(cmdStr) - return c.OSCommand.DetectUnamePass(cmdObj, promptUserForCredential) + return c.DetectUnamePass(cmdObj, promptUserForCredential) } diff --git a/pkg/gui/commit_message_panel.go b/pkg/gui/commit_message_panel.go index 7ed9669ab..edc86eff7 100644 --- a/pkg/gui/commit_message_panel.go +++ b/pkg/gui/commit_message_panel.go @@ -22,9 +22,9 @@ func (gui *Gui) handleCommitConfirm() error { cmdStr := gui.GitCommand.CommitCmdStr(message, flags) gui.OnRunCommand(oscommands.NewCmdLogEntry(cmdStr, gui.Tr.Spans.Commit, true)) + _ = gui.returnFromContext() return gui.withGp |