{"id":51008412,"url":"https://github.com/voidd0/gitwhen","last_synced_at":"2026-06-20T23:31:02.350Z","repository":{"id":354577572,"uuid":"1223795108","full_name":"voidd0/gitwhen","owner":"voidd0","description":"gitwhen — pinpoint when a string, line, or file changed in git history. Zero deps wrapper around git log -S / git blame / git log --diff-filter.","archived":false,"fork":false,"pushed_at":"2026-04-29T06:14:24.000Z","size":14,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-29T07:20:40.567Z","etag":null,"topics":["cli","code-history","devtools","git","git-archaeology","git-blame","git-history","git-log","nodejs","voiddo"],"latest_commit_sha":null,"homepage":"https://tools.voiddo.com/gitwhen/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/voidd0.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"custom":["https://voiddo.com/contact/","https://scrb.voiddo.com/"]}},"created_at":"2026-04-28T16:58:20.000Z","updated_at":"2026-04-29T06:14:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/voidd0/gitwhen","commit_stats":null,"previous_names":["voidd0/gitwhen"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/voidd0/gitwhen","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fgitwhen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fgitwhen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fgitwhen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fgitwhen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/voidd0","download_url":"https://codeload.github.com/voidd0/gitwhen/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fgitwhen/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34589204,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","code-history","devtools","git","git-archaeology","git-blame","git-history","git-log","nodejs","voiddo"],"created_at":"2026-06-20T23:31:01.395Z","updated_at":"2026-06-20T23:31:02.345Z","avatar_url":"https://github.com/voidd0.png","language":"JavaScript","funding_links":["https://voiddo.com/contact/","https://scrb.voiddo.com/"],"categories":[],"sub_categories":[],"readme":"# gitwhen\n\n[![npm version](https://img.shields.io/npm/v/@v0idd0/gitwhen.svg?color=A0573A)](https://www.npmjs.com/package/@v0idd0/gitwhen)\n[![npm downloads](https://img.shields.io/npm/dw/@v0idd0/gitwhen.svg?color=1F1A14)](https://www.npmjs.com/package/@v0idd0/gitwhen)\n[![License: MIT](https://img.shields.io/badge/license-MIT-A0573A.svg)](LICENSE)\n[![Node ≥14](https://img.shields.io/badge/node-%E2%89%A514-1F1A14)](package.json)\n\n**[Homepage](https://tools.voiddo.com/gitwhen/?ref=gitwhen-readme)** · **[Compare with tig](https://tools.voiddo.com/gitwhen/compare/tig/?ref=gitwhen-readme)** · **[GitHub](https://github.com/voidd0/gitwhen)** · **[npm](https://www.npmjs.com/package/@v0idd0/gitwhen)** · **[All tools](https://tools.voiddo.com/?ref=gitwhen-catalog-readme)** · **[Contact](mailto:support@voiddo.com)**\n\n---\n\nPinpoint *when* a string, line, or file changed in git history. Wraps `git log -S`, `git blame`, and `git log --diff-filter=A` with sensible defaults so you don't have to memorize flag combinations. Zero deps. Free forever from vøiddo.\n\nIf you are choosing between a focused CLI and an interactive TUI, start with the live compare page: [gitwhen vs tig](https://tools.voiddo.com/gitwhen/compare/tig/?ref=gitwhen-readme).\n\n```\n$ gitwhen \"TODO: deprecated\"\ngitwhen \"TODO: deprecated\"\n\n ● a3c4b18 2026-03-14 alice — drop legacy queue path\n ● 7f1e602 2025-11-08 bob   — TODO before refactor\n\n2 commit(s) touched the diff.\n```\n\n## Why gitwhen\n\nGit already knows the answer. The problem is the question takes three different commands depending on whether you want to find when a *string* entered the codebase, when a *line* was last set, or when a *file* was first added or last deleted. You only run any of them once a quarter, so by the time you need it you've forgotten the flag soup. `git log -S \"\u003cstr\u003e\" -- path/`, `git blame -L 42,42 file`, `git log --diff-filter=A --reverse -- path` — three different mental models. gitwhen is the mnemonic that wraps all three.\n\n## Install\n\n```bash\nnpm install -g @v0idd0/gitwhen\n```\n\n## Usage\n\n```bash\n# When did this string get added/removed?\ngitwhen \"TODO: deprecated\"\n\n# What commit last set this exact line?\ngitwhen src/server/index.ts:42\n\n# When was a file first added / deleted / re-added?\ngitwhen --file backend/legacy.py\n\n# Regex variant\ngitwhen --regex \"console\\.log\\(.*pii.*\\)\"\n\n# Restrict string search to a path\ngitwhen \"API_KEY\" --path backend/\n\n# JSON for scripts\ngitwhen \"feature_flag\" --json | jq '.commits[0].author'\n```\n\n## What it does\n\n| Mode | Wraps | Output |\n|---|---|---|\n| `gitwhen \"\u003cquery\u003e\"` | `git log --all -S \"\u003cquery\u003e\"` | Every commit that introduced or removed this exact string, oldest first |\n| `gitwhen \u003cfile\u003e:\u003cline\u003e` | `git blame --porcelain` | Hash, author, date, subject, line content |\n| `gitwhen --file \u003cpath\u003e` | `git log --diff-filter=A/D` | First-added commit, every delete, re-adds, last-touched |\n| `gitwhen --regex \"\u003cre\u003e\"` | `git log --all -G \u003cre\u003e` | Same as string mode but regex matching on the diff |\n\nAdd `--json` to any for structured output ready for `jq`.\n\n## Compared to alternatives\n\n| tool | string-pickaxe | line-blame | file-lifespan | regex on diff | install |\n|---|---|---|---|---|---|\n| gitwhen | yes | yes | yes | yes | one npm install |\n| `git log -S` | yes | no | no | no | bundled |\n| `git blame` | no | yes | no | no | bundled |\n| `git log --diff-filter` | no | no | yes | no | bundled |\n| GitLens (VS Code) | yes | yes | yes | partial | editor extension |\n\nIf you live in VS Code, GitLens does this and more. For a terminal-resident workflow (server triage, code review on a remote box), gitwhen is the consolidating CLI.\n\n## FAQ\n\n**Why search across all branches by default?** Because regressions tend to live in *some* branch you forgot about. `git log -S` defaulting to current branch means \"I know what reverted me\" misses the obvious answer.\n\n**Performance on a 100K-commit repo?** First search is bound by `git log -S` itself (a few seconds in pathological cases). gitwhen adds \u003c100ms of parsing on top.\n\n**Does it find renames?** For `--file` mode yes (we pass `--follow`). For string-pickaxe mode renames don't matter — the content is what's tracked.\n\n**What about `git log --all -L \u003cline\u003e`?** That's the \"evolution of this exact line\" view. It's powerful but slow on large files; gitwhen's blame mode is the snapshot (\"who set this *now*\"). Different question, different tool.\n\n## Exit codes\n\n- `0` — found at least one match\n- `1` — no commits matched (empty timeline)\n- `2` — invalid arguments or not a git repo\n\nWire it into a pre-commit / CI guardrail:\n\n```bash\ngitwhen --json \"OLD_DEPRECATED_API\" | jq -e '.count \u003e 0' \u003e /dev/null \u0026\u0026 {\n  echo \"OLD_DEPRECATED_API is back in your tree.\"\n  exit 1\n}\n```\n\n## Programmatic API\n\n```javascript\nconst { searchString, blameLine, fileLifespan } = require('@v0idd0/gitwhen');\n\nconst r = searchString('feature_flag', { cwd: '/path/to/repo' });\nconsole.log(r.commits[0]);\n// { hash, short, author, email, date, subject }\n```\n\n## More from the studio\n\nThis is one tool out of many — see [`from-the-studio.md`](from-the-studio.md) for the full lineup of vøiddo products (other CLI tools, browser extensions, the studio's flagship products and games).\n\n## From the same studio\n\n- **[@v0idd0/jsonyo](https://www.npmjs.com/package/@v0idd0/jsonyo)** — JSON swiss army knife, 18 commands, zero limits\n- **[@v0idd0/envguard](https://www.npmjs.com/package/@v0idd0/envguard)** — stop shipping `.env` drift to staging\n- **[@v0idd0/depcheck](https://www.npmjs.com/package/@v0idd0/depcheck)** — find unused dependencies in one command\n- **[@v0idd0/gitstats](https://www.npmjs.com/package/@v0idd0/gitstats)** — git repo analytics, one command\n- **[View all tools →](https://voiddo.com/tools/)**\n\n## License\n\nMIT — part of the [vøiddo](https://voiddo.com/?ref=gitwhen-studio-readme) tools collection.\n\n---\n\nBuilt by [vøiddo](https://voiddo.com/) — a small studio shipping AI-flavoured products, free dev tools, Chrome extensions and weird browser games.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoidd0%2Fgitwhen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvoidd0%2Fgitwhen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoidd0%2Fgitwhen/lists"}