{
 "kind": "feature",
 "id": "feature:code-search",
 "url": "https://headlesson.com/features/code-search",
 "title": "Searching code from the command line: ripgrep, ugrep or git grep, and which files each one sees",
 "summary": "For assistants asked to find text in a code tree, this feature compares the three recorded search tools on the same six authored files. headlesson ran ripgrep 15.1.0, ugrep 7.8.5 and git grep 2.50.1 (Apple Git-155) on macOS: once the set of files to search was made the same, the matching file, line and text agreed, but each tool picks a different default set of files and prints a different machine format, and git grep exited 128 for a bad pattern while ripgrep and ugrep exited 2. It is a small sample, not a speed or full compatibility comparison.",
 "published": "2026-10-14",
 "updated": "2026-10-14",
 "body": "# Which files get searched by default\n\n- The six authored files were .gitignore, .hidden.py, src/main.rs, src/util.py, build/out.txt and app.log, with .gitignore listing the last two. app:ripgrep, app:ugrep and app:git-grep were given byte-identical copies.\n- app:ripgrep skips ignored and hidden files by default, but applies .gitignore only inside a Git repository; in a separate authored tree used in its 2026-10-11 test, a copy without .git returned matches from ignored files, so --no-require-git was needed.\n- app:ugrep uses .gitignore only when --ignore-files is given, and --hidden adds hidden files.\n- app:git-grep searches tracked files by default, including a tracked hidden file: 2 matches here. --untracked gave 3, --untracked --no-exclude-standard gave 5, and --no-index --exclude-standard gave 3.\n- Editorial advice, not tested beyond these files: state the directory and the hidden and ignore rules explicitly with app:ripgrep, app:ugrep or app:git-grep rather than relying on defaults, and check whether ignored or hidden files such as .env may be read before widening the search.\n\n# Observed in the tests\n\n- With the hidden and ignore rules set to match, app:ripgrep and app:git-grep returned the same file, line number and text for the 3-match and 5-match cases, and app:ripgrep and app:ugrep agreed on the ordinary (2) and hidden (3) cases. Output order was not compared.\n- Machine output differs: app:ripgrep --json prints JSON Lines events, app:ugrep --json prints one JSON array of files with nested matches, and app:git-grep was read through -n -z, which separates file, line number and text with NUL bytes and is not JSON. The sets were compared after decoding.\n- No match exited 1 with app:ripgrep, app:ugrep and app:git-grep. An invalid pattern \"(\" exited 2 with app:ripgrep and app:ugrep but 128 with app:git-grep, so a caller cannot treat every non-zero exit as \"no match\".\n- Each lesson passed all of its steps: app:ripgrep with the Homebrew build already installed (2026-10-11), app:ugrep built from pinned source with optional PCRE2, Boost Regex and compression libraries turned off, and app:git-grep with the Git that ships with macOS and every command isolated from the user's Git configuration with env -i and configuration controls.\n\n# What was not tested\n\nThe comparison of app:ripgrep, app:ugrep and app:git-grep used six small files. Binary files, Unicode, multiline matches, file names containing newlines, symlinks, full regex compatibility, ugrep's TUI and compressed-file search, speed and memory were not tested; app:ugrep was not rerun for the git grep comparison, only its saved inputs were checked byte for byte. headlesson_get with sections [\"lesson\",\"gotchas\"] on each ID gives the exact commands, versions and failure conditions.\n",
 "refs": [
  {
   "id": "app:ripgrep",
   "name": "ripgrep (rg)",
   "source": {
    "source": "https://github.com/BurntSushi/ripgrep/blob/master/README.md",
    "checked": "2026-10-11",
    "certainty": "primary",
    "by": "official"
   }
  },
  {
   "id": "app:ugrep",
   "name": "ugrep",
   "source": {
    "source": "https://github.com/Genivia/ugrep/blob/v7.8.5/README.md",
    "checked": "2026-10-14",
    "certainty": "primary",
    "by": "official"
   }
  },
  {
   "id": "app:git-grep",
   "name": "git grep (Git subcommand)",
   "source": {
    "source": "https://github.com/git/git/blob/v2.50.1/Documentation/git-grep.adoc",
    "checked": "2026-10-14",
    "certainty": "primary",
    "by": "official"
   }
  }
 ],
 "article_source": {
  "source": "headlesson editorial judgement",
  "checked": "2026-10-14",
  "certainty": "inferred",
  "by": "editorial"
 },
 "note": "Editorial article by the headlesson operator, written from the catalog records it cites. Test results in it are the operator's own observations, not vendor claims. Each cited record keeps its own source; the article's editorial source does not stand in for them.",
 "mcp_get": "headlesson_get id=\"feature:code-search\"",
 "page_updated": "2026-10-14"
}
