1 | var util = require('util'),
|
2 | fs = require('fs'),
|
3 | GitFileOperations = require('./git_file_operations').GitFileOperations,
|
4 | exec = require('child_process').exec,
|
5 | FileIndex = require('./file_index').FileIndex,
|
6 | Repository = require('./repository').Repository,
|
7 | Difference = require('../diff/diff').Difference;
|
8 |
|
9 | var Git = exports.Git = function(git_directory) {
|
10 | var _git_diretory = git_directory, _git_file_index;
|
11 | var _repository = new Repository(_git_diretory, {});
|
12 |
|
13 | Object.defineProperty(this, "git_directory", { get: function() { return _git_diretory; }, set: function(value) { _git_diretory = value; }, enumerable: true});
|
14 | Object.defineProperty(this, "git_file_index", { get: function() { return _git_file_index; }, set: function(value) { _git_file_index = value; }, enumerable: true});
|
15 | Object.defineProperty(this, "repository", { get: function() { return _repository; }, set: function(value) { _repository = value; }, enumerable: true});
|
16 | }
|
17 |
|
18 |
|
19 | if(process.platform.toLowerCase().match(/mswin(?!ce)|mingw|bccwin|win32/)) {
|
20 | Git.git_binary = "git";
|
21 | } else {
|
22 | Git.git_binary = "/usr/bin/env git";
|
23 | }
|
24 |
|
25 |
|
26 | var chomp = function chomp(raw_text) {
|
27 | return raw_text ? raw_text.replace(/(\n|\r)+$/, '') : '';
|
28 | }
|
29 |
|
30 | var read_file = function(path, callback) {
|
31 | fs.stat(path, function(err, stat) {
|
32 | if(err) return callback(err, null);
|
33 | fs.readFile(path, 'ascii', callback);
|
34 | })
|
35 | }
|
36 |
|
37 |
|
38 | Git.prototype.refs = function(options, prefix, callback) {
|
39 | var refs = [];
|
40 | var already = {};
|
41 | var self = this;
|
42 |
|
43 |
|
44 | var stream = GitFileOperations.glob_streaming(this.git_directory + "/" + prefix);
|
45 |
|
46 | stream.addListener("data", function(result) {
|
47 |
|
48 | if(result.stat.isFile()) {
|
49 |
|
50 | try {
|
51 | var id = chomp(fs.readFileSync(result.path, 'ascii'));
|
52 | var name = result.path.replace(self.git_directory + "/" + prefix + "/", '');
|
53 |
|
54 | if(!already[name]) {
|
55 | refs.push(name + " " + id);
|
56 | already[name] = true;
|
57 | }
|
58 | } catch(err) {
|
59 |
|
60 | }
|
61 | }
|
62 | });
|
63 |
|
64 |
|
65 | stream.addListener("end", function(err, result) {
|
66 | fs.stat(self.git_directory + "/packed-refs", function(err, stat) {
|
67 | if(err || !stat.isFile()) return callback(null, refs.join("\n"));
|
68 |
|
69 | read_file(self.git_directory + "/packed-refs", function(err, data) {
|
70 | var parts = data.split(/\n/);
|
71 |
|
72 | for(var i = 0; i < parts.length; i++) {
|
73 | var match = parts[i].match(/^(\w{40}) (.*?)$/)
|
74 | if(match) {
|
75 | if(match[2].match("^" + prefix)) {
|
76 | var id = chomp(match[1]);
|
77 | var name = match[2].replace(prefix + "/", '');
|
78 |
|
79 | if(!already[name]) {
|
80 | refs.push(name + " " + id);
|
81 | already[name] = true;
|
82 | }
|
83 | }
|
84 | }
|
85 | }
|
86 |
|
87 | callback(null, refs.join("\n"));
|
88 | });
|
89 | })
|
90 | })
|
91 | }
|
92 |
|
93 |
|
94 | Git.prototype.fs_read = function(file, callback) {
|
95 | GitFileOperations.fs_read(this.git_directory, file, callback);
|
96 | }
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 | Git.prototype.transform_options = function(options) {
|
168 | var args = [];
|
169 | var keys = Object.keys(options);
|
170 |
|
171 |
|
172 | Object.keys(options).forEach(function(key) {
|
173 | if(key.length == 1) {
|
174 | if(options[key] == true && options[key].constructor == Boolean) { args.push('-' + key);
|
175 | } else if(options[key] == false && options[key].constructor == Boolean) {
|
176 | } else { args.push('-' + key + ' "' + options[key].toString().replace('"', "\\\"") + '"'); }
|
177 | } else {
|
178 | if(options[key] == true && options[key].constructor == Boolean) { args.push("--" + key.toString().replace(/_/, '-'));
|
179 | } else if(options[key] == false && options[key].constructor == Boolean) {
|
180 | } else { args.push('--' + key.toString().replace(/_/, '-') + '="' + options[key].toString().replace('"', "\\\"") + '"'); }
|
181 | }
|
182 | });
|
183 |
|
184 |
|
185 | return args;
|
186 | }
|
187 |
|
188 | Git.prototype.git = function() {
|
189 |
|
190 | var args = Array.prototype.slice.call(arguments, 0);
|
191 | var callback = args.pop();
|
192 |
|
193 | var function_name = args.length ? args.shift() : null;
|
194 | var options = args.length ? args.shift() : {};
|
195 | var arguments = args;
|
196 |
|
197 | this.call_git('', function_name, '', options, arguments, function(err, result) {
|
198 | callback(err, result);
|
199 | });
|
200 | }
|
201 |
|
202 | var shell_escape = function(str) {
|
203 | return str.toString().replace('"', "\\\"").replace(/\;/g, "\\;");
|
204 | }
|
205 |
|
206 |
|
207 | Git.prototype.call_git = function(prefix, command, postfix, options, args, callback) {
|
208 |
|
209 | var timeout = options['timeout'] ? timeout : 1000 * 60;
|
210 | var call_string = '';
|
211 |
|
212 | if(options['timeout']) delete options['timeout'];
|
213 | var option_arguments = this.transform_options(options);
|
214 |
|
215 | if(process.platform.toLowerCase().match(/mswin(?!ce)|mingw|bccwin/)) {
|
216 | } else {
|
217 |
|
218 | var ext_args = args.map(function(arg) { return (arg == '--' || arg.substr(0, 1) == '|' ? arg : ('"' + shell_escape(arg) + '"'))})
|
219 | .filter(function(arg) { return arg == null || arg == '' ? false : true});
|
220 |
|
221 | var final_arguments = option_arguments.concat(ext_args);
|
222 |
|
223 | call_string = prefix + Git.git_binary + ' --git-dir="'+ this.git_directory + '" ' + command.toString().replace(/_/, '-') + ' ' + final_arguments.join(" ") + postfix;
|
224 | }
|
225 |
|
226 | execute_git_call(call_string, { encoding: 'utf8', timeout: timeout, killSignal: 'SIGKILL'}, callback);
|
227 | }
|
228 |
|
229 | var execute_git_call = function(call_string, options, callback) {
|
230 |
|
231 | options.maxBuffer = 1024 * 1024;
|
232 | exec(call_string, options,
|
233 | function (error, stdout, stderr) {
|
234 | if (error != null) {
|
235 | var result = error.toString();
|
236 | callback(result != null ? result.trim() : result, null);
|
237 | } else {
|
238 | var result = stdout.toString();
|
239 | callback(null, result != null ? result.trim() : result)
|
240 | }
|
241 | });
|
242 | }
|
243 |
|
244 | var file_index = function(git, callback) {
|
245 |
|
246 | if(!git.git_file_index) {
|
247 | new FileIndex(git.git_directory, function(err, _file_index) {
|
248 | git.git_file_index = _file_index;
|
249 | callback(null, _file_index);
|
250 | });
|
251 | } else {
|
252 | callback(null, git.git_file_index);
|
253 | }
|
254 | }
|
255 |
|
256 |
|
257 | Git.prototype.rev_list = function(options, reference, callback) {
|
258 | var self = this;
|
259 | var args = Array.prototype.slice.call(arguments, 0);
|
260 | var callback = args.pop();
|
261 | options = args.length ? args.shift() : {};
|
262 | reference = args.length ? args.shift() : 'master';
|
263 |
|
264 |
|
265 | if(options['skip'] != null && parseInt(options['skip']) == 0) delete options['skip'];
|
266 | var allowed_options = {"max_count":1, "since":1, "until":1, "pretty":1};
|
267 | var establish_keys = Object.keys(options).filter(function(key) {
|
268 | return allowed_options[key] ? false : true;
|
269 | });
|
270 |
|
271 |
|
272 | if(establish_keys.length > 0) {
|
273 | self.call_git('', 'rev_list', '', options, [reference], function(err, result) {
|
274 | callback(err, result);
|
275 | })
|
276 | } else if(Object.keys(options).length == 0){
|
277 |
|
278 | file_index(self, function(err, _file_index) {
|
279 | if(err) return callback(err, _file_index);
|
280 |
|
281 | self.rev_parse({}, reference, 0, function(err, ref) {
|
282 | if(err) return callback(err, ref);
|
283 |
|
284 | _file_index.commits_from(ref, function(err, commits) {
|
285 | if(err) {
|
286 | self.call_git('', 'rev_list', '', options, [reference], function(err, result) {
|
287 | callback(err, result);
|
288 | })
|
289 | } else {
|
290 | callback(null, commits.join("\n") + "\n");
|
291 | }
|
292 | })
|
293 | });
|
294 | })
|
295 | } else {
|
296 | self.rev_parse({}, reference, 0, function(err, ref) {
|
297 | if(err) return callback(err, ref);
|
298 |
|
299 | if(Array.isArray(ref)) {
|
300 | self.call_git('', 'rev_list', '', options, [reference], function(err, result) {
|
301 | callback(err, result);
|
302 | })
|
303 | } else {
|
304 | try {
|
305 |
|
306 | self.repository.rev_list(ref, options, function(err, result) {
|
307 | callback(err, result);
|
308 | })
|
309 | } catch(err) {
|
310 | callback(err, null);
|
311 | }
|
312 | }
|
313 | });
|
314 | }
|
315 | }
|
316 |
|
317 |
|
318 | var chomp = function chomp(raw_text) {
|
319 | return raw_text.replace(/(\n|\r)+$/, '');
|
320 | }
|
321 |
|
322 | Git.prototype.rev_parse = function(options, string, level, callback) {
|
323 | if(string != null && string.constructor != String) return callback('only supports single sha reference');
|
324 | var self = this;
|
325 |
|
326 |
|
327 | var args = Array.prototype.slice.call(arguments, 2);
|
328 | var callback = args.pop();
|
329 | level = args.length ? args.shift() : 0;
|
330 |
|
331 | if(string.match(/\.\./)) {
|
332 | var parts = string.split("..");
|
333 | var sha1 = parts[0], sha2 = parts[1];
|
334 | var value = [this.rev_parse({}, sha1, level + 1, callback), this.rev_parse({}, sha2, level + 1, callback)];
|
335 | if(level == 0) return callback(null, value);
|
336 | }
|
337 |
|
338 |
|
339 | if(string.match(/^[0-9a-f]{40}$/)) {
|
340 | var value = chomp(string);
|
341 | if(level == 0) {
|
342 | return callback(null, value);
|
343 | } else {
|
344 | return value;
|
345 | }
|
346 | }
|
347 |
|
348 |
|
349 | var head = this.git_directory + "/refs/heads/" + string;
|
350 | try {
|
351 | if(level == 0) {
|
352 | return callback(null, chomp(fs.readFileSync(head, 'utf8')));
|
353 | } else {
|
354 | return chomp(fs.readFileSync(head, 'utf8'));
|
355 | }
|
356 | } catch(err) {}
|
357 |
|
358 | var head = this.git_directory + "/refs/remotes/" + string;
|
359 | try {
|
360 | if(level == 0) {
|
361 | return callback(null, chomp(fs.readFileSync(head, 'utf8')));
|
362 | } else {
|
363 | return chomp(fs.readFileSync(head, 'utf8'));
|
364 | }
|
365 | } catch(err) {}
|
366 |
|
367 | var head = this.git_directory + "/refs/tags/" + string;
|
368 | try {
|
369 | if(level == 0) {
|
370 | return callback(null, chomp(fs.readFileSync(head, 'utf8')));
|
371 | } else {
|
372 | return chomp(fs.readFileSync(head, 'utf8'));
|
373 | }
|
374 | } catch(err) {}
|
375 |
|
376 |
|
377 | var packref = this.git_directory + "/packed-refs";
|
378 | try {
|
379 |
|
380 | var parts = data.split(/\n/);
|
381 |
|
382 | for(var i = 0; i < parts.length; i++) {
|
383 | var match_parts = parts[i].match(/^(\w{40}) refs\/.+?\/(.*?)$/);
|
384 | if(match_parts) {
|
385 | ref = match_parts[1];
|
386 |
|
387 | if(new RegExp(string + '$').test(match_parts[3])) {
|
388 | if(level == 0) {
|
389 | return callback(null, chomp(ref));
|
390 | } else {
|
391 | return chomp(ref);
|
392 | }
|
393 | }
|
394 | }
|
395 | }
|
396 | } catch(err) {}
|
397 |
|
398 |
|
399 | self.call_git('', 'rev-parse', '', options, [string], function(err, result) {
|
400 | callback(null, result ? chomp(result) : result);
|
401 | })
|
402 | }
|
403 |
|
404 |
|
405 | Git.prototype.ls_tree = function(treeish, paths, options, callback) {
|
406 | var self = this;
|
407 | var args = Array.prototype.slice.call(arguments, 1);
|
408 | var callback = args.pop();
|
409 | paths = args.length ? args.shift() : [];
|
410 | paths = paths ? paths : [];
|
411 | options = args.length ? args.shift() : {};
|
412 |
|
413 | try {
|
414 |
|
415 | this.rev_parse({}, treeish, function(err, sha) {
|
416 | if(err) return callback(err, sha);
|
417 | var tree = self.repository.ls_tree(sha, flatten(paths), options['r']);
|
418 | if(tree == '') return callback('no such sha found', null);
|
419 |
|
420 | callback(null, tree);
|
421 | })
|
422 | } catch(err) {
|
423 | callback(err, null);
|
424 | }
|
425 | }
|
426 |
|
427 |
|
428 | Git.prototype.cat_file = function(type, ref, callback) {
|
429 | if(type == "t") {
|
430 | this.file_type(ref, callback);
|
431 | } else if(type == "s") {
|
432 | this.file_size(ref, callback);
|
433 | } else if(type == "p") {
|
434 | callback(null, this.repository.cat_file(ref));
|
435 | }
|
436 | }
|
437 |
|
438 | Git.prototype.file_size = function(ref, callback) {
|
439 | callback(null, this.repository.cat_file_size(ref));
|
440 | }
|
441 |
|
442 |
|
443 |
|
444 |
|
445 |
|
446 | Git.prototype.fs_mkdir = function(dir, callback) {
|
447 | var path = this.git_directory + "/" + dir;
|
448 | GitFileOperations.fs_mkdir(path, callback);
|
449 | }
|
450 |
|
451 |
|
452 | Git.prototype.init = function(options, callback) {
|
453 | var self = this;
|
454 | var arguments = Array.prototype.slice(arguments);
|
455 |
|
456 | if(Object.keys(options).length == 0) {
|
457 | Repository.init(this.git_directory, callback);
|
458 | } else {
|
459 |
|
460 | this.call_git('', 'init', '', options, arguments, function(err, result) {
|
461 | if(err) return callback(err, result);
|
462 | callback(null, self);
|
463 | });
|
464 | }
|
465 | }
|
466 |
|
467 |
|
468 | Git.prototype.clone = function(options, original_path, target_path, callback) {
|
469 | }
|
470 |
|
471 |
|
472 |
|
473 |
|
474 |
|
475 |
|
476 |
|
477 |
|
478 |
|
479 |
|
480 |
|
481 |
|
482 |
|
483 |
|
484 | var flatten = function(array) {
|
485 | return array.reduce(function(a,b) {
|
486 | return a.concat(b);
|
487 | }, []);
|
488 | }
|
489 |
|
490 | Git.prototype.diff = function(commit1, commit2, options, callback) {
|
491 | try {
|
492 | var self = this;
|
493 | var args = Array.prototype.slice.call(arguments, 2);
|
494 |
|
495 | var callback = args.pop();
|
496 | options = args.length ? args.shift() : {};
|
497 |
|
498 |
|
499 | var patch = '', commit_obj1 = null, tree1 = null, tree2 = null;
|
500 |
|
501 | var commit_obj1 = self.repository.get_object_by_sha1(commit1);
|
502 | var tree1 = commit_obj1.tree;
|
503 |
|
504 | if(commit2) {
|
505 | tree2 = self.repository.get_object_by_sha1(commit2).tree;
|
506 | } else {
|
507 | tree2 = self.repository.get_object_by_sha1(commit_obj1.parent[0]).tree;
|
508 | }
|
509 |
|
510 | var qdiff = self.repository.quick_diff(tree1, tree2).sort();
|
511 | qdiff.forEach(function(diff_arr) {
|
512 |
|
513 | var path = diff_arr[0];
|
514 | var status = diff_arr[1];
|
515 | var treeSHA1 = diff_arr[2];
|
516 | var treeSHA2 = diff_arr[3];
|
517 | var format = 'unified';
|
518 | var lines = 3;
|
519 | var output = '';
|
520 | var file_length_difference = 0;
|
521 |
|
522 |
|
523 | var fileA = treeSHA1 ? self.repository.cat_file(treeSHA1) : '';
|
524 | var fileB = treeSHA2 ? self.repository.cat_file(treeSHA2) : '';
|
525 |
|
526 |
|
527 | var sha1 = treeSHA1 || '0000000000000000000000000000000000000000';
|
528 | var sha2 = treeSHA2 || '0000000000000000000000000000000000000000';
|
529 |
|
530 |
|
531 | var data_old = fileA.trim().split(/\n/).map(function(e) { return chomp(e); });
|
532 | var data_new = fileB.trim().split(/\n/).map(function(e) { return chomp(e); });
|
533 |
|
534 | if(data_old.length == 1 && data_old[0] == '') data_old = [];
|
535 | if(data_new.length == 1 && data_new[0] == '') data_new = [];
|
536 |
|
537 |
|
538 | var diffs = Difference.LCS.diff(data_old, data_new);
|
539 | if(diffs.length > 0) {
|
540 |
|
541 | var a_path = "a/" + path.replace(/\.\//g, '');
|
542 | var b_path = "b/" + path.replace(/\.\//g, '');
|
543 |
|
544 | var header = "diff --git " + a_path + " " + b_path;
|
545 | if(options['full_index']) {
|
546 | header = header + '\n' + 'index ' + sha1 + '..' + sha2;
|
547 | if(treeSHA2) header = header + "' 100644";
|
548 | } else {
|
549 | header = header + '\n' + 'index ' + sha1.substr(0, 7) + '..' + sha2.substr(0, 7);
|
550 | if(treeSHA2) header = header + ' 100644';
|
551 | }
|
552 |
|
553 | header = header + '\n--- ' + (treeSHA1 ? a_path : '/dev/null');
|
554 | header = header + '\n+++ ' + (treeSHA2 ? b_path : '/dev/null');
|
555 | header = header + '\n';
|
556 |
|
557 |
|
558 | var old_hunk = null, hunk = null;
|
559 |
|
560 | diffs.forEach(function(piece) {
|
561 |
|
562 | try {
|
563 | hunk = new Difference.LCS.Hunk(data_old, data_new, piece, lines, file_length_difference);
|
564 | file_length_difference = hunk.file_length_difference;
|
565 |
|
566 | if(old_hunk) {
|
567 | if(lines > 0 && hunk.overlaps(old_hunk)) {
|
568 | hunk.unshift(old_hunk);
|
569 | } else {
|
570 | output = output + old_hunk.diff(format);
|
571 | }
|
572 | }
|
573 | } catch(err) {}
|
574 |
|
575 | old_hunk = hunk;
|
576 | output = output + '\n';
|
577 | });
|
578 |
|
579 |
|
580 | output = output + old_hunk.diff(format);
|
581 | output = output + '\n';
|
582 | patch = patch + header + output.trimLeft();
|
583 | }
|
584 | });
|
585 |
|
586 |
|
587 | callback(null, patch);
|
588 | } catch(err) {
|
589 | callback('tree was bad or lcs is not working', null);
|
590 | }
|
591 | }
|
592 |
|
593 |
|
594 | Git.prototype.fs_exist = function(path, callback) {
|
595 | GitFileOperations.fs_exist(this.git_directory, path, callback);
|
596 | }
|
597 |
|
598 |
|
599 |
|
600 |
|
601 |
|
602 |
|
603 | Git.prototype.fs_write = function(file, content, callback) {
|
604 | GitFileOperations.fs_write(this.git_directory, file, content, callback);
|
605 | }
|
606 |
|
607 |
|
608 | Git.prototype.log = function(commit, path, options, callback) {
|
609 | args = ['--raw', '--no-abbrev', '--numstat'];
|
610 | if (path) {
|
611 | args.push('--');
|
612 | args.push(path);
|
613 | }
|
614 | options.color = 'never';
|
615 | this.call_git('', 'log', '', options, args, callback);
|
616 | }
|
617 |
|
618 |
|
619 |
|
620 |
|
621 |
|
622 | Git.prototype.select_existing_objects = function(object_ids, callback) {
|
623 | var existing_object_ids = [];
|
624 |
|
625 | for(var i = 0; i < object_ids.length; i++) {
|
626 |
|
627 | this.repository.object_exists(object_ids[i], function(err, result) {
|
628 | if(err) return callback(err, result);
|
629 | if(result) existing_object_ids.push(object_ids[i]);
|
630 | });
|
631 | }
|
632 |
|
633 | callback(null, existing_object_ids);
|
634 | }
|
635 |
|
636 |
|
637 | Git.prototype.format_patch = function(options, reference, callback) {
|
638 | this.call_git('', 'format_patch', '', options, [reference], function(err, result) {
|
639 | callback(err, result);
|
640 | })
|
641 | }
|
642 |
|
643 |
|
644 | Git.prototype.blame = function() {
|
645 |
|
646 | var args = Array.prototype.slice.call(arguments, 0);
|
647 | var callback = args.pop();
|
648 | var options = args.length ? args.shift() : {};
|
649 | var arguments = args;
|
650 |
|
651 |
|
652 | this.call_git('', 'blame', '', options, arguments, function(err, result) {
|
653 | callback(err, result);
|
654 | });
|
655 | }
|
656 |
|
657 | var clean_paths = function(commits) {
|
658 | var new_commits = {};
|
659 |
|
660 | Object.keys(commits).forEach(function(file) {
|
661 | var sha = commits[file];
|
662 | file = file.substr(file.length - 1, 1) == '/' ? file.substr(0, file.length - 1) : file;
|
663 | new_commits[file] = sha;
|
664 | })
|
665 |
|
666 | return new_commits;
|
667 | }
|
668 |
|
669 |
|
670 | Git.prototype.blame_tree = function(commit, path, callback) {
|
671 | var self = this;
|
672 | var args = Array.prototype.slice.call(arguments, 1);
|
673 | var callback = args.pop();
|
674 | path = args.length ? args.shift() : null;
|
675 |
|
676 |
|
677 | path = path != null && path != '' ? [path].join("/").toString() + '/' : path;
|
678 | path = !path || path.constructor != String ? '' : path;
|
679 |
|
680 |
|
681 | file_index(this, function(err, file_index_instance) {
|
682 | if(err) return callback(err, file_index_instance);
|
683 |
|
684 | self.rev_parse({}, commit, 0, function(err, rev_parse_output) {
|
685 | if(err) return callback(err, rev_parse_output);
|
686 |
|
687 | self.looking_for(commit, path, function(err, looking_for) {
|
688 | if(err) return callback(err, looking_for);
|
689 |
|
690 | file_index_instance.last_commits(rev_parse_output, looking_for, function(err, commits) {
|
691 | if(err) return callback(err, commits);
|
692 |
|
693 | callback(null, clean_paths(commits));
|
694 | });
|
695 | });
|
696 | });
|
697 | });
|
698 | }
|
699 |
|
700 |
|
701 | Git.prototype.looking_for = function(commit, path, callback) {
|
702 | var self = this;
|
703 | var args = Array.prototype.slice.call(arguments, 1);
|
704 | var callback = args.pop();
|
705 | path = args.length ? args.shift() : null;
|
706 | var file = null;
|
707 |
|
708 |
|
709 | self.rev_parse({}, commit, 0, function(err, rev_parse_output) {
|
710 | if(err) return callback(err, rev_parse_output);
|
711 |
|
712 |
|
713 | self.repository.get_subtree(rev_parse_output, path, function(err, tree_sha) {
|
714 | if(err) return callback(err, tree_sha);
|
715 |
|
716 |
|
717 | var looking_for = [];
|
718 |
|
719 | var object = self.repository.get_object_by_sha1(tree_sha);
|
720 |
|
721 | object.entries.forEach(function(entry) {
|
722 | file = path && !(path == '' || path == '.' || path == './') ? path + "/" + entry.name : entry.name;
|
723 |
|
724 | file = file.replace('//', '/');
|
725 |
|
726 | if(entry.type == 'directory') file = file + "/";
|
727 |
|
728 | looking_for.push(file);
|
729 | });
|
730 |
|
731 |
|
732 | return callback(null, looking_for);
|
733 | });
|
734 | });
|
735 | }
|
736 |
|
737 |
|
738 | Git.prototype.commit = function() {
|
739 |
|
740 | var args = Array.prototype.slice.call(arguments, 0);
|
741 | var callback = args.pop();
|
742 | var options = args.length ? args.shift() : {};
|
743 | var arguments = args;
|
744 |
|
745 |
|
746 | this.call_git('', 'commit', '', options, arguments, function(err, result) {
|
747 | callback(err, result);
|
748 | });
|
749 | }
|
750 |
|
751 |
|
752 | Git.prototype.config = function() {
|
753 |
|
754 | var args = Array.prototype.slice.call(arguments, 0);
|
755 | var callback = args.pop();
|
756 | var options = args.length ? args.shift() : {};
|
757 | var arguments = args;
|
758 |
|
759 | this.call_git('', 'config', '', options, arguments, function(err, result) {
|
760 | callback(err, result);
|
761 | });
|
762 | }
|
763 |
|
764 |
|
765 | Git.prototype.add = function() {
|
766 |
|
767 | var args = Array.prototype.slice.call(arguments, 0);
|
768 | var callback = args.pop();
|
769 | var options = args.length ? args.shift() : {};
|
770 | var arguments = args;
|
771 |
|
772 | this.call_git('', 'add', '', options, arguments, function(err, result) {
|
773 | callback(err, result);
|
774 | });
|
775 | }
|
776 |
|
777 |
|
778 | Git.prototype.remove = function() {
|
779 |
|
780 | var args = Array.prototype.slice.call(arguments, 0);
|
781 | var callback = args.pop();
|
782 | var options = args.length ? args.shift() : {};
|
783 | var arguments = args;
|
784 |
|
785 | this.call_git('', 'rm', '', options, arguments, function(err, result) {
|
786 | callback(err, result);
|
787 | });
|
788 | }
|
789 |
|
790 |
|
791 | Git.prototype.ls_files = function() {
|
792 |
|
793 | var args = Array.prototype.slice.call(arguments, 0);
|
794 | var callback = args.pop();
|
795 | var options = args.length ? args.shift() : {};
|
796 | var arguments = args;
|
797 |
|
798 | this.call_git('', 'ls-files', '', options, arguments, function(err, result) {
|
799 | callback(err, result);
|
800 | });
|
801 | }
|
802 |
|
803 |
|
804 | Git.prototype.diff_files = function() {
|
805 |
|
806 | var args = Array.prototype.slice.call(arguments, 0);
|
807 | var callback = args.pop();
|
808 | var options = args.length ? args.shift() : {};
|
809 | var arguments = args;
|
810 |
|
811 | this.call_git('', 'diff-files', '', options, arguments, function(err, result) {
|
812 | callback(err, result);
|
813 | });
|
814 | }
|
815 |
|
816 |
|
817 | Git.prototype.diff_index = function() {
|
818 |
|
819 | var args = Array.prototype.slice.call(arguments, 0);
|
820 | var callback = args.pop();
|
821 | var options = args.length ? args.shift() : {};
|
822 | var arguments = args;
|
823 |
|
824 | this.call_git('', 'diff-index', '', options, arguments, function(err, result) {
|
825 | callback(err, result);
|
826 | });
|
827 | }
|
828 |
|
829 | Git.prototype.file_type = function(ref, callback) {
|
830 | return callback(null, this.repository.cat_file_type(ref));
|
831 | }
|
832 |
|
833 | Git.prototype.put_raw_object = function(content, type, callback) {
|
834 | return this.repository.put_raw_object(content, type, callback);
|
835 | }
|
836 |
|
837 | Git.prototype.commit_from_sha = function(id) {
|
838 | var repository = new Repository(this.git_directory);
|
839 | var object = repository.get_object_by_sha1(id);
|
840 |
|
841 | if(object.type == "commit") {
|
842 | return id;
|
843 | } else if(object.type == "tag") {
|
844 | return object.object;
|
845 | } else {
|
846 | return '';
|
847 | }
|
848 | }
|
849 |
|
850 |
|
851 |
|
852 |
|
853 |
|
854 |
|
855 |
|
856 |
|
857 |
|
858 |
|
859 |
|
860 |
|
861 |
|
862 |
|
863 |
|
864 |
|
865 |
|
866 |
|
867 |
|
868 |
|
869 |
|
870 |
|
871 |
|
872 |
|
873 |
|
874 |
|
875 |
|
876 |
|
877 |
|
878 |
|
879 |
|
880 |
|
881 |
|
882 |
|
883 |
|
884 |
|
885 |
|
886 |
|
887 |
|
888 |
|
889 |
|
890 |
|
891 |
|