LogoFreestyle

Search

Full-text search across repository files, filenames, commit messages, and diff history.

Search for text or regex patterns across all files in a repository at a given revision. Returns matching lines with context, column offsets, and file metadata.

import { freestyle } from "freestyle";

const repo = freestyle.git.repos.ref({ repoId: "your-repo-id" });

const result = await repo.search({
  query: "TODO",
  pathPattern: "src/**/*.ts",
  excludePattern: "**/*.test.ts",
});

for (const file of result.files) {
  for (const match of file.matches) {
    console.log(`${file.path}:${match.lineNumber} ${match.line}`);
  }
}

Parameters:

ParameterTypeDefaultDescription
querystringRequired. The text or regex pattern to search for
revstring"HEAD"Git ref to search (branch name, tag, or commit SHA)
pathPatternstringGlob pattern to include only matching file paths (e.g. "src/**/*.ts")
excludePatternstringGlob pattern to exclude file paths (e.g. "node_modules/**")
maxResultsnumber100Maximum number of matching files to return (max 1000)
caseSensitivebooleanfalseWhether the search is case-sensitive
isRegexbooleanfalseTreat the query as a regular expression
wholeWordbooleanfalseMatch whole words only
offsetnumber0Number of file results to skip (for pagination)

Response:

interface SearchResult {
  totalFiles: number;    // Total matching files (before pagination)
  totalMatches: number;  // Total matching lines across all files
  hasMore: boolean;      // Whether more results exist beyond this page
  files: Array<{
    path: string;              // File path relative to repo root
    extension: string | null;  // File extension (e.g. "ts")
    size: number;              // File size in bytes
    matches: Array<{
      lineNumber: number;      // 1-based line number
      line: string;            // Full text of the matching line
      startColumn: number;     // 0-based byte offset of match start
      endColumn: number;       // 0-based byte offset of match end
      contextBefore: string[]; // Lines before the match
      contextAfter: string[];  // Lines after the match
    }>;
  }>;
}

Pass isRegex: true to use regular expression patterns:

import { freestyle } from "freestyle";

const repo = freestyle.git.repos.ref({ repoId: "your-repo-id" });

// Find all function definitions
const result = await repo.search({
  query: "^(export\\s+)?(async\\s+)?function\\s+\\w+",
  isRegex: true,
  pathPattern: "**/*.ts",
});

Pagination

Use the offset parameter along with hasMore to paginate through results:

import { freestyle } from "freestyle";

const repo = freestyle.git.repos.ref({ repoId: "your-repo-id" });

let offset = 0;
const pageSize = 50;
let allFiles = [];

while (true) {
  const result = await repo.search({
    query: "TODO",
    maxResults: pageSize,
    offset,
  });

  allFiles.push(...result.files);

  if (!result.hasMore) break;
  offset += pageSize;
}

console.log(`Found ${allFiles.length} files with TODOs`);

Search for files by their name or path. Useful for file pickers and navigation.

import { freestyle } from "freestyle";

const repo = freestyle.git.repos.ref({ repoId: "your-repo-id" });

const result = await repo.searchFiles({
  query: "index",
  maxResults: 20,
});

for (const file of result.files) {
  console.log(`${file.path} (${file.size} bytes)`);
}

Parameters:

ParameterTypeDefaultDescription
querystringRequired. Text or regex to match against file paths
revstring"HEAD"Git ref to search
maxResultsnumber100Maximum number of results (max 1000)
caseSensitivebooleanfalseWhether the search is case-sensitive
isRegexbooleanfalseTreat the query as a regular expression

Response:

interface FilenameSearchResult {
  totalFiles: number;
  hasMore: boolean;
  files: Array<{
    path: string;              // Full path relative to repo root
    extension: string | null;  // File extension
    size: number;              // File size in bytes
  }>;
}

Search through commit messages in the repository history.

import { freestyle } from "freestyle";

const repo = freestyle.git.repos.ref({ repoId: "your-repo-id" });

const result = await repo.searchCommits({
  query: "fix",
  maxResults: 10,
});

for (const commit of result.commits) {
  console.log(`${commit.sha.slice(0, 7)} ${commit.message} (${commit.authorName})`);
}

Parameters:

ParameterTypeDefaultDescription
querystringRequired. Text or regex to search in commit messages
revstring"HEAD"Git ref to start walking from
maxResultsnumber100Maximum number of matching commits to return (max 1000)
caseSensitivebooleanfalseWhether the search is case-sensitive
isRegexbooleanfalseTreat the query as a regular expression

Response:

interface CommitSearchResult {
  totalCommits: number;
  hasMore: boolean;
  commits: Array<{
    sha: string;          // Full commit SHA
    message: string;      // First line of the commit message
    fullMessage: string;  // Complete commit message
    authorName: string;
    authorEmail: string;
    timestamp: string;    // ISO 8601 timestamp
  }>;
}

Search for content that was added or removed across commits — the equivalent of git log -S or git log -G. This walks the commit history and inspects each commit's diff for lines matching the query.

This is useful for finding when a specific piece of code was introduced, when a bug was added, or tracking changes to a particular pattern over time.

import { freestyle } from "freestyle";

const repo = freestyle.git.repos.ref({ repoId: "your-repo-id" });

const result = await repo.searchDiffs({
  query: "DATABASE_URL",
  pathPattern: "src/**",
  maxResults: 5,
});

for (const commit of result.commits) {
  console.log(`${commit.sha.slice(0, 7)} ${commit.message}`);
  for (const file of commit.files) {
    for (const match of file.matches) {
      const prefix = match.isAddition ? "+" : "-";
      console.log(`  ${file.path}:${match.lineNumber} ${prefix} ${match.line}`);
    }
  }
}

Parameters:

ParameterTypeDefaultDescription
querystringRequired. Text or regex to search in changed lines
revstring"HEAD"Git ref to start walking from
pathPatternstringGlob pattern to include only matching file paths
excludePatternstringGlob pattern to exclude file paths
maxResultsnumber100Maximum number of matching commits to return (max 1000)
caseSensitivebooleanfalseWhether the search is case-sensitive
isRegexbooleanfalseTreat the query as a regular expression
wholeWordbooleanfalseMatch whole words only
offsetnumber0Number of commit results to skip (for pagination)

Response:

interface DiffSearchResult {
  totalCommits: number;  // Total commits with matching changes
  hasMore: boolean;
  commits: Array<{
    sha: string;          // Commit SHA
    message: string;      // First line of commit message
    authorName: string;
    authorEmail: string;
    timestamp: string;    // ISO 8601
    files: Array<{
      path: string;       // File path
      matches: Array<{
        line: string;        // The changed line content
        lineNumber: number;  // Line number in the file
        startColumn: number; // Match start offset
        endColumn: number;   // Match end offset
        isAddition: boolean; // true = added, false = deleted
      }>;
    }>;
  }>;
}

Diff search walks up to 10,000 commits from the starting revision. For repositories with extensive history, use a specific rev to narrow the search window.

On this page

Freestyle AI

Documentation assistant

Experimental: AI responses may not always be accurate—please verify important details with the official documentation.

How can I help?

Ask me about Freestyle while you browse the docs.