0
# Diff and Status
1
2
File difference computation and working directory status tracking. These operations help understand changes between different states of the repository, including modifications, additions, and deletions of files.
3
4
## Capabilities
5
6
### Diff Operations
7
8
Compare different states of the repository to identify changes.
9
10
```javascript { .api }
11
/**
12
* Diff tree to tree
13
* @param {Repository} repo - Repository instance
14
* @param {Tree} oldTree - Old tree to compare from
15
* @param {Tree} newTree - New tree to compare to
16
* @param {DiffOptions} opts - Diff options
17
* @returns {Promise<Diff>} Diff object
18
*/
19
Diff.treeToTree(repo, oldTree, newTree, opts): Promise<Diff>;
20
21
/**
22
* Diff tree to index
23
* @param {Repository} repo - Repository instance
24
* @param {Tree} oldTree - Tree to compare from
25
* @param {Index} index - Index to compare to
26
* @param {DiffOptions} opts - Diff options
27
* @returns {Promise<Diff>} Diff object
28
*/
29
Diff.treeToIndex(repo, oldTree, index, opts): Promise<Diff>;
30
31
/**
32
* Diff index to working directory
33
* @param {Repository} repo - Repository instance
34
* @param {Index} index - Index to compare from
35
* @param {DiffOptions} opts - Diff options
36
* @returns {Promise<Diff>} Diff object
37
*/
38
Diff.indexToWorkdir(repo, index, opts): Promise<Diff>;
39
40
/**
41
* Diff tree to working directory
42
* @param {Repository} repo - Repository instance
43
* @param {Tree} oldTree - Tree to compare from
44
* @param {DiffOptions} opts - Diff options
45
* @returns {Promise<Diff>} Diff object
46
*/
47
Diff.treeToWorkdir(repo, oldTree, opts): Promise<Diff>;
48
49
/**
50
* Diff tree to working directory with index
51
* @param {Repository} repo - Repository instance
52
* @param {Tree} oldTree - Tree to compare from
53
* @param {DiffOptions} opts - Diff options
54
* @returns {Promise<Diff>} Diff object
55
*/
56
Diff.treeToWorkdirWithIndex(repo, oldTree, opts): Promise<Diff>;
57
58
/**
59
* Diff two blobs
60
* @param {Blob} oldBlob - Old blob to compare from
61
* @param {string} oldAsPath - Path name for old blob
62
* @param {Blob} newBlob - New blob to compare to
63
* @param {string} newAsPath - Path name for new blob
64
* @param {DiffOptions} opts - Diff options
65
* @param {Function} fileCallback - File callback
66
* @param {Function} binaryCallback - Binary callback
67
* @param {Function} hunkCallback - Hunk callback
68
* @param {Function} lineCallback - Line callback
69
* @returns {Promise<void>}
70
*/
71
Diff.blobs(oldBlob, oldAsPath, newBlob, newAsPath, opts, fileCallback, binaryCallback, hunkCallback, lineCallback): Promise<void>;
72
73
/**
74
* Diff blob to buffer
75
* @param {Blob} oldBlob - Old blob to compare from
76
* @param {string} oldAsPath - Path name for old blob
77
* @param {Buffer} buffer - Buffer to compare to
78
* @param {string} bufferAsPath - Path name for buffer
79
* @param {DiffOptions} opts - Diff options
80
* @param {Function} fileCallback - File callback
81
* @param {Function} binaryCallback - Binary callback
82
* @param {Function} hunkCallback - Hunk callback
83
* @param {Function} lineCallback - Line callback
84
* @returns {Promise<void>}
85
*/
86
Diff.blobToBuffer(oldBlob, oldAsPath, buffer, bufferAsPath, opts, fileCallback, binaryCallback, hunkCallback, lineCallback): Promise<void>;
87
```
88
89
**Usage Examples:**
90
91
```javascript
92
const NodeGit = require('nodegit');
93
94
const repo = await NodeGit.Repository.open('./my-repo');
95
96
// Compare two commits
97
const commit1 = await repo.getHeadCommit();
98
const commit2 = await commit1.parent(0);
99
100
const tree1 = await commit1.getTree();
101
const tree2 = await commit2.getTree();
102
103
const diff = await NodeGit.Diff.treeToTree(repo, tree2, tree1, null);
104
console.log('Number of changes:', diff.numDeltas());
105
106
// Compare index to working directory
107
const index = await repo.index();
108
const workdirDiff = await NodeGit.Diff.indexToWorkdir(repo, index, null);
109
110
console.log('Unstaged changes:', workdirDiff.numDeltas());
111
112
// Compare tree to working directory
113
const headTree = await (await repo.getHeadCommit()).getTree();
114
const fullDiff = await NodeGit.Diff.treeToWorkdir(repo, headTree, null);
115
116
console.log('All changes since last commit:', fullDiff.numDeltas());
117
```
118
119
### Diff Instance Methods
120
121
Methods available on Diff objects to examine and process changes.
122
123
```javascript { .api }
124
/**
125
* Get number of deltas (changed files)
126
* @returns {number} Number of changed files
127
*/
128
diff.numDeltas(): number;
129
130
/**
131
* Get delta by index
132
* @param {number} idx - Delta index
133
* @returns {DiffDelta} Delta object
134
*/
135
diff.getDelta(idx): DiffDelta;
136
137
/**
138
* Get patches for diff
139
* @returns {Promise<ConvenientPatch[]>} Array of patch objects
140
*/
141
diff.patches(): Promise<ConvenientPatch[]>;
142
143
/**
144
* Convert diff to string
145
* @returns {string} Diff as string
146
*/
147
diff.toString(): string;
148
149
/**
150
* Convert diff to buffer
151
* @param {number} format - Output format
152
* @returns {Promise<Buffer>} Diff as buffer
153
*/
154
diff.toBuf(format): Promise<Buffer>;
155
156
/**
157
* Iterate through diff
158
* @param {Function} fileCallback - Called for each file
159
* @param {Function} binaryCallback - Called for binary files
160
* @param {Function} hunkCallback - Called for each hunk
161
* @param {Function} lineCallback - Called for each line
162
* @returns {Promise<void>}
163
*/
164
diff.foreach(fileCallback, binaryCallback, hunkCallback, lineCallback): Promise<void>;
165
166
/**
167
* Find similar files (renames/copies)
168
* @param {DiffFindOptions} opts - Find options
169
* @returns {Promise<void>}
170
*/
171
diff.findSimilar(opts): Promise<void>;
172
173
/**
174
* Merge diffs
175
* @param {Diff} from - Diff to merge from
176
* @returns {Promise<void>}
177
*/
178
diff.merge(from): Promise<void>;
179
180
/**
181
* Get best similarity score
182
* @returns {number} Best similarity (0-100)
183
*/
184
diff.getBestSimilarity(): number;
185
```
186
187
**Usage Examples:**
188
189
```javascript
190
// Examine diff details
191
const diff = await NodeGit.Diff.treeToTree(repo, tree1, tree2, null);
192
193
// Look for renames
194
await diff.findSimilar({
195
flags: NodeGit.Diff.FIND.RENAMES
196
});
197
198
// Get patches with details
199
const patches = await diff.patches();
200
patches.forEach(async function(patch) {
201
const oldFile = patch.oldFile();
202
const newFile = patch.newFile();
203
204
console.log('File:', newFile.path());
205
console.log('Status:', patch.status());
206
console.log('Lines added:', patch.lineStats().total_additions);
207
console.log('Lines deleted:', patch.lineStats().total_deletions);
208
209
// Get hunks for this patch
210
const hunks = await patch.hunks();
211
hunks.forEach(async function(hunk) {
212
console.log('Hunk header:', hunk.header());
213
214
// Get lines for this hunk
215
const lines = await hunk.lines();
216
lines.forEach(function(line) {
217
const origin = String.fromCharCode(line.origin());
218
console.log(origin + line.content());
219
});
220
});
221
});
222
223
// Iterate through diff manually
224
await diff.foreach(
225
function(delta, progress) {
226
console.log('File changed:', delta.newFile().path());
227
},
228
function(delta, progress) {
229
console.log('Binary file:', delta.newFile().path());
230
},
231
function(delta, hunk) {
232
console.log('Hunk:', hunk.header().trim());
233
},
234
function(delta, hunk, line) {
235
const origin = String.fromCharCode(line.origin());
236
console.log(origin + line.content().trim());
237
}
238
);
239
```
240
241
### Status Operations
242
243
Get working directory and index status information.
244
245
```javascript { .api }
246
/**
247
* Get file status
248
* @param {Repository} repo - Repository instance
249
* @param {string} path - File path
250
* @returns {Promise<number>} Status flags
251
*/
252
Status.file(repo, path): Promise<number>;
253
254
/**
255
* Iterate through all status entries
256
* @param {Repository} repo - Repository instance
257
* @param {Function} callback - Status callback function
258
* @returns {Promise<void>}
259
*/
260
Status.foreach(repo, callback): Promise<void>;
261
262
/**
263
* Check if path should be ignored
264
* @param {Repository} repo - Repository instance
265
* @param {string} path - File path
266
* @returns {Promise<boolean>} True if should be ignored
267
*/
268
Status.shouldIgnore(repo, path): Promise<boolean>;
269
```
270
271
### Repository Status Methods
272
273
Convenience methods on Repository for status operations.
274
275
```javascript { .api }
276
/**
277
* Get repository status
278
* @returns {Promise<StatusFile[]>} Array of status files
279
*/
280
repository.getStatus(): Promise<StatusFile[]>;
281
282
/**
283
* Get status with options
284
* @param {StatusOptions} opts - Status options
285
* @returns {Promise<StatusFile[]>} Array of status files
286
*/
287
repository.getStatusExt(opts): Promise<StatusFile[]>;
288
289
/**
290
* Check if path is ignored
291
* @param {string} path - File path to check
292
* @returns {Promise<boolean>} True if ignored
293
*/
294
repository.isIgnored(path): Promise<boolean>;
295
```
296
297
**Usage Examples:**
298
299
```javascript
300
// Get repository status
301
const statusFiles = await repo.getStatus();
302
303
statusFiles.forEach(function(file) {
304
const path = file.path();
305
const flags = file.statusFlags();
306
307
console.log('File:', path);
308
309
if (flags & NodeGit.Status.STATUS.INDEX_NEW) {
310
console.log(' New in index');
311
}
312
if (flags & NodeGit.Status.STATUS.INDEX_MODIFIED) {
313
console.log(' Modified in index');
314
}
315
if (flags & NodeGit.Status.STATUS.INDEX_DELETED) {
316
console.log(' Deleted in index');
317
}
318
if (flags & NodeGit.Status.STATUS.WT_NEW) {
319
console.log(' New in working tree');
320
}
321
if (flags & NodeGit.Status.STATUS.WT_MODIFIED) {
322
console.log(' Modified in working tree');
323
}
324
if (flags & NodeGit.Status.STATUS.WT_DELETED) {
325
console.log(' Deleted in working tree');
326
}
327
if (flags & NodeGit.Status.STATUS.IGNORED) {
328
console.log(' Ignored');
329
}
330
});
331
332
// Check specific file status
333
const fileStatus = await NodeGit.Status.file(repo, 'README.md');
334
if (fileStatus & NodeGit.Status.STATUS.WT_MODIFIED) {
335
console.log('README.md has been modified');
336
}
337
338
// Check if file is ignored
339
const isIgnored = await repo.isIgnored('node_modules/package.json');
340
if (isIgnored) {
341
console.log('File is ignored by .gitignore');
342
}
343
344
// Iterate through status
345
await NodeGit.Status.foreach(repo, function(path, flags) {
346
console.log('Status for', path + ':', flags);
347
});
348
```
349
350
### Status with Options
351
352
Get status with filtering and configuration options.
353
354
```javascript { .api }
355
/**
356
* Get extended status with options
357
* @param {StatusOptions} opts - Status options
358
* @returns {Promise<StatusFile[]>} Filtered status files
359
*/
360
repository.getStatusExt(opts): Promise<StatusFile[]>;
361
```
362
363
**Usage Examples:**
364
365
```javascript
366
// Get status with options
367
const statusOptions = {
368
flags:
369
NodeGit.Status.OPT.INCLUDE_UNTRACKED |
370
NodeGit.Status.OPT.RECURSE_UNTRACKED_DIRS,
371
pathspec: ['src/', 'docs/']
372
};
373
374
const filteredStatus = await repo.getStatusExt(statusOptions);
375
376
filteredStatus.forEach(function(file) {
377
console.log('Filtered status:', file.path(), file.statusFlags());
378
});
379
380
// Include ignored files
381
const allStatus = await repo.getStatusExt({
382
flags:
383
NodeGit.Status.OPT.INCLUDE_IGNORED |
384
NodeGit.Status.OPT.INCLUDE_UNTRACKED
385
});
386
387
console.log('All files including ignored:', allStatus.length);
388
```
389
390
### StatusFile Methods
391
392
Methods available on StatusFile objects.
393
394
```javascript { .api }
395
/**
396
* Get file path
397
* @returns {string} File path
398
*/
399
statusFile.path(): string;
400
401
/**
402
* Get status flags
403
* @returns {number} Status flags bitmask
404
*/
405
statusFile.statusFlags(): number;
406
407
/**
408
* Get diff from HEAD to index
409
* @returns {DiffDelta} HEAD to index diff
410
*/
411
statusFile.headToIndex(): DiffDelta;
412
413
/**
414
* Get diff from index to working directory
415
* @returns {DiffDelta} Index to working directory diff
416
*/
417
statusFile.indexToWorkdir(): DiffDelta;
418
```
419
420
**Usage Examples:**
421
422
```javascript
423
const statusFiles = await repo.getStatus();
424
425
statusFiles.forEach(function(file) {
426
console.log('Path:', file.path());
427
428
const headToIndex = file.headToIndex();
429
if (headToIndex) {
430
console.log(' Staged change:', headToIndex.status());
431
}
432
433
const indexToWorkdir = file.indexToWorkdir();
434
if (indexToWorkdir) {
435
console.log(' Unstaged change:', indexToWorkdir.status());
436
}
437
});
438
```
439
440
## Types
441
442
```javascript { .api }
443
interface DiffOptions {
444
flags: number;
445
ignoreSubmodules: number;
446
pathspec: string[];
447
notifyCallback: Function;
448
progressCallback: Function;
449
contextLines: number;
450
interhunkLines: number;
451
idAbbrev: number;
452
maxSize: number;
453
oldPrefix: string;
454
newPrefix: string;
455
}
456
457
interface DiffFindOptions {
458
flags: number;
459
renameThreshold: number;
460
renameFromRewriteThreshold: number;
461
copyThreshold: number;
462
breakRewriteThreshold: number;
463
renameLimit: number;
464
metric: Function;
465
}
466
467
interface StatusOptions {
468
flags: number;
469
pathspec: string[];
470
baseline: Tree;
471
}
472
473
interface DiffDelta {
474
status(): number;
475
flags(): number;
476
similarity(): number;
477
nfiles(): number;
478
oldFile(): DiffFile;
479
newFile(): DiffFile;
480
}
481
482
interface DiffFile {
483
path(): string;
484
size(): number;
485
flags(): number;
486
mode(): number;
487
id(): Oid;
488
}
489
490
interface ConvenientPatch {
491
oldFile(): DiffFile;
492
newFile(): DiffFile;
493
status(): number;
494
lineStats(): { total_context: number, total_additions: number, total_deletions: number };
495
hunks(): Promise<ConvenientHunk[]>;
496
}
497
498
interface ConvenientHunk {
499
size(): number;
500
header(): string;
501
lines(): Promise<DiffLine[]>;
502
}
503
504
interface DiffLine {
505
origin(): number;
506
oldLineno(): number;
507
newLineno(): number;
508
numLines(): number;
509
content(): string;
510
contentOffset(): number;
511
}
512
513
// Status flags
514
Status.STATUS = {
515
CURRENT: 0,
516
INDEX_NEW: 1,
517
INDEX_MODIFIED: 2,
518
INDEX_DELETED: 4,
519
INDEX_RENAMED: 8,
520
INDEX_TYPECHANGE: 16,
521
WT_NEW: 128,
522
WT_MODIFIED: 256,
523
WT_DELETED: 512,
524
WT_TYPECHANGE: 1024,
525
WT_RENAMED: 2048,
526
IGNORED: 16384,
527
CONFLICTED: 32768
528
};
529
530
// Status options
531
Status.OPT = {
532
INCLUDE_UNTRACKED: 1,
533
INCLUDE_IGNORED: 2,
534
INCLUDE_UNMODIFIED: 4,
535
EXCLUDE_SUBMODULES: 8,
536
RECURSE_UNTRACKED_DIRS: 16,
537
DISABLE_PATHSPEC_MATCH: 32,
538
RECURSE_IGNORED_DIRS: 64,
539
RENAMES_HEAD_TO_INDEX: 128,
540
RENAMES_INDEX_TO_WORKDIR: 256,
541
SORT_CASE_SENSITIVELY: 512,
542
SORT_CASE_INSENSITIVELY: 1024,
543
RENAMES_FROM_REWRITES: 2048,
544
NO_REFRESH: 4096,
545
UPDATE_INDEX: 8192
546
};
547
548
// Diff find flags
549
Diff.FIND = {
550
BY_CONFIG: 0,
551
RENAMES: 1,
552
RENAMES_AND_COPIES: 2,
553
COPIES: 4,
554
COPIES_HARDER: 8,
555
RENAMES_FROM_REWRITES: 16,
556
BREAK_REWRITES: 32,
557
AND_BREAK_REWRITES: 48,
558
FOR_UNTRACKED: 64,
559
ALL: 255,
560
IGNORE_LEADING_WHITESPACE: 0,
561
IGNORE_WHITESPACE: 4194304,
562
DONT_IGNORE_WHITESPACE: 8388608,
563
EXACT_MATCH_ONLY: 16777216,
564
BREAK_REWRITES_FOR_RENAMES_ONLY: 33554432,
565
REMOVE_UNMODIFIED: 67108864
566
};
567
568
// Delta status
569
Diff.DELTA = {
570
UNMODIFIED: 0,
571
ADDED: 1,
572
DELETED: 2,
573
MODIFIED: 3,
574
RENAMED: 4,
575
COPIED: 5,
576
IGNORED: 6,
577
UNTRACKED: 7,
578
TYPECHANGE: 8,
579
UNREADABLE: 9,
580
CONFLICTED: 10
581
};
582
```