From 9272276247e9e47cc1a44c2be678f0091bf9b468 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 15 Nov 2025 18:15:17 +0100 Subject: [PATCH 1/3] Don't log the GetDiff command This is used for internal purposes and shouldn't pollute the command log. --- pkg/commands/git_commands/diff.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/commands/git_commands/diff.go b/pkg/commands/git_commands/diff.go index 4feeb4d7f..3074e653a 100644 --- a/pkg/commands/git_commands/diff.go +++ b/pkg/commands/git_commands/diff.go @@ -55,7 +55,7 @@ func (self *DiffCommands) GetDiff(staged bool, additionalArgs ...string) (string Dir(self.repoPaths.worktreePath). Arg(additionalArgs...). ToArgv(), - ).RunWithOutput() + ).DontLog().RunWithOutput() } type DiffToolCmdOptions struct { From eb91a43d58ee8988aa76a1d5e172ead84163ba1d Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 15 Nov 2025 18:25:36 +0100 Subject: [PATCH 2/3] Test properties of cmdObj for Push --- pkg/commands/git_commands/sync_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/commands/git_commands/sync_test.go b/pkg/commands/git_commands/sync_test.go index 4254788d8..99f934a16 100644 --- a/pkg/commands/git_commands/sync_test.go +++ b/pkg/commands/git_commands/sync_test.go @@ -100,7 +100,12 @@ func TestSyncPush(t *testing.T) { t.Run(s.testName, func(t *testing.T) { instance := buildSyncCommands(commonDeps{}) task := gocui.NewFakeTask() - s.test(instance.PushCmdObj(task, s.opts)) + cmdObj, err := instance.PushCmdObj(task, s.opts) + if err == nil { + assert.True(t, cmdObj.ShouldLog()) + assert.Equal(t, cmdObj.GetCredentialStrategy(), oscommands.PROMPT) + } + s.test(cmdObj, err) }) } } From f8a48b61fc95b9a7a4afc4d7a28c358439dbf6ff Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 15 Nov 2025 17:47:35 +0100 Subject: [PATCH 3/3] Suppress output from background fetch However, show it when there was an error. This is important for the case that a fork that you have as a remote was deleted, in which case the command log is the only way to get notified about that. --- pkg/commands/git_commands/sync.go | 1 + pkg/commands/git_commands/sync_test.go | 5 +++++ pkg/commands/oscommands/cmd_obj.go | 15 +++++++++++++++ pkg/commands/oscommands/cmd_obj_runner.go | 12 +++++++++++- 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/pkg/commands/git_commands/sync.go b/pkg/commands/git_commands/sync.go index 0f5559a7b..d64a0910c 100644 --- a/pkg/commands/git_commands/sync.go +++ b/pkg/commands/git_commands/sync.go @@ -79,6 +79,7 @@ func (self *SyncCommands) FetchBackgroundCmdObj() *oscommands.CmdObj { cmdObj := self.cmd.New(cmdArgs) cmdObj.DontLog().FailOnCredentialRequest() + cmdObj.SuppressOutputUnlessError() return cmdObj } diff --git a/pkg/commands/git_commands/sync_test.go b/pkg/commands/git_commands/sync_test.go index 99f934a16..fdc44a6b9 100644 --- a/pkg/commands/git_commands/sync_test.go +++ b/pkg/commands/git_commands/sync_test.go @@ -104,6 +104,7 @@ func TestSyncPush(t *testing.T) { if err == nil { assert.True(t, cmdObj.ShouldLog()) assert.Equal(t, cmdObj.GetCredentialStrategy(), oscommands.PROMPT) + assert.False(t, cmdObj.ShouldSuppressOutputUnlessError()) } s.test(cmdObj, err) }) @@ -124,6 +125,7 @@ func TestSyncFetch(t *testing.T) { test: func(cmdObj *oscommands.CmdObj) { assert.True(t, cmdObj.ShouldLog()) assert.Equal(t, cmdObj.GetCredentialStrategy(), oscommands.PROMPT) + assert.False(t, cmdObj.ShouldSuppressOutputUnlessError()) assert.Equal(t, cmdObj.Args(), []string{"git", "fetch", "--no-write-fetch-head"}) }, }, @@ -133,6 +135,7 @@ func TestSyncFetch(t *testing.T) { test: func(cmdObj *oscommands.CmdObj) { assert.True(t, cmdObj.ShouldLog()) assert.Equal(t, cmdObj.GetCredentialStrategy(), oscommands.PROMPT) + assert.False(t, cmdObj.ShouldSuppressOutputUnlessError()) assert.Equal(t, cmdObj.Args(), []string{"git", "fetch", "--all", "--no-write-fetch-head"}) }, }, @@ -162,6 +165,7 @@ func TestSyncFetchBackground(t *testing.T) { test: func(cmdObj *oscommands.CmdObj) { assert.False(t, cmdObj.ShouldLog()) assert.Equal(t, cmdObj.GetCredentialStrategy(), oscommands.FAIL) + assert.True(t, cmdObj.ShouldSuppressOutputUnlessError()) assert.Equal(t, cmdObj.Args(), []string{"git", "fetch", "--no-write-fetch-head"}) }, }, @@ -171,6 +175,7 @@ func TestSyncFetchBackground(t *testing.T) { test: func(cmdObj *oscommands.CmdObj) { assert.False(t, cmdObj.ShouldLog()) assert.Equal(t, cmdObj.GetCredentialStrategy(), oscommands.FAIL) + assert.True(t, cmdObj.ShouldSuppressOutputUnlessError()) assert.Equal(t, cmdObj.Args(), []string{"git", "fetch", "--all", "--no-write-fetch-head"}) }, }, diff --git a/pkg/commands/oscommands/cmd_obj.go b/pkg/commands/oscommands/cmd_obj.go index 96392dcb4..24d2ca511 100644 --- a/pkg/commands/oscommands/cmd_obj.go +++ b/pkg/commands/oscommands/cmd_obj.go @@ -22,6 +22,9 @@ type CmdObj struct { // see StreamOutput() streamOutput bool + // see SuppressOutputUnlessError() + suppressOutputUnlessError bool + // see UsePty() usePty bool @@ -123,6 +126,18 @@ func (self *CmdObj) StreamOutput() *CmdObj { return self } +// when you call this, the streamed output will be suppressed unless there is an error +func (self *CmdObj) SuppressOutputUnlessError() *CmdObj { + self.suppressOutputUnlessError = true + + return self +} + +// returns true if SuppressOutputUnlessError() was called +func (self *CmdObj) ShouldSuppressOutputUnlessError() bool { + return self.suppressOutputUnlessError +} + // returns true if StreamOutput() was called func (self *CmdObj) ShouldStreamOutput() bool { return self.streamOutput diff --git a/pkg/commands/oscommands/cmd_obj_runner.go b/pkg/commands/oscommands/cmd_obj_runner.go index 953937706..b964edce7 100644 --- a/pkg/commands/oscommands/cmd_obj_runner.go +++ b/pkg/commands/oscommands/cmd_obj_runner.go @@ -227,7 +227,13 @@ func (self *cmdObjRunner) runAndStreamAux( cmdObj *CmdObj, onRun func(*cmdHandler, io.Writer), ) error { - cmdWriter := self.guiIO.newCmdWriterFn() + var cmdWriter io.Writer + var combinedOutput bytes.Buffer + if cmdObj.ShouldSuppressOutputUnlessError() { + cmdWriter = &combinedOutput + } else { + cmdWriter = self.guiIO.newCmdWriterFn() + } if cmdObj.ShouldLog() { self.logCmdObj(cmdObj) @@ -267,6 +273,10 @@ func (self *cmdObjRunner) runAndStreamAux( self.log.Infof("%s (%s)", cmdObj.ToString(), time.Since(t)) if err != nil { + if cmdObj.suppressOutputUnlessError { + _, _ = self.guiIO.newCmdWriterFn().Write(combinedOutput.Bytes()) + } + errStr := stderr.String() if errStr != "" { return errors.New(errStr)