blame-why
v1.1.0
Published
Enrich git blame with PR context — instantly understand why a line of code changed
Maintainers
Readme
blame-why
git blametells you who and when.blame-whytells you why.
Enrich git blame output with the linked pull request, issue description, and review comments — all inline in your terminal. Stop context-switching between your editor, GitHub, and Jira just to understand a single line of code.
$ blame-why src/auth.ts 42────────────────────────────────────────────────────────────────────────
blame-why src/auth.ts:42
────────────────────────────────────────────────────────────────────────
L42 const hash = await bcrypt.hash(password, SALT_ROUNDS);
Commit a3f9d2b1 a3f9d2b1c4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9
Summary Switch to bcrypt for password hashing
Author Jane Doe <[email protected]>
Date Mar 15, 2024, 02:30 PM (+0000)
────────────────────────────────────────────────────────────────────────
Pull Request #234 [merged]
────────────────────────────────────────────────────────────────────────
Replace MD5 password hashing with bcrypt
by @janedoe · merged Mar 15, 2024, 03:45 PM
https://github.com/example/repo/pull/234
Description:
MD5 is cryptographically broken and must not be used for password
storage. This PR migrates auth to bcrypt with a cost factor of 12,
matching OWASP recommendations.
·······································································
Linked Issues (1)
#123 Security: MD5 password hashing is insecure [closed]
https://github.com/example/repo/issues/123
Reported by the security team audit in Q1. MD5 is vulnerable to
rainbow table attacks and fast brute-force.
·······································································
Review Comments (1)
@alice · src/auth.ts:42 · Mar 15, 2024, 03:10 PM
Should we expose SALT_ROUNDS as a config value so ops can tune it?Features
- PR context — Title, description, author, and merge date at a glance
- Linked issues — Automatically parsed from
Closes #123/Fixes #456keywords in the PR body - Review comments — The inline discussion that shaped the code
- Graceful fallback — Works without
GITHUB_TOKEN, and degrades cleanly when no PR exists - JSON output —
--jsonflag for scripting and editor integrations - GitHub Enterprise — Override the API base URL via
GITHUB_API_BASE
Installation
From npm (recommended)
npm install -g blame-whyFrom source
git clone https://github.com/AbelKel/blame-why.git
cd blame-why
npm install
npm run build
npm link # installs the `blame-why` binary globallySetup
Set your GitHub personal access token so API requests are authenticated (5,000 req/hr instead of 60):
export GITHUB_TOKEN=ghp_your_token_hereAdd this to your shell profile (~/.bashrc, ~/.zshrc, etc.) to make it permanent.
You can create a token at GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens. The only scope required is read access to pull requests and issues on the relevant repositories.
Usage
blame-why <file> <line> [options]Arguments
| Argument | Description |
|----------|-------------|
| file | Path to the source file (relative to cwd or absolute) |
| line | 1-based line number to inspect |
Options
| Flag | Description | Default |
|------|-------------|---------|
| -r, --remote <name> | Git remote name to resolve as GitHub origin | origin |
| --no-comments | Skip fetching inline review comments (faster) | — |
| --max-comments <n> | Max review comments to display | 5 |
| --json | Output raw JSON instead of formatted text | — |
| -v, --version | Print version | — |
| -h, --help | Show help | — |
Environment variables
| Variable | Description |
|----------|-------------|
| GITHUB_TOKEN | GitHub personal access token (recommended) |
| GITHUB_API_BASE | Override for GitHub Enterprise (e.g. https://github.myco.com/api/v3) |
Examples
# Basic usage
blame-why src/auth.ts 42
# Skip review comments for a faster response
blame-why lib/parser.js 108 --no-comments
# Use a different remote (e.g. an upstream fork)
blame-why src/index.ts 7 --remote upstream
# Pipe JSON output into jq
blame-why src/routes.ts 55 --json | jq '.pullRequest.title'
# GitHub Enterprise
GITHUB_API_BASE=https://github.myco.com/api/v3 blame-why src/app.ts 12How it works
git blame --porcelainis run for the specified file and line, giving the commit SHA, author, date, and commit message- The git remote URL is parsed to extract the GitHub owner and repo
- GitHub REST API —
GET /repos/{owner}/{repo}/commits/{sha}/pulls— finds PRs that contain the commit - The PR body is scanned for closing keywords (
Closes #N,Fixes #N,Resolves #N) and linked issues are fetched - Review comments for the PR are fetched and filtered to the most recent
--max-comments - Everything is rendered with colour via chalk
Architecture
src/
├── index.ts CLI entry point — argument parsing and orchestration
├── git.ts Git operations (blame, remote URL parsing)
├── github.ts GitHub REST API calls and response mapping
├── formatter.ts All terminal output — chalk colours, layout, truncation
└── types.ts TypeScript interfaces shared across modulesEach module has a single responsibility and is independently testable. The formatter is the only module that calls console.log; all others are pure functions that return structured data.
Fallback behaviour
| Situation | Behaviour |
|-----------|-----------|
| No GitHub remote | Shows git blame info only |
| No GITHUB_TOKEN set | Proceeds unauthenticated (60 req/hr); shows a warning |
| Commit not in any PR | Shows git blame info + "no PR found" note |
| GitHub API error | Shows git blame info + warning message (non-fatal) |
| Uncommitted line | Shows author as pending, skips GitHub lookup |
| Line out of range | Exits with a clear error message |
Screenshots
Contributing
git clone https://github.com/AbelKel/blame-why.git
cd blame-why
npm install
npm run lint # type-check only, no emit
npm run build # compile to dist/License
MIT
