Skip to content

Commit c667e1a

Browse files
committed
Rename detection for git log + tests
1 parent 4bfba56 commit c667e1a

File tree

2 files changed

+199
-3
lines changed

2 files changed

+199
-3
lines changed

generate/templates/manual/revwalk/file_history_walk.cc

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,14 @@ void GitRevwalk::FileHistoryWalkWorker::Execute()
8080
}
8181
}
8282

83+
if ((baton->error_code = git_diff_find_similar(diffs, NULL)) != GIT_OK) {
84+
git_commit_free(nextCommit);
85+
git_commit_free(parent);
86+
break;
87+
}
88+
8389
bool flag = false;
90+
bool doRenamedPass = false;
8491
unsigned int numDeltas = git_diff_num_deltas(diffs);
8592
for (unsigned int j = 0; j < numDeltas; ++j) {
8693
git_patch *nextPatch;
@@ -99,16 +106,20 @@ void GitRevwalk::FileHistoryWalkWorker::Execute()
99106
bool isEqualNewFile = !strcmp(delta->new_file.path, baton->file_path);
100107

101108
if (isEqualNewFile) {
109+
if (delta->status == GIT_DELTA_ADDED) {
110+
doRenamedPass = true;
111+
break;
112+
}
102113
std::pair<git_commit *, std::pair<char *, git_delta_t> > *historyEntry;
103114
if (!isEqualOldFile) {
104115
historyEntry = new std::pair<git_commit *, std::pair<char *, git_delta_t> >(
105116
nextCommit,
106-
std::make_pair<char *, git_delta_t>(strdup(delta->old_file.path), delta->status)
117+
std::pair<char *, git_delta_t>(strdup(delta->old_file.path), delta->status)
107118
);
108119
} else {
109120
historyEntry = new std::pair<git_commit *, std::pair<char *, git_delta_t> >(
110121
nextCommit,
111-
std::make_pair<char *, git_delta_t>(strdup(delta->new_file.path), delta->status)
122+
std::pair<char *, git_delta_t>(strdup(delta->new_file.path), delta->status)
112123
);
113124
}
114125
baton->out->push_back(historyEntry);
@@ -122,6 +133,53 @@ void GitRevwalk::FileHistoryWalkWorker::Execute()
122133
}
123134
}
124135

136+
if (
137+
doRenamedPass &&
138+
(baton->error_code = git_diff_find_similar(diffs, NULL)) == GIT_OK
139+
) {
140+
flag = false;
141+
numDeltas = git_diff_num_deltas(diffs);
142+
for (unsigned int j = 0; j < numDeltas; ++j) {
143+
git_patch *nextPatch;
144+
baton->error_code = git_patch_from_diff(&nextPatch, diffs, j);
145+
146+
if (baton->error_code < GIT_OK) {
147+
break;
148+
}
149+
150+
if (nextPatch == NULL) {
151+
continue;
152+
}
153+
154+
const git_diff_delta *delta = git_patch_get_delta(nextPatch);
155+
bool isEqualOldFile = !strcmp(delta->old_file.path, baton->file_path);
156+
bool isEqualNewFile = !strcmp(delta->new_file.path, baton->file_path);
157+
158+
if (isEqualNewFile) {
159+
std::pair<git_commit *, std::pair<char *, git_delta_t> > *historyEntry;
160+
if (!isEqualOldFile) {
161+
historyEntry = new std::pair<git_commit *, std::pair<char *, git_delta_t> >(
162+
nextCommit,
163+
std::pair<char *, git_delta_t>(strdup(delta->old_file.path), delta->status)
164+
);
165+
} else {
166+
historyEntry = new std::pair<git_commit *, std::pair<char *, git_delta_t> >(
167+
nextCommit,
168+
std::pair<char *, git_delta_t>(strdup(delta->new_file.path), delta->status)
169+
);
170+
}
171+
baton->out->push_back(historyEntry);
172+
flag = true;
173+
}
174+
175+
git_patch_free(nextPatch);
176+
177+
if (flag) {
178+
break;
179+
}
180+
}
181+
}
182+
125183
if (!flag && nextCommit != NULL) {
126184
git_commit_free(nextCommit);
127185
}

test/tests/revwalk.js

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
var assert = require("assert");
2+
var RepoUtils = require("../utils/repository_setup");
3+
var promisify = require("promisify-node");
4+
var fse = promisify(require("fs-extra"));
25
var path = require("path");
36
var local = path.join.bind(path, __dirname);
47

@@ -27,6 +30,7 @@ describe("Revwalk", function() {
2730

2831
beforeEach(function() {
2932
this.walker = this.repository.createRevWalk();
33+
this.walker.sorting(NodeGit.Revwalk.SORT.TIME);
3034
this.walker.push(this.commit.id());
3135
});
3236

@@ -141,7 +145,7 @@ describe("Revwalk", function() {
141145
});
142146
});
143147

144-
it("can get do a fast walk", function() {
148+
it("can do a fast walk", function() {
145149
var test = this;
146150
var magicSha = "b8a94aefb22d0534cc0e5acf533989c13d8725dc";
147151

@@ -152,6 +156,140 @@ describe("Revwalk", function() {
152156
});
153157
});
154158

159+
it("can get the history of a file", function() {
160+
var test = this;
161+
var magicShas = [
162+
"6ed3027eda383d417457b99b38c73f88f601c368",
163+
"95cefff6aabd3c1f6138ec289f42fec0921ff610",
164+
"7ad92a7e4d26a1af93f3450aea8b9d9b8069ea8c",
165+
"96f077977eb1ffcb63f9ce766cdf110e9392fdf5",
166+
"694adc5369687c47e02642941906cfc5cb21e6c2",
167+
"eebd0ead15d62eaf0ba276da53af43bbc3ce43ab",
168+
"1273fff13b3c28cfdb13ba7f575d696d2a8902e1"
169+
];
170+
171+
return test.walker.fileHistoryWalk("include/functions/copy.h", 1000)
172+
.then(function(results) {
173+
var shas = results.map(function(result) {
174+
return result.commit.sha();
175+
});
176+
assert.equal(magicShas.length, shas.length);
177+
magicShas.forEach(function(sha, i) {
178+
assert.equal(sha, shas[i]);
179+
});
180+
});
181+
});
182+
183+
it("can get the history of a file while ignoring parallel branches",
184+
function() {
185+
var test = this;
186+
var magicShas = [
187+
"f80e085e3118bbd6aad49dad7c53bdc37088bf9b",
188+
"907b29d8a3b765570435c922a59cd849836a7b51"
189+
];
190+
var shas;
191+
var walker = test.repository.createRevWalk();
192+
walker.sorting(NodeGit.Revwalk.SORT.TIME);
193+
walker.push("115d114e2c4d5028c7a78428f16a4528c51be7dd");
194+
195+
return walker.fileHistoryWalk("README.md", 15)
196+
.then(function(results) {
197+
shas = results.map(function(result) {
198+
return result.commit.sha();
199+
});
200+
assert.equal(magicShas.length, shas.length);
201+
magicShas.forEach(function(sha, i) {
202+
assert.equal(sha, shas[i]);
203+
});
204+
205+
magicShas = [
206+
"4a34168b80fe706f52417106821c9cbfec630e47",
207+
"f80e085e3118bbd6aad49dad7c53bdc37088bf9b",
208+
"694b2d703a02501f288269bea7d1a5d643a83cc8",
209+
"907b29d8a3b765570435c922a59cd849836a7b51"
210+
];
211+
212+
walker = test.repository.createRevWalk();
213+
walker.sorting(NodeGit.Revwalk.SORT.TIME);
214+
walker.push("d46f7da82969ca6620864d79a55b951be0540bda");
215+
216+
return walker.fileHistoryWalk("README.md", 50);
217+
})
218+
.then(function(results) {
219+
shas = results.map(function(result) {
220+
return result.commit.sha();
221+
});
222+
assert.equal(magicShas.length, shas.length);
223+
magicShas.forEach(function(sha, i) {
224+
assert.equal(sha, shas[i]);
225+
});
226+
});
227+
});
228+
229+
it("can yield information about renames in a file history walk",
230+
function() {
231+
var treeOid;
232+
var repo;
233+
var fileNameA = "a.txt";
234+
var fileNameB = "b.txt";
235+
var repoPath = local("../repos/renamedFileRepo");
236+
var signature = NodeGit.Signature.create("Foo bar",
237+
"foo@bar.com", 123456789, 60);
238+
return RepoUtils.createRepository(repoPath)
239+
.then(function(r) {
240+
repo = r;
241+
return RepoUtils.commitFileToRepo(
242+
repo,
243+
fileNameA,
244+
"line1\nline2\nline3\n"
245+
);
246+
})
247+
.then(function() {
248+
return fse.move(
249+
path.join(repoPath, fileNameA),
250+
path.join(repoPath, fileNameB)
251+
);
252+
})
253+
.then(function() {
254+
return repo.openIndex()
255+
.then(function(index) {
256+
index.read(1);
257+
index.addByPath(fileNameB);
258+
index.removeByPath(fileNameA);
259+
index.write();
260+
261+
return index.writeTree();
262+
});
263+
})
264+
.then(function(oidResult) {
265+
treeOid = oidResult;
266+
return NodeGit.Reference.nameToId(repo, "HEAD");
267+
})
268+
.then(function(head) {
269+
return repo.getCommit(head);
270+
})
271+
.then(function(head) {
272+
return repo.createCommit("HEAD", signature, signature,
273+
"renamed commit", treeOid, [head]);
274+
})
275+
.then(function() {
276+
return NodeGit.Reference.nameToId(repo, "HEAD");
277+
})
278+
.then(function(commitOid) {
279+
var walker = repo.createRevWalk();
280+
walker.sorting(NodeGit.Revwalk.SORT.TIME);
281+
walker.push(commitOid.tostrS());
282+
return walker.fileHistoryWalk(fileNameB, 5);
283+
})
284+
.then(function(results) {
285+
assert.equal(results[0].status, NodeGit.Diff.DELTA.RENAMED);
286+
assert.equal(results[0].oldName, fileNameA);
287+
})
288+
.then(function() {
289+
return fse.remove(repoPath);
290+
});
291+
});
292+
155293
// This test requires forcing garbage collection, so mocha needs to be run
156294
// via node rather than npm, with a la `node --expose-gc [pathtohmoca]
157295
// [testglob]`

0 commit comments

Comments
 (0)