processor/history_ignore.go GO 101 lines View on github.com → Search inside
1// SPDX-License-Identifier: MIT23package processor45import (6	"bufio"7	"io"8	"path"9	"strings"1011	"github.com/go-git/go-git/v5"12	"github.com/go-git/go-git/v5/plumbing"13	"github.com/go-git/go-git/v5/plumbing/filemode"14	"github.com/go-git/go-git/v5/plumbing/format/gitignore"15	"github.com/go-git/go-git/v5/plumbing/object"16)1718// historyIgnore wraps a gitignore.Matcher built from .ignore / .sccignore19// files found in the HEAD tree. .gitignore is already applied by git itself,20// so files it excludes never appear in the tree — only the scc/ripgrep21// conventions need extra handling.22type historyIgnore struct {23	matcher gitignore.Matcher24}2526func (h *historyIgnore) Match(p string, isDir bool) bool {27	if h == nil || h.matcher == nil {28		return false29	}30	parts := strings.Split(p, "/")31	return h.matcher.Match(parts, isDir)32}3334// buildHistoryIgnore scans the HEAD tree for .ignore and .sccignore blobs,35// parses them, and produces a matcher. Respects the existing --no-ignore36// (Ignore) and --no-scc-ignore (SccIgnore) flag globals.37func buildHistoryIgnore(repo *git.Repository, head plumbing.Hash) (*historyIgnore, error) {38	commit, err := repo.CommitObject(head)39	if err != nil {40		return nil, err41	}42	tree, err := commit.Tree()43	if err != nil {44		return nil, err45	}4647	var patterns []gitignore.Pattern48	err = tree.Files().ForEach(func(f *object.File) error {49		if f.Mode == filemode.Dir || f.Mode == filemode.Submodule || f.Mode == filemode.Symlink {50			return nil51		}5253		base := path.Base(f.Name)54		switch {55		case base == ".ignore" && !Ignore:56		case base == ".sccignore" && !SccIgnore:57		default:58			return nil59		}6061		reader, err := f.Reader()62		if err != nil {63			return nil64		}65		defer reader.Close()6667		domain := splitDomain(path.Dir(f.Name))68		patterns = append(patterns, parseIgnoreFile(reader, domain)...)69		return nil70	})71	if err != nil {72		return nil, err73	}7475	if len(patterns) == 0 {76		return &historyIgnore{}, nil77	}78	return &historyIgnore{matcher: gitignore.NewMatcher(patterns)}, nil79}8081func splitDomain(dir string) []string {82	if dir == "" || dir == "." {83		return nil84	}85	return strings.Split(dir, "/")86}8788func parseIgnoreFile(r io.Reader, domain []string) []gitignore.Pattern {89	var out []gitignore.Pattern90	scan := bufio.NewScanner(r)91	for scan.Scan() {92		line := strings.TrimRight(scan.Text(), "\r")93		trimmed := strings.TrimSpace(line)94		if trimmed == "" || strings.HasPrefix(trimmed, "#") {95			continue96		}97		out = append(out, gitignore.ParsePattern(line, domain))98	}99	return out100}

Code quality findings 1

Multiple appends without pre-allocation; use make() with capacity when size is known
info performance append-without-prealloc
out = append(out, gitignore.ParsePattern(line, domain))

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.