Skip to content

Commit 9b3f0d0

Browse files
committed
Added diff functions with options parameter.
Allows options for diffs so that we can do things like exclude whitespace for example.
1 parent b4874be commit 9b3f0d0

File tree

3 files changed

+174
-2
lines changed

3 files changed

+174
-2
lines changed

lib/commit.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,19 @@ Commit.prototype.parents = function() {
173173
* @return {Array<Diff>} an array of diffs
174174
*/
175175
Commit.prototype.getDiff = function(callback) {
176+
return this.getDiffWithOptions(null, callback);
177+
};
178+
179+
/**
180+
* Generate an array of diff trees showing changes between this commit
181+
* and its parent(s).
182+
*
183+
* @async
184+
* @param {Object} options
185+
* @param {Function} callback
186+
* @return {Array<Diff>} an array of diffs
187+
*/
188+
Commit.prototype.getDiffWithOptions = function(options, callback) {
176189
var commit = this;
177190

178191
return commit.getTree().then(function(thisTree) {
@@ -181,7 +194,7 @@ Commit.prototype.getDiff = function(callback) {
181194
if (parents.length) {
182195
diffs = parents.map(function(parent) {
183196
return parent.getTree().then(function(parentTree) {
184-
return thisTree.diff(parentTree);
197+
return thisTree.diffWithOptions(parentTree, options);
185198
});
186199
});
187200
} else {

lib/tree.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,19 @@ Tree.lookup = LookupWrapper(Tree);
2525
* @return {DiffList}
2626
*/
2727
Tree.prototype.diff = function(tree, callback) {
28-
return Diff.treeToTree(this.repo, tree, this, null).then(function(diff) {
28+
return this.diffWithOptions(tree, null, callback);
29+
};
30+
31+
/**
32+
* Diff two trees with options
33+
* @async
34+
* @param {Tree} tree to diff against
35+
* @param {Object} options
36+
* @param {Function} callback
37+
* @return {DiffList}
38+
*/
39+
Tree.prototype.diffWithOptions = function(tree, options, callback) {
40+
return Diff.treeToTree(this.repo, tree, this, options).then(function(diff) {
2941
if (typeof callback === "function") {
3042
callback(null, diff);
3143
}

test/tests/commit.js

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ var exec = promisify(function(command, opts, callback) {
1313
describe("Commit", function() {
1414
var NodeGit = require("../../");
1515
var Repository = NodeGit.Repository;
16+
var Diff = NodeGit.Diff;
1617

1718
var reposPath = local("../repos/workdir");
1819
var oid = "fce88902e66c72b5b93e75bdb5ae717038b221f6";
@@ -29,6 +30,56 @@ describe("Commit", function() {
2930
});
3031
}
3132

33+
function commitFile(repo, fileName, fileContent, commitMessage) {
34+
var index;
35+
var treeOid;
36+
var parent;
37+
38+
return fse.writeFile(path.join(repo.workdir(), fileName), fileContent)
39+
.then(function() {
40+
return repo.openIndex();
41+
})
42+
.then(function(indexResult) {
43+
index = indexResult;
44+
return index.read(1);
45+
})
46+
.then(function() {
47+
return index.addByPath(fileName);
48+
})
49+
.then(function() {
50+
return index.write();
51+
})
52+
.then(function() {
53+
return index.writeTree();
54+
})
55+
.then(function(oidResult) {
56+
treeOid = oidResult;
57+
return NodeGit.Reference.nameToId(repo, "HEAD");
58+
})
59+
.then(function(head) {
60+
return repo.getCommit(head);
61+
})
62+
.then(function(parentResult) {
63+
parent = parentResult;
64+
return Promise.all([
65+
NodeGit.Signature.create("Foo Bar", "foo@bar.com", 123456789, 60),
66+
NodeGit.Signature.create("Foo A Bar", "foo@bar.com", 987654321, 90)
67+
]);
68+
})
69+
.then(function(signatures) {
70+
var author = signatures[0];
71+
var committer = signatures[1];
72+
73+
return repo.createCommit(
74+
"HEAD",
75+
author,
76+
committer,
77+
"message",
78+
treeOid,
79+
[parent]);
80+
});
81+
}
82+
3283
function undoCommit() {
3384
return exec("git reset --hard HEAD~1", {cwd: reposPath});
3485
}
@@ -443,6 +494,102 @@ describe("Commit", function() {
443494
});
444495
});
445496

497+
// it("can get the commit diff in large context", function() {
498+
// For displaying the full file we can set context_lines of options.
499+
// Eventually this should work, but right now there is a
500+
// comment in diff.c in libgit2 of "/* TODO: parse thresholds */"
501+
// It will add the "--unified" but not with the "=x" part.
502+
// options.context_lines = 20000;
503+
// });
504+
505+
it("can get the commit diff without whitespace", function() {
506+
var repo;
507+
var options = {};
508+
var GIT_DIFF_IGNORE_WHITESPACE = (1 << 22);
509+
options.flags = GIT_DIFF_IGNORE_WHITESPACE;
510+
511+
var fileName = "whitespacetest.txt";
512+
var fileContent = "line a\nline b\nline c\nline d\n line e\nline f\n" +
513+
"line g\nline h\nline i\n line j\nline k\nline l\n" +
514+
"line m\nline n\n line o\nline p\nline q\n" +
515+
"line r\nline s\nline t\nline u\nline v\nline w\n" +
516+
"line x\nline y\nline z\n";
517+
var changedFileContent = "line a\nline b\n line c\nline d\n" +
518+
"line e\nline f\nline g\n line h\nline i\nline j\n" +
519+
"line k\nline l\nline m\nline n\nline o\nlinep\n" +
520+
" line q\nline r\nline s\nline t\n\nline u\n" +
521+
"line v1\nline w\nline x\n \nline y\nline z\n";
522+
523+
function getLineText(line) {
524+
return line.rawContent().substring(0, line.contentLen());
525+
}
526+
527+
return NodeGit.Repository.open(reposPath)
528+
.then(function(repoResult) {
529+
repo = repoResult;
530+
return commitFile(repo, fileName, fileContent, "commit this");
531+
})
532+
.then(function(){
533+
return commitFile(repo, fileName, changedFileContent, "commit that");
534+
})
535+
.then (function() {
536+
return repo.getHeadCommit();
537+
})
538+
.then (function(wsCommit) {
539+
return wsCommit.getDiffWithOptions(options);
540+
})
541+
.then(function(diff) {
542+
assert.equal(diff.length, 1);
543+
return diff[0].patches();
544+
})
545+
.then(function(patches) {
546+
assert.equal(patches.length, 1);
547+
var patch = patches[0];
548+
549+
assert.equal(patch.oldFile().path(), fileName);
550+
assert.equal(patch.newFile().path(), fileName);
551+
assert.ok(patch.isModified());
552+
553+
return patch.hunks();
554+
})
555+
.then(function(hunks) {
556+
return hunks[0].lines();
557+
})
558+
.then(function(lines) {
559+
//check all hunk lines
560+
assert.equal(lines.length, 12);
561+
assert.equal(lines[0].origin(), Diff.LINE.CONTEXT);
562+
assert.equal(lines[1].contentLen(), 9);
563+
564+
assert.equal(getLineText(lines[1]), "line s\n");
565+
assert.equal(lines[1].origin(), Diff.LINE.CONTEXT);
566+
assert.equal(lines[2].origin(), Diff.LINE.CONTEXT);
567+
568+
assert.equal(lines[3].contentLen(), 1);
569+
assert.equal(getLineText(lines[3]), "\n");
570+
assert.equal(lines[3].origin(), Diff.LINE.ADDITION);
571+
572+
assert.equal(lines[4].origin(), Diff.LINE.CONTEXT);
573+
574+
assert.equal(lines[5].contentLen(), 7);
575+
assert.equal(getLineText(lines[5]), "line v\n");
576+
assert.equal(lines[5].origin(), Diff.LINE.DELETION);
577+
assert.equal(lines[6].contentLen(), 8);
578+
assert.equal(getLineText(lines[6]), "line v1\n");
579+
assert.equal(lines[6].origin(), Diff.LINE.ADDITION);
580+
581+
assert.equal(lines[7].origin(), Diff.LINE.CONTEXT);
582+
assert.equal(lines[8].origin(), Diff.LINE.CONTEXT);
583+
584+
assert.equal(lines[9].contentLen(), 4);
585+
assert.equal(getLineText(lines[9]), "\t\t\t\n");
586+
assert.equal(lines[9].origin(), Diff.LINE.ADDITION);
587+
588+
assert.equal(lines[10].origin(), Diff.LINE.CONTEXT);
589+
assert.equal(lines[11].origin(), Diff.LINE.CONTEXT);
590+
});
591+
});
592+
446593
describe("Commit's Author", function() {
447594
before(function() {
448595
this.author = this.commit.author();

0 commit comments

Comments
 (0)