A lens from
git blameto release version. See which release first shipped any line of code, right in your editor.
π’ v1.2.0 β the line under your cursor first shipped in v1.2.0
π’ Unreleased β committed, but not in any release tag yet
π’ Uncommitted β working-tree edit
π’ Limited history β shallow clone; can't determine reliably
A single status-bar item, updated as you move the cursor. No new panels, no hover popups, no editor decorations. Just one quiet line that answers the question: "in which release did this line first reach users?"
ShipLens runs in three places: VSCode-compatible editors, JetBrains-Platform IDEs, and your terminal.
| Surface | Where to get it |
|---|---|
| VSCode | VSCode Marketplace |
| Cursor / VSCodium / Theia / Gitpod | Open VSX Registry |
| Any JetBrains-Platform IDE (2025.1+) | JetBrains Marketplace |
| Terminal (macOS / Linux) | brew install ender-wang/tap/shiplens |
| Terminal (any OS, manual) | GitHub Releases β shiplens-cli-*.tar.gz / .zip |
JetBrains IDE coverage β verified compatible: IntelliJ IDEA (Ultimate + Community), PyCharm (Pro + Community), GoLand, WebStorm, RubyMine, CLion, Rider, DataGrip, PhpStorm, RustRover, DataSpell, Android Studio, MPS. Not supported: AppCode (deprecated upstream), JetBrains Gateway, JetBrains Client, Code With Me Guest.
In an editor, open the Extensions panel (Cmd+Shift+X / Ctrl+Shift+X), search ShipLens, click Install. All editor builds ship the same algorithm, byte-for-byte.
To install an editor extension from the command line:
code --install-extension Ender-Wang.shiplens # VSCode
cursor --install-extension Ender-Wang.shiplens # CursorTo install the CLI:
brew install ender-wang/tap/shiplens # macOS / Linux (Homebrew)
shiplens line src/auth.ts:42 # β π’ v1.2.0
shiplens commit abc1234 --json # stable JSON for scripts / CIRequires VSCode 1.85+ (or any compatible fork) for the editor extension; the CLI has no runtime dependencies beyond git on PATH. Works alongside GitLens.
git blame answers who last touched a line. Tools like GitLens make that
information beautifully accessible. But none of them answer the equally
important question β which release first shipped that change to users?
You can piece it together with git tag --contains, git describe, or a
trip to the Changelog, but each of those means leaving the editor and
breaking your reading flow. ShipLens collapses that lookup into a glance at
the status bar.
| Dimension | GitLens | ShipLens |
|---|---|---|
| Core question | Who changed this line, when | Which release shipped this line |
| Primary UI | Inline blame, hover, side panels | A single line in the status bar |
| Performance focus | Whole-file blame, rich UI | Single-line query, minimal noise |
| Configuration surface | High | Minimal |
| Coexistence | β | Fully compatible; runs alongside GitLens |
ShipLens is intentionally narrow. If GitLens is the microscope, ShipLens is the timestamp on the slide.
ShipLens shows a tag only when three things are true:
git blame -L N,N -- filereports commitCas the line's last author.git tag --contains Cincludes tagT.Tis the earliest non-pre-release tag in that set, ordered by the committer date of the commit each tag points to.
Steps 1 and 2 are pure git β the same machinery that powers GitLens, GitHub blame, and git rev-list. We don't reinterpret them. Step 3 is the only judgment call: we sort by committer date because tag creation date can lag the actual release (retroactive tagging), author date can predate the merge by months, and topological order isn't well-defined when commits are cherry-picked across release branches. Pre-releases are filtered before the pick via shiplens.tagInclude / shiplens.tagExclude (defaults exclude *-rc*, *-beta*, *-alpha*, *-pre*, *-dev*, *-snapshot*).
When any of those assumptions doesn't hold, ShipLens says so explicitly rather than guess: Uncommitted (working-tree edit), Unreleased (no containing tag yet), Limited history (shallow clone, ancestry can't be traversed reliably).
You can reproduce the algorithm by hand in any repo:
git blame -L N,N -- file # β commit SHA
git tag --contains <sha> # β candidate tags
for t in <candidates>; do # β committer dates
echo -n "$t "; git log -1 --format='%cI' "$t"
done | sort -k2The first non-pre-release line in that sorted output is what the status bar shows. If they ever disagree, that's a bug β please open an issue.
- Code archaeology β spot a critical line and immediately know which release it first appeared in. No editor switch, no Changelog hunting.
- Bug triage β a user reports "it broke in v1.3.0"; jump to the suspect line and verify whether it was indeed introduced there.
- Regression test scoping β use the first-release tag to decide which versions need re-testing for a given change.
- Documentation and review β cite a release version directly from the status bar when explaining a change to teammates.
- Multi-repo workflows β in microservice or multi-repo setups, quickly correlate a change in the current repo with its release graph.
The shiplens CLI (see Install) covers scripts, CI jobs, and any agent that can shell out. For Cursor specifically, ShipLens also ships a Cursor Agent Skill that teaches the agent the same algorithm without needing the binary on PATH. Install it once:
mkdir -p ~/.cursor/skills
cp -r skills/shiplens ~/.cursor/skills/Then ask your agent things like:
- "Which release first shipped line 42 of
src/auth.ts?" - "In which version did the regression on line 88 of this file land?"
- "What tag contains commit abc1234?"
The skill auto-activates on those phrasings β no need to mention "ShipLens" by name. It runs the exact same git blame β git tag --contains β first by committer date pipeline as the editor extension, with the same default filters.
The canonical skill source lives at skills/shiplens/SKILL.md in this repo. It's updated alongside extension releases when defaults change.
Available on the VSCode Marketplace, Open VSX Registry, and JetBrains Marketplace.
- First-release tag for the current line, displayed in the status bar.
- Tooltip with commit SHA, summary, author, and tag date.
- Tag include/exclude glob configuration (pre-releases filtered by default).
- Multi-root workspace isolation.
- Graceful degradation for
Uncommitted,Unreleased, andLimited history.
- Click status bar to open the corresponding GitHub / GitLab tag page.
- Multi-line selection: show the earliest and latest release across the range.
- Monorepo tag-prefix routing (e.g.,
frontend-v*vs.backend-v*). - Background tag-DAG index for instant lookups on large repos.
- Issue / PR linking through commit message references (
Fixes #123β release). - File-level release timeline view (every release in which the file changed).
- CI/CD signal hookup β tag β pipeline status alongside the version.
- JetBrains plugin reusing the same core.
- Optional integration with GitLens' blame data source.
The defaults work for most repos. The full set of v0.1 settings:
| Setting | Default | Description |
|---|---|---|
shiplens.tagInclude |
* |
Glob passed to git tag --contains. |
shiplens.tagExclude |
["*-rc*", "*-beta*", "*-alpha*", "*-pre*", "*-dev*", "*-snapshot*", "rescue/*"] |
Patterns dropped after the include filter. Covers common pre-release suffixes and the rescue/* namespace some teams use for internal hotfixes. |
shiplens.sortBy |
committerDate |
How candidate tags are ordered. |
shiplens.debounceMs |
150 |
Delay between cursor movement and the next query. |
shiplens.followRenames |
false |
Pass --follow to git blame. |
shiplens.statusBar.alignment |
right |
Status bar position. |
This is an npm-workspaces monorepo:
packages/coreβ@shiplens/core, the editor-agnostic library that does the git work. Pure TypeScript, no editor dependencies.packages/vscode-extensionβshiplens, the VSCode extension shell. UI, configuration, and event wiring; no git logic of its own.packages/jetbrains-pluginβshiplens-jetbrains, a Kotlin port of the algorithm + IntelliJ-Platform integration (status bar, settings, listeners). Single-JAR, no Node runtime, no IPC. Mirrors@shiplens/core's structure file-for-file for easy lockstep maintenance.
nvm use # picks up Node 22 from .nvmrc
npm install
npm run buildOpen this folder in VSCode and press F5 ("Run Extension"). A new window
opens with ShipLens loaded. npm run watch keeps the bundle fresh while you
iterate; reload the host window (Cmd+R) after a change.
npm run package # produces packages/vscode-extension/shiplens.vsix
npm run install:vsix # runs `code --install-extension ... --force`Or install from the VSCode UI: Extensions panel β β¦ menu β Install
from VSIXβ¦ β pick packages/vscode-extension/shiplens.vsix.
To uninstall: code --uninstall-extension Ender-Wang.shiplens (or via the
Extensions panel).
MIT β see LICENSE.