> ## Documentation Index
> Fetch the complete documentation index at: https://code.storage/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# getBlame()

> Show what revision and author last modified each line of a file.

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  const blame = await repo.getBlame({
    path: "src/api/auth.ts",
    ref: "main",
  });

  console.log(`${blame.path} @ ${blame.commitSha}`);
  for (const line of blame.lines) {
    console.log(
      `${line.lineNumber}\t${line.commitSha.slice(0, 8)}\t${line.authorName}\t${line.summary}`
    );
  }

  // Range + rename detection
  const range = await repo.getBlame({
    path: "src/api/auth.ts",
    ref: "main",
    ranges: ["10,40"],
    detectMoves: true,
  });
  ```

  ```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  blame = await repo.get_blame(
      path="src/api/auth.py",
      ref="main",
  )

  print(f"{blame['path']} @ {blame['commit_sha']}")
  for line in blame["lines"]:
      print(
          f"{line['line_number']}\t{line['commit_sha'][:8]}\t"
          f"{line['author_name']}\t{line['summary']}"
      )

  # Range + rename detection
  range_blame = await repo.get_blame(
      path="src/api/auth.py",
      ref="main",
      ranges=["10,40"],
      detect_moves=True,
  )
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  blame, err := repo.GetBlame(context.Background(), storage.BlameOptions{
      Path: "src/api/auth.go",
      Ref:  "main",
  })
  if err != nil {
      log.Fatal(err)
  }

  fmt.Printf("%s @ %s\n", blame.Path, blame.CommitSHA)
  for _, line := range blame.Lines {
      fmt.Printf("%d\t%s\t%s\t%s\n",
          line.LineNumber, line.CommitSHA[:8], line.AuthorName, line.Summary)
  }

  // Range + rename detection
  rangeBlame, err := repo.GetBlame(context.Background(), storage.BlameOptions{
      Path:        "src/api/auth.go",
      Ref:         "main",
      Ranges:      []string{"10,40"},
      DetectMoves: true,
  })
  ```
</CodeGroup>

## Options

<ParamField path="path" type="string" required>
  Path to the file within the repository.
</ParamField>

<ParamField path="ref" type="string">
  Branch name, tag, or commit SHA. Defaults to the default branch.
</ParamField>

<ParamField path="ephemeral" type="boolean">
  When `true`, resolves the ref under the ephemeral namespace.
</ParamField>

<ParamField path="ranges" type="string[]">
  `git blame -L`-style range specs. Each entry is one `-L` argument: numeric
  ranges (`"10,20"`), regex anchors (`"/getUser/,/^}/"`), relative offsets
  (`"10,+5"`), half-open ranges (`"10,"`, `",20"`), a single line (`"10"`), or
  function names (`":funcname"`). Up to 16 specs per request. Omit to blame
  the whole file. (TypeScript: `ranges`, Python: `ranges`, Go: `Ranges`.)
</ParamField>

<ParamField path="detectMoves" type="boolean">
  Follow the file across renames and copies (passes `-C -C -M` to `git blame`).
</ParamField>

<ParamField path="ttl" type="number">
  Token TTL in seconds.
</ParamField>

## Response

<ResponseField name="ref" type="string">
  The ref the blame ran against. When the request omitted `ref`, this is the repository's default branch.
</ResponseField>

<ResponseField name="path" type="string">
  Echo of the requested file path.
</ResponseField>

<ResponseField name="commitSha" type="string">
  The fully-resolved commit SHA that `ref` pointed to when the blame ran.
</ResponseField>

<ResponseField name="lines" type="array">
  One entry per blamed line, in file order. Each entry has:

  * `lineNumber` — 1-based line number in the file at `ref`
  * `commitSha` — commit that last touched the line
  * `originalLineNumber` — line number in the originating commit (differs after edits)
  * `originalPath` — path in the originating commit (differs after renames when `detectMoves` is on)
  * `previousCommitSha` — parent commit that touched the line; omitted for the initial commit
  * `authorName`, `authorEmail`
  * `authorTime` (parsed `Date` in TypeScript, `datetime` in Python, `time.Time` in Go)
  * `rawAuthorTime` — RFC 3339 string as returned by the server
  * `committerName`, `committerEmail`, `committerTime`, `rawCommitterTime`
  * `summary` — first line of the commit message
</ResponseField>

## Notes

* Commit metadata is duplicated per line in the SDK result; if you need a deduped commit map, group by `commitSha` client-side.
* Each `ranges` entry is one `git blame -L` argument. Supported forms: a single line `"10"`, a numeric range `"10,20"`, an offset `"10,+5"` / `"10,-5"`, a regex `"/getUser/"`, a regex pair `"/start/,/end/"`, regex + offset `"/start/,+30"`, half-open ranges `"10,"` and `",20"`, and `":funcname"` for function-body targeting. Line numbers are 1-based and inclusive; ranges that resolve to lines outside the file return a 400, not a silent clamp. Up to 16 specs per request, each capped at 256 characters (regex content capped at 200).
* Annotated tags are peeled to the underlying commit, so `commitSha` always equals the dereferenced commit (`git rev-parse <ref>^{}`).
* Symlinks blame as a single line of the link-target text. Binary files (including ones that cross git's 8 KiB heuristic via embedded NUL bytes) are blamed as text.
* `path` may not contain NUL bytes.
