feat(git)!: replace dugite with tsgit, own the unified-diff rendering - #64
Merged
Conversation
Drops the bundled dugite git binary in favor of @scolladon/tsgit, a
pure-TypeScript git implementation with zero native dependencies — no
git binary required on any platform, no more Alpine/musl workaround.
tsgit's diff() returns structured DiffChange data, not patch text, so
smart-diff now materializes blob content via readBlob and renders its
own unified diffs (Myers line-diff + hunk grouping), which also fixes
a latent bug: getDiff and getDiffSummary previously derived counts
from two separate `git diff` passes (--numstat / --name-status) that
could in principle disagree; they now share one blob-diff pass.
Path filtering (no pathspec support in tsgit) moved client-side to a
predicate over the returned DiffChange[]. getCommits now uses tsgit's
log() with all-parent ordering, fixing the previous first-parent-only
range bug for free.
BREAKING CHANGE: createGitClient is now async and returns a tsgit
Repository handle instead of a `{ run(args) }` shell wrapper.
buildDiffPathspecs, buildDiffShapingGitArgs, and parseDiffSummary are
removed in favor of buildPathFilterPredicate, direct renderer options,
and buildFileSummary/mergeFileSummariesByPath/summarizeFiles. Node
engine requirement bumped to >=22.22.1 (tsgit's actual minimum).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
getRepoRoot() returns the canonical path, but macOS symlinks /var to /private/var — the raw mkdtemp path never matched on that platform. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
realpathSync (JS fallback) resolves symlinks but not NTFS 8.3 short-name aliasing, which is what GitHub's Windows runners hit (TEMP resolves under RUNNER~1 but tsgit's getRepoRoot() returns the long form runneradmin). realpathSync.native calls the OS's own canonicalization and handles both. Also re-normalize both sides at assertion time in the two comparisons, on top of normalizing at fixture-creation time. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
dugitegit binary for@scolladon/tsgit, a pure-TypeScript git implementation with zero native dependencies — no git binary required on any platform, no more Alpine/musl workaround.diff()returns structuredDiffChangedata, not patch text, so smart-diff now materializes blob content viareadBloband renders its own unified diffs (Myers line-diff + hunk grouping). This also fixes a latent correctness gap:getDiffandgetDiffSummarypreviously derived counts from two separategit diffpasses (--numstat/--name-status) that could in principle disagree; they now share one blob-diff pass, so they can't.diff()has no pathspec support) moved client-side to a predicate over the returnedDiffChange[].getCommitsnow uses tsgit'slog()with all-parent date ordering, fixing the previous first-parent-only range bug for free.Breaking changes (major version)
createGitClientis now async, returning a tsgitRepositoryhandle instead of a{ run(args) }shell wrapper. Callgit.dispose()when done.buildDiffPathspecs,buildDiffShapingGitArgs, andparseDiffSummaryare removed, replaced bybuildPathFilterPredicate, direct renderer options, andbuildFileSummary/mergeFileSummariesByPath/summarizeFiles.>=22.22.1(tsgit's actual minimum, tighter than the previous>=22).Full details in the README's "Migrating from 3.x → 4.x" section.
Test plan
npm run lint(biome) cleantsc --noEmitcleannpm test— 320 tests passing, 100% statements/branches/functions/lines coveragenpx knipclean (no unused deps/exports)npm run buildsucceeds (CLI + library bundles)🤖 Generated with Claude Code