vcs-diff 0.4.0

Parse and model Git-format unified diffs in pure Rust (no git binary required) — the diff types shared across the vcs-toolkit-rs wrappers.
Documentation
# Changelog — vcs-diff

All notable changes to the `vcs-diff` crate are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this crate adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
This crate is versioned and published independently of the other workspace
crates; tag releases as `vcs-diff-v<version>`.

## [Unreleased]

### Added
-

### Changed
-

### Fixed
-

## [0.4.0] - 2026-07-03

### Changed

- refactor(diff): hoist shared DiffSpec into vcs-diff (dedup git+jj)
- Release: vcs-diff v0.3.0, vcs-cli-support v0.3.0, vcs-git v0.7.0, vcs-jj v0.7.0, vcs-github v0.7.0, vcs-gitlab v0.3.0, vcs-gitea v0.3.0, vcs-forge v0.3.0, vcs-testkit v0.3.0, vcs-core v0.5.0, vcs-watch v0.3.0, vcs-mcp v0.3.0


### Changed

- deps: processkit 0.10.1 — testing-module imports, program-aware cassettes, cancellation core, Signalled/Timeout diagnostics
- meta: discoverability — sharpen descriptions/keywords/categories + README intro + GitHub topics
- Release: vcs-diff v0.2.0, vcs-cli-support v0.2.0, vcs-git v0.6.0, vcs-jj v0.6.0, vcs-github v0.6.0, vcs-gitlab v0.2.0, vcs-gitea v0.2.0, vcs-forge v0.2.0, vcs-testkit v0.2.0, vcs-core v0.4.0, vcs-watch v0.2.0, vcs-mcp v0.2.0


### Fixed

- fix(diff+mcp): drop empty-path diff sections; validate mcp --allow-tools names
- fix(diff): unquote git-quoted paths so non-ASCII filenames aren't dropped
- fix(git): blame on SHA-256 repos; remote_head_branch/upstream surface timeouts


### Added

- feat(mcp): vcs-mcp — MCP server over the facades (Wave F)


### Changed

- refactor: extract vcs-diff + vcs-cli-support foundational crates
- Release: vcs-diff v0.1.0, vcs-cli-support v0.1.0, vcs-git v0.5.0, vcs-jj v0.5.0, vcs-github v0.5.0, vcs-gitlab v0.1.0, vcs-gitea v0.1.0, vcs-forge v0.1.0, vcs-testkit v0.1.0, vcs-core v0.3.0, vcs-watch v0.1.0, vcs-mcp v0.1.0


### Fixed

- fix: review follow-ups — docs, CI, Windows paths, mappers, and tests
- fix: whole-solution review follow-ups — parser/config robustness, backend parity, watch worktrees, forge contracts

## [0.3.0] - 2026-07-03

### Added
- **`DiffSpec`** — the diff-request enum (`WorkingTree` / `Rev(String)`) that a
  wrapper's `diff`/`diff_text` takes, hoisted here from `vcs-git`/`vcs-jj` so both
  backends share one definition (re-exported as `vcs_git::DiffSpec` /
  `vcs_jj::DiffSpec`). Deliberately **not** `#[non_exhaustive]`: each backend must
  interpret every variant, so adding one is a breaking change caught at compile
  time. This crate defines it but has no method that consumes it.

### Changed
-

### Fixed
-

## [0.2.0] - 2026-06-27

### Added
-

### Changed
-

### Fixed
- **Git-quoted paths are now decoded instead of dropping the file.** git C-quotes a
  path (wraps it in `"…"` with `\NNN` octal/`\t`/`\"`/`\\` escapes) when it contains a
  control byte, a quote/backslash, or — with the default `core.quotePath=true`**any
  non-ASCII byte** (e.g. `café.txt``"caf\303\251.txt"`). The parser only matched the
  *unquoted* `+++ b/` / `--- a/` / `rename` / `" b/"` forms, so a file with a non-ASCII
  (or tab/quote) name was **silently omitted** from `parse_diff`. It now unquotes the
  path on every source (`rename to`/`from`, `+++`/`---`, and the `diff --git` header
  fallback), so internationalised filenames parse correctly.
- A diff section whose path can't be resolved to a non-empty string (a malformed
  `diff --git … b/` with no path, and no `+++`/`---`/rename line) is now **dropped**
  rather than yielding a `FileDiff` with an empty `path`. A present-but-empty
  `+++ b/`/`--- a/` likewise falls through to the next path source instead of
  producing an empty path.

## [0.1.0] - 2026-06-08

### Added
- Initial release: the shared git-format unified-diff model and parser —
  `ChangeKind`, `DiffLine`, `Hunk`, `FileDiff`, `DiffStat`, and `parse_diff`  plus the `Version` type and `parse_dotted_version`. Extracted from the
  byte-identical copies previously carried by `vcs-git` and `vcs-jj` (and the
  third `ChangeKind`/`DiffStat` copy in `vcs-core`), so the parser and the
  version `Ord` can no longer drift between backends. Dependency-free (std
  only); property-tested for panic-freedom.
- Optional `serde` feature: derives `serde::Serialize` on the public DTOs
  (`DiffStat`, `ChangeKind`, `DiffLine`, `Hunk`, `FileDiff`, `Version`) so a
  consumer (e.g. `vcs-mcp`) can emit them as JSON. **Off by default** — the crate
  stays std-only unless the feature is enabled; enums serialize as their variant
  names, structs keep their snake_case field names.

### Changed
-

### Fixed
-

[Unreleased]: https://github.com/ZelAnton/vcs-toolkit-rs/compare/vcs-diff-v0.4.0...HEAD
[0.4.0]: https://github.com/ZelAnton/vcs-toolkit-rs/compare/vcs-diff-v0.3.0...vcs-diff-v0.4.0
[0.3.0]: https://github.com/ZelAnton/vcs-toolkit-rs/compare/vcs-diff-v0.2.0...vcs-diff-v0.3.0
[0.2.0]: https://github.com/ZelAnton/vcs-toolkit-rs/compare/vcs-diff-v0.1.0...vcs-diff-v0.2.0
[0.1.0]: https://github.com/ZelAnton/vcs-toolkit-rs/releases/tag/vcs-diff-v0.1.0