From 4820241cafae97f4833f69cda1eefebba37b96b5 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 16 Aug 2026 15:44:36 +0200 Subject: [PATCH 1/7] Remove the common-false-positives and legacy linter exception presets I don't really know what they are for, but they don't trigger any errors. --- .golangci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 5ed7fb32d..e6a2f37ab 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -99,8 +99,6 @@ linters: generated: lax presets: - comments - - common-false-positives - - legacy - std-error-handling paths: - vendor/ From a26899f5ab3016f54a2935c5c4ad2e176fbf6816 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 16 Aug 2026 16:23:26 +0200 Subject: [PATCH 2/7] Fix use of reflect.Ptr Apparently Ptr is a deprecated name; with the new golangci-lint version this would cause inline: Constant reflect.Ptr should be inlined --- pkg/jsonschema/generate.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/jsonschema/generate.go b/pkg/jsonschema/generate.go index dc5045025..cf7596761 100644 --- a/pkg/jsonschema/generate.go +++ b/pkg/jsonschema/generate.go @@ -144,7 +144,7 @@ func setDefaultVals(rootSchema, schema *jsonschema.Schema, defaults any) { t := reflect.TypeOf(defaults) v := reflect.ValueOf(defaults) - if t.Kind() == reflect.Ptr || t.Kind() == reflect.Interface { + if t.Kind() == reflect.Pointer || t.Kind() == reflect.Interface { t = t.Elem() v = v.Elem() } @@ -202,7 +202,7 @@ func isZeroValue(v any) bool { switch rv.Kind() { case reflect.Slice, reflect.Map: return rv.Len() == 0 - case reflect.Ptr, reflect.Interface: + case reflect.Pointer, reflect.Interface: return rv.IsNil() case reflect.Struct: for i := range rv.NumField() { From 1db9f9cdb83d0b9ce1eed0d08eb9325a77e88096 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 16 Aug 2026 16:27:14 +0200 Subject: [PATCH 3/7] Fix linter warning about `WriteString(fmt.Sprintf(...))` --- pkg/cheatsheet/generate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index a9cee6494..5c5a94530 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -196,7 +196,7 @@ func getHeader(binding *types.Binding, tr *i18n.TranslationSet) header { func formatSections(tr *i18n.TranslationSet, bindingSections []*bindingSection) string { var content strings.Builder - content.WriteString(fmt.Sprintf("# Lazygit %s\n", tr.Keybindings)) + fmt.Fprintf(&content, "# Lazygit %s\n", tr.Keybindings) for _, section := range bindingSections { content.WriteString(formatTitle(section.title)) From f0ccb937d3fdf8d76f420357fba21e571124d819 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 16 Aug 2026 16:29:08 +0200 Subject: [PATCH 4/7] Use lo.Map instead of manual append loops Not only is this nicer code (and more idiomatic at least in this code base), but it also avoids linter warnings about missing preallocations (lo.Map does preallocate the result array). --- pkg/gocui/view_test.go | 13 ++++--------- pkg/integration/components/env.go | 10 +++++----- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/pkg/gocui/view_test.go b/pkg/gocui/view_test.go index 294f02b32..2ee5eb4b8 100644 --- a/pkg/gocui/view_test.go +++ b/pkg/gocui/view_test.go @@ -11,6 +11,7 @@ import ( "github.com/gdamore/tcell/v3" "github.com/gdamore/tcell/v3/color" "github.com/rivo/uniseg" + "github.com/samber/lo" "github.com/stretchr/testify/assert" ) @@ -106,10 +107,8 @@ func TestWriteString(t *testing.T) { for _, s := range test.stringsToWrite { v.writeString(s) } - var resultingLines [][]string - for _, l := range v.buf.lines { - resultingLines = append(resultingLines, cellsToStrings(l.cells)) - } + resultingLines := lo.Map(v.buf.lines, + func(l lineType, _ int) []string { return cellsToStrings(l.cells) }) assert.Equal(t, test.expectedLines, resultingLines) } } @@ -465,11 +464,7 @@ func cellsToString(cells []cell) string { } func cellsToStrings(cells []cell) []string { - s := []string{} - for _, c := range cells { - s = append(s, c.chr) - } - return s + return lo.Map(cells, func(c cell, _ int) string { return c.chr }) } func TestLineWrap(t *testing.T) { diff --git a/pkg/integration/components/env.go b/pkg/integration/components/env.go index 6306a88ba..39152092e 100644 --- a/pkg/integration/components/env.go +++ b/pkg/integration/components/env.go @@ -3,6 +3,8 @@ package components import ( "fmt" "os" + + "github.com/samber/lo" ) const ( @@ -43,11 +45,9 @@ var hostEnvironmentAllowlist = [...]string{ // Returns a copy of the environment filtered by // hostEnvironmentAllowlist func allowedHostEnvironment() []string { - env := []string{} - for _, envVar := range hostEnvironmentAllowlist { - env = append(env, fmt.Sprintf("%s=%s", envVar, os.Getenv(envVar))) - } - return env + return lo.Map(hostEnvironmentAllowlist[:], func(envVar string, _ int) string { + return fmt.Sprintf("%s=%s", envVar, os.Getenv(envVar)) + }) } func NewTestEnvironment(rootDir string) []string { From 92e50a5d9afbffca30d18692cbdcbca87cd3d68f Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 16 Aug 2026 16:32:00 +0200 Subject: [PATCH 5/7] Avoid appending to an array literal Instead, create the one dynamic element beforehand and include it in the literal. This avoids a preallocation warning from the linter. --- .../controllers/basic_commits_controller.go | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/pkg/gui/controllers/basic_commits_controller.go b/pkg/gui/controllers/basic_commits_controller.go index 410335712..f698f6cf0 100644 --- a/pkg/gui/controllers/basic_commits_controller.go +++ b/pkg/gui/controllers/basic_commits_controller.go @@ -157,6 +157,18 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e } } + commitTagsItem := &types.MenuItem{ + Label: self.c.Tr.CommitTags, + OnPress: func() error { + return self.copyCommitTagsToClipboard(commit) + }, + Keys: menuKey('t'), + } + + if len(commit.Tags) == 0 { + commitTagsItem.DisabledReason = &types.DisabledReason{Text: self.c.Tr.CommitHasNoTags} + } + items := []*types.MenuItem{ { Label: self.c.Tr.CommitHash, @@ -207,22 +219,9 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e }, Keys: menuKey('a'), }, + commitTagsItem, } - commitTagsItem := types.MenuItem{ - Label: self.c.Tr.CommitTags, - OnPress: func() error { - return self.copyCommitTagsToClipboard(commit) - }, - Keys: menuKey('t'), - } - - if len(commit.Tags) == 0 { - commitTagsItem.DisabledReason = &types.DisabledReason{Text: self.c.Tr.CommitHasNoTags} - } - - items = append(items, &commitTagsItem) - return self.c.Menu(types.CreateMenuOptions{ Title: self.c.Tr.Actions.CopyCommitAttributeToClipboard, Items: items, From 486d8536f25c1e682711f05484d9242881b1bfbb Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 16 Aug 2026 16:09:01 +0200 Subject: [PATCH 6/7] Preallocate arrays where the new linter version would warn about it --- pkg/commands/patch/hunk.go | 3 ++- pkg/gui/context/base_context.go | 4 ++-- pkg/gui/keybindings.go | 5 +++-- pkg/integration/components/runner.go | 5 +++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pkg/commands/patch/hunk.go b/pkg/commands/patch/hunk.go index 6d0177d05..568b312a7 100644 --- a/pkg/commands/patch/hunk.go +++ b/pkg/commands/patch/hunk.go @@ -44,7 +44,8 @@ func (self *Hunk) lineCount() int { // Returns all lines in the hunk, including the header line func (self *Hunk) allLines() []*PatchLine { - lines := []*PatchLine{{Content: self.formatHeaderLine(), Kind: HUNK_HEADER}} + lines := make([]*PatchLine, 1, 1+len(self.bodyLines)) + lines[0] = &PatchLine{Content: self.formatHeaderLine(), Kind: HUNK_HEADER} lines = append(lines, self.bodyLines...) return lines } diff --git a/pkg/gui/context/base_context.go b/pkg/gui/context/base_context.go index 7584b5a12..67b4654a6 100644 --- a/pkg/gui/context/base_context.go +++ b/pkg/gui/context/base_context.go @@ -119,7 +119,7 @@ func (self *BaseContext) GetKey() types.ContextKey { } func (self *BaseContext) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { - bindings := []*types.Binding{} + bindings := make([]*types.Binding, 0, len(self.keybindingsFns)) 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 @@ -216,7 +216,7 @@ func (self *BaseContext) AddOnQuitFn(fn func()) { } func (self *BaseContext) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { - bindings := []*gocui.ViewMouseBinding{} + bindings := make([]*gocui.ViewMouseBinding, 0, len(self.mouseKeybindingsFns)) 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 diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 22d76f01b..c6ac2533e 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -295,8 +295,9 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin }, } - mouseKeybindings := []*gocui.ViewMouseBinding{} - for _, c := range gui.State.Contexts.Flatten() { + contexts := gui.State.Contexts.Flatten() + mouseKeybindings := make([]*gocui.ViewMouseBinding, 0, len(contexts)) + for _, c := range contexts { viewName := c.GetViewName() for _, binding := range c.GetKeybindings(opts) { // TODO: move all mouse keybindings into the mouse keybindings approach below diff --git a/pkg/integration/components/runner.go b/pkg/integration/components/runner.go index aaaabd0a0..098f3f2e9 100644 --- a/pkg/integration/components/runner.go +++ b/pkg/integration/components/runner.go @@ -256,14 +256,15 @@ func getLazygitCommand( return nil, err } - cmdArgs := []string{tempLazygitPath(), "-debug", "--use-config-dir=" + paths.Config()} - resolvedExtraArgs := lo.Map(test.ExtraCmdArgs(), func(arg string, _ int) string { return utils.ResolvePlaceholderString(arg, map[string]string{ "actualPath": paths.Actual(), "actualRepoPath": paths.ActualRepo(), }) }) + + cmdArgs := make([]string, 0, 3+len(resolvedExtraArgs)) + cmdArgs = append(cmdArgs, tempLazygitPath(), "-debug", "--use-config-dir="+paths.Config()) cmdArgs = append(cmdArgs, resolvedExtraArgs...) // Use a limited environment for test isolation, including pass through From 37c53ac1bfe2eca83b59b36bc56d99a618e45a61 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 16 Aug 2026 16:08:53 +0200 Subject: [PATCH 7/7] Bump golangci-lint to 2.12.2 --- .github/workflows/ci.yml | 2 +- scripts/golangci-lint-shim.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f85875dc8..f32d4804d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -195,7 +195,7 @@ jobs: uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9 with: # If you change this, make sure to also update scripts/golangci-lint-shim.sh - version: v2.4.0 + version: v2.12.2 upload-coverage: # List all jobs that produce coverage files needs: [unit-tests, integration-tests] diff --git a/scripts/golangci-lint-shim.sh b/scripts/golangci-lint-shim.sh index a85ccc4d7..6cb3e007c 100755 --- a/scripts/golangci-lint-shim.sh +++ b/scripts/golangci-lint-shim.sh @@ -3,6 +3,6 @@ set -e # Must be kept in sync with the version in .github/workflows/ci.yml -version="v2.4.0" +version="v2.12.2" go run "github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$version" "$@"