# Git Graph for Obsidian VS Code's Source Control graph as an Obsidian side pane. If your vault is a git repository (or sits inside one), the pane shows the commit graph: colored lanes, commit subjects, authors, dates, branch/tag/remote badges, the current HEAD, and a row for uncommitted changes. Click a commit to see its full message and changed files. Read-only: the plugin never runs a git command that modifies the repository. Click a file in an expanded commit to open it in the editor (files outside the vault or no longer present show a notice). Click the changes row to see the uncommitted files; click a file to open it. Deleted files are shown struck through and cannot be opened. ## Requirements - Obsidian 1.13 or newer, desktop only. - `git` installed. If it is not on your PATH, set the executable in the plugin settings. - git 2.13 or newer (`--absolute-git-dir` is used to resolve the repository's `.git` directory). ## What the plugin touches Obsidian's community-plugin review flags any plugin that uses Node's `fs` module or runs external programs. This one does both, for exactly these purposes, and nothing else: - **Runs the `git` executable** (the one from the *Git executable* setting) with `child_process.execFile` — never through a shell — to read the repository: `rev-parse`, `log`, `for-each-ref`, `status`, `show`, `diff-tree`, `symbolic-ref`. No command writes to the repository or the working tree; the plugin has no commit, checkout, fetch or push. - **Reads the repository's `.git` directory** with `fs.existsSync` and `fs.watch` so the pane refreshes when a commit, branch or checkout happens. For a vault that is a folder inside a larger repository, that directory sits outside the vault. The plugin never writes there. - **Resolves real paths** (`fs.realpathSync.native`) of the vault folder and the repository root so a vault opened through a symlink or junction matches the paths git reports. Files are opened in the editor through Obsidian's vault API only. The plugin makes no network requests and collects no telemetry. ## Usage Open the pane from the ribbon icon, or from the command palette: **Git Graph: Open**. **Git Graph: Refresh** re-reads the repository on demand; the pane also refreshes on its own when the repository's git state changes (commits, branches, checkouts). Working-tree edits (unstaged/staged file changes) refresh the changes row within about half a second while the pane is open; a git-state change still refreshes the whole graph. When the vault is a folder inside a larger repository, the row counts only files under the vault. The history icon in the pane header narrows the list to just the commits that touched the file open in the active editor, as a flat list with the graph lanes hidden; switching the active file re-filters it, and clicking the icon again returns to the full graph. Renames are followed, including one made in Obsidian and not yet committed. File history obeys the **Refs to show** setting like the rest of the pane, so on Auto a commit that touched the file on an unmerged branch is not listed until you switch to All. In file history, an expanded commit shows that file's diff (against the commit's first parent) instead of the file list, which stays one click away under **All files**; **Newer** / **Older** — or ↑ / ↓ on the expanded row — step to the neighbouring commit, keeping it where the last one was and paging in older history as needed. On any other row ↑ / ↓ move the focus between rows. ## Settings | Setting | Default | Meaning | |---|---|---| | Git executable | `git` | Command or path used to run git. | | Refs to show | Auto | Auto: current branch, its upstream, default remote branch. All: every branch and tag. | | Commits per page | 200 | Loaded at once; more load as you scroll. | | Show working tree changes | on | Row above the newest commit with the uncommitted change count for files inside the vault; click it for the file list. | | Date format | Relative | "3 days ago" or `YYYY-MM-DD HH:mm`. | ## Development ```bash npm install npm run test-build # builds and installs into .obsidian/plugins/git-graph/ — open this repo as a vault npm run check # build + lint + dead-code check + LOC backstop + coverage: the pre-commit gate ``` `npm run check` runs, in order: `build` (typecheck + vite build), `lint` (oxlint then eslint), `deadcode` (fallow), `loc` (the LOC report and per-file backstop), then `test:coverage` (`vitest run --coverage`, which also runs every test). `tsconfig.json` includes `src/**`, `tests/**`, `harness/**` and the root configs, so `npm run typecheck` (`vue-tsc --noEmit`) type-checks all of them; `build` and `test-build` call it instead of inlining `vue-tsc`. | Gate | Command | What fails it | |---|---|---| | Typecheck | `npm run typecheck` | A type error anywhere under `src/**`, `tests/**`, `harness/**` or the root configs (strict, `noUncheckedIndexedAccess`). | | Build | `npm run build` | `typecheck`, or the vite build itself, failing. | | oxlint | `npm run lint:oxlint` | Any oxlint correctness/suspicious finding. | | eslint | `npm run lint:eslint` | Any obsidianmd/typescript-eslint/vue rule, at `--max-warnings 0` — including the size/complexity limits: `src/**` caps `max-lines` (300), `max-lines-per-function` (80), `complexity` (12), `max-depth` (4), `max-params` (5), `max-nested-callbacks` (4); `tests/**`, `harness/**` and `scripts/**` cap `max-lines` (500), `complexity` (15), `max-depth` (4) (no per-function line limit — a `describe` body is one function). A handful of pre-existing functions exceed these by a small, documented margin; each has a file-scoped override in `eslint.config.mjs` with a `// TODO(quality)` comment explaining why an extraction isn't trivial. | | deadcode | `npm run deadcode` | fallow finding an unused export, file, component prop, or dependency. | | LOC | `npm run loc` | Any tracked file (`src/`, `tests/`, `scripts/`, `harness/`, `styles/`) exceeding 400 code lines — a backstop for file types eslint's size rules don't cover (`.css`, `.mjs` configs). Also prints a per-directory and top-10-files LOC table; `--json` for machine-readable output. | | Coverage thresholds | `npm run test:coverage` | v8 coverage over `src/**/*.{ts,vue}` dropping below thresholds: statements 90%, branches 80%, functions 90%, lines 90% (rounded down from the measured baseline, floored at 80/80/80/70). | | Tests | `npm run test` | Any vitest failure (`dom` and `node` projects). | | Test build | `npm run test-build` | `typecheck`, the dev-mode vite build, or `scripts/test-build.mjs` (installs into `.obsidian/plugins/git-graph/`) failing. | ### Styles All CSS lives in `styles/` as partials, listed in load order by `styles/index.css`; no `.vue` file carries a `