Compare commits

...

4 Commits

7 changed files with 2466 additions and 2582 deletions

View File

@@ -1,5 +1,23 @@
# Changelog
## 2025-11-04 - 3.3.1 - fix(getUncommittedDiff)
Avoid false-positive diffs in getUncommittedDiff by detecting symlinked directories and skipping identical files
- Detect files reported as "added" that are actually inside symlinked directories (catch isomorphic-git error: "anticipated to be a tree but it is a blob") and skip them to avoid huge false-positive lists.
- Compare HEAD and workdir file contents and skip entries where contents are identical to filter out permission/timestamp/line-ending false positives.
- Add glob support for excludeFiles via minimatch and skip exact or glob-matching paths during diff collection.
- Files changed: ts/smartgit.classes.gitrepo.ts (symlink detection, content comparison, diff filtering), ts/smartgit.plugins.ts (export minimatch), readme.hints.md (notes).
- Observed impact: false positives reduced dramatically in reported case (1,883 → 2 files); output size reduced from ~59 MB → ~2 KB.
## 2025-11-04 - 3.3.0 - feat(GitRepo)
Add glob-pattern exclusions for getUncommittedDiff and add minimatch; bump dependencies
- getUncommittedDiff now supports glob patterns for excluded files via minimatch (skip files when filepath matches exact or glob pattern).
- Expose minimatch through plugins (ts/smartgit.plugins.ts) so plugin code can use glob matching consistently.
- Add minimatch to dependencies (minimatch ^10.1.1).
- Bump several dependencies: @push.rocks/smartenv to ^6.0.0, @push.rocks/smartfile to ^11.2.7, @push.rocks/smartshell to ^3.3.0, @push.rocks/smartstring to ^4.1.0, isomorphic-git to ^1.34.2.
- Bump devDependencies for build/test tooling: @git.zone/tsbuild ^2.7.1, @git.zone/tsrun ^1.6.2, @git.zone/tstest ^2.7.0.
## 2025-01-04 - 3.2.0 - feat(core)
Enhanced error handling, type safety, and documentation

View File

@@ -1,6 +1,6 @@
{
"name": "@push.rocks/smartgit",
"version": "3.2.1",
"version": "3.3.1",
"description": "A smart wrapper for nodegit that simplifies Git operations in Node.js.",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
@@ -32,21 +32,22 @@
},
"homepage": "https://code.foss.global/push.rocks/smartgit",
"dependencies": {
"@push.rocks/smartenv": "^5.0.13",
"@push.rocks/smartfile": "^11.2.5",
"@push.rocks/smartenv": "^6.0.0",
"@push.rocks/smartfile": "^11.2.7",
"@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartshell": "^3.2.3",
"@push.rocks/smartstring": "^4.0.15",
"@push.rocks/smartshell": "^3.3.0",
"@push.rocks/smartstring": "^4.1.0",
"@push.rocks/smarttime": "^4.1.1",
"@types/diff": "^8.0.0",
"diff": "^8.0.2",
"isomorphic-git": "^1.32.2"
"isomorphic-git": "^1.34.2",
"minimatch": "^10.1.1"
},
"devDependencies": {
"@git.zone/tsbuild": "^2.6.4",
"@git.zone/tsrun": "^1.3.3",
"@git.zone/tstest": "^2.3.2"
"@git.zone/tsbuild": "^2.7.1",
"@git.zone/tsrun": "^1.6.2",
"@git.zone/tstest": "^2.7.0"
},
"private": false,
"files": [

4939
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1,32 @@
# smartgit Project Hints
## Recent Fixes
### getUncommittedDiff() False Positives Fix (2025-11-04)
**Problem**:
- Method was reporting 1,883 diffs when only 1-2 files were actually modified
- Root cause: isomorphic-git's `statusMatrix()` reports files inside symlinked directories as "added" files
- Example: `ghost_local/current` → symlink to `ghost_local/versions/5.129.1` causes all 1,880+ files inside to be reported as changes
**Solution Implemented**:
1. **Symlink detection** (lines 160-184): For files reported as "added" (head=0, workdir≠0), try to read from HEAD anyway. If we get error "anticipated to be a tree but it is a blob", the parent path is a symlink - skip the file entirely.
2. **Content comparison** (lines 196-200): Before creating any diff, check if `headContent === workdirContent`. If identical, skip (catches permission/timestamp/line-ending false positives).
**Results**:
- Reduced false positives from 1,883 → 2 files (99.89% reduction)
- Output size: 59 MB → 2 KB (29,500x reduction)
- Only reports actual content changes
**Files Modified**:
- `ts/smartgit.classes.gitrepo.ts` lines 153-209
**Dependencies Added**:
- `minimatch` for glob pattern support in excludeFiles parameter
## Architecture Notes
- Main class: `Smartgit` (not `SmartGit` - lowercase 'g')
- Must call `await smartgit.init()` before use
- Repository methods: `createRepoByOpen()`, `createRepoByClone()`, `createRepoByInit()`

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartgit',
version: '3.1.1',
version: '3.3.1',
description: 'A smart wrapper for nodegit that simplifies Git operations in Node.js.'
}

View File

@@ -122,8 +122,8 @@ export class GitRepo {
const diffs: string[] = [];
for (const row of statusMatrix) {
const [filepath, head, workdir] = row;
if (excludeFiles.includes(filepath)) {
continue; // Skip excluded files
if (excludeFiles.some(pattern => filepath === pattern || plugins.minimatch(filepath, pattern))) {
continue; // Skip excluded files (supports exact matches and glob patterns)
}
let headContent = '';
@@ -156,6 +156,31 @@ export class GitRepo {
plugins.path.join(this.repoDir, filepath),
'utf8'
);
// Try to read from HEAD anyway - catches false positives from symlinks
// where isomorphic-git reports symlink contents as "added" files
try {
headContent = await plugins.isomorphicGit
.readBlob({
fs: this.smartgitRef.envDeps.fs,
dir: this.repoDir,
oid: await plugins.isomorphicGit.resolveRef({
fs: this.smartgitRef.envDeps.fs,
dir: this.repoDir,
ref: 'HEAD',
}),
filepath,
})
.then((result) => new TextDecoder().decode(result.blob));
} catch (err) {
// Check if this is a symlink false positive
// Error: "was anticipated to be a tree but it is a blob" means parent path is a symlink
if (err.message && err.message.includes('anticipated to be a tree but it is a blob')) {
// This file is inside a symlinked directory - skip it entirely
continue;
}
// Otherwise, file truly doesn't exist in HEAD - leave headContent empty for diff
}
}
// Handle deleted files
@@ -175,6 +200,11 @@ export class GitRepo {
}
if (headContent || workdirContent) {
// Skip files with identical content (filters false positives from statusMatrix)
if (headContent === workdirContent) {
continue;
}
const diff = plugins.diff.createTwoFilesPatch(
filepath,
filepath,

View File

@@ -15,5 +15,6 @@ export { smartenv, smartfile, smartpath, smartpromise, smartstring, smarttime };
// third party
import * as diff from 'diff';
import isomorphicGit from 'isomorphic-git';
import { minimatch } from 'minimatch';
export { diff, isomorphicGit };
export { diff, isomorphicGit, minimatch };