1 | # ggit
|
2 |
|
3 | > Local promise-returning git command wrappers
|
4 |
|
5 | [![NPM][ggit-icon] ][ggit-url]
|
6 |
|
7 | [![Build status][ggit-ci-image] ][ggit-ci-url]
|
8 | [![dependencies][ggit-dependencies-image] ][ggit-dependencies-url]
|
9 | [![devdependencies][ggit-devdependencies-image] ][ggit-devdependencies-url]
|
10 | [![semantic-release][semantic-image] ][semantic-url]
|
11 | [![manpm](https://img.shields.io/badge/manpm-%E2%9C%93-3399ff.svg)](https://github.com/bahmutov/manpm)
|
12 |
|
13 | [ggit-icon]: https://nodei.co/npm/ggit.svg?downloads=true
|
14 | [ggit-url]: https://npmjs.org/package/ggit
|
15 | [ggit-ci-image]: https://travis-ci.org/bahmutov/ggit.svg?branch=master
|
16 | [ggit-ci-url]: https://travis-ci.org/bahmutov/ggit
|
17 | [ggit-dependencies-image]: https://david-dm.org/bahmutov/ggit.svg
|
18 | [ggit-dependencies-url]: https://david-dm.org/bahmutov/ggit
|
19 | [ggit-devdependencies-image]: https://david-dm.org/bahmutov/ggit/dev-status.svg
|
20 | [ggit-devdependencies-url]: https://david-dm.org/bahmutov/ggit#info=devDependencies
|
21 | [semantic-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
|
22 | [semantic-url]: https://github.com/semantic-release/semantic-release
|
23 |
|
24 |
|
25 |
|
26 | ## Stand alone tool
|
27 |
|
28 | You can install and run this tool as a stand alone CLI application.
|
29 |
|
30 | npm install -g ggit
|
31 | ggit --help
|
32 | # get last commit id in the current folder, save into json file
|
33 | ggit last -f build.json
|
34 |
|
35 | ## API
|
36 |
|
37 | ### cloneRepo
|
38 |
|
39 | ```javascript
|
40 | var clone = require('ggit').cloneRepo;
|
41 | clone({
|
42 | url: 'git@github.com:bahmutov/test-next-updater.git',
|
43 | folder: 'folder to create, should not exist yet'
|
44 | }).then(function () {
|
45 | console.log('cloned repo to destination folder');
|
46 | });
|
47 | ```
|
48 |
|
49 | ### exec
|
50 |
|
51 | ```javascript
|
52 | var exec = require('ggit').exec;
|
53 | var cmd = 'rm -rf folder';
|
54 | var verbose = true;
|
55 | exec(cmd, verbose).then(function () {
|
56 | console.log('removed folder');
|
57 | });
|
58 | ```
|
59 |
|
60 | ### blame
|
61 |
|
62 | Finds last person who has touched specific line in a file
|
63 |
|
64 | * filename - full or partial filename (from the repo's root)
|
65 | * lineNumber - starts with 1
|
66 |
|
67 | ```javascript
|
68 | var blame = require('ggit').blame;
|
69 | blame(filename, lineNumber).then(function (info) {
|
70 | /*
|
71 | info is object with fields like
|
72 | { commit: '6e65f8ec5ed63cac92ed130b1246d9c23223c04e',
|
73 | author: 'Gleb Bahmutov',
|
74 | committer: 'Gleb Bahmutov',
|
75 | summary: 'adding blame feature',
|
76 | filename: 'test/blame.js',
|
77 | line: 'var blame = require(\'../index\').blame;' }
|
78 | */
|
79 | });
|
80 | ```
|
81 |
|
82 | Equivalent to porcelain git output: see [git-blame](http://git-scm.com/docs/git-blame)
|
83 |
|
84 |
|
85 |
|
86 | ### isTracked
|
87 |
|
88 | Returns `true` if given path is tracked in the repo.
|
89 |
|
90 | * path
|
91 |
|
92 | ```javascript
|
93 | var isTracked = require('ggit').isTracked;
|
94 | isTracked(filename).then(function (result) {
|
95 | // result is true or false
|
96 | });
|
97 | ```
|
98 |
|
99 |
|
100 | ### hasChanges
|
101 |
|
102 | Returns `true` if there are local uncommitted stages
|
103 |
|
104 | ```javascript
|
105 | var changed = require('ggit').hasChanges;
|
106 | changed().then(function (result) {
|
107 | // result is true or false
|
108 | });
|
109 | ```
|
110 |
|
111 |
|
112 | ### commit
|
113 |
|
114 | Commit any changes with a given message. Second argument is optional and will
|
115 | be added after a blank line to the short main message.
|
116 |
|
117 | ```js
|
118 | var commit = require('ggit').commit;
|
119 | commit('added foo', 'long text').then(function () {
|
120 | // after commit
|
121 | });
|
122 | ```
|
123 |
|
124 | You can pass the entire message if wanted as first argument
|
125 |
|
126 | ```js
|
127 | var fullMessage = 'first line\n\nbody of message\n';
|
128 | commit(fullMessage).then(...);
|
129 | ```
|
130 |
|
131 |
|
132 | ### push
|
133 |
|
134 | Push commits to the remote
|
135 |
|
136 | ```javascript
|
137 | var psuh = require('ggit').psuh;
|
138 | psuh().then(function () {
|
139 | // after the push
|
140 | });
|
141 | ```
|
142 |
|
143 |
|
144 | ### commits
|
145 |
|
146 | Returns list of commits in the given folder as a list or object
|
147 |
|
148 | ```js
|
149 | // commits.all - gets all commits
|
150 | var commits = require('ggit').commits;
|
151 | commits.all(gitRepoFolder)
|
152 | .then(R.take(2))
|
153 | .then(console.table)
|
154 | .done();
|
155 | // commits.byId - transforms list of commits into object
|
156 | // where keys = ids, values = messages
|
157 | // For example to get an object with 2 commit ids as keys
|
158 | commits.all(gitRepoFolder)
|
159 | .then(R.take(2))
|
160 | .then(commits.byId)
|
161 | .then(console.log)
|
162 | .done();
|
163 | ```
|
164 |
|
165 | Each object has at least 'id', 'message' and (maybe empty) 'body' properties.
|
166 |
|
167 | You can also return just the commits starting from the last version tag
|
168 | (which usually starts with 'v'). This is useful for semantic release code.
|
169 |
|
170 | ```sh
|
171 | var commits = require('ggit').commits;
|
172 | commits.afterLastTag()
|
173 | .then(function (list) { ... })
|
174 | ```
|
175 |
|
176 |
|
177 | ### trackedFiles
|
178 |
|
179 | Returns all tracked source files in the given folder matching pattern.
|
180 | Both folder and pattern are optional.
|
181 |
|
182 | ```js
|
183 | require('ggit')
|
184 | .trackedFiles(__dirname, '*.js', options)
|
185 | .then(function (list) {
|
186 | console.log('javascript tracked in the current folder are');
|
187 | console.log(list);
|
188 | })
|
189 | .done();
|
190 | ```
|
191 |
|
192 | The `options` argument is optional, and is passed directly to the
|
193 | [glob](https://www.npmjs.com/package/glob) package that does file discovery.
|
194 | The only important option to use is `{ dot: true }` - if you want to find the
|
195 | filenames that start with `.`. For example to find ALL files in the repo call
|
196 |
|
197 | ```js
|
198 | require('ggit')
|
199 | .trackedFiles(__dirname, '**', { dot: true })
|
200 | // returns .gitignore, .travis.yml, index.js etc
|
201 | ```
|
202 |
|
203 |
|
204 | ### untrackedFiles
|
205 |
|
206 | Returns all untracked source files in the repo.
|
207 |
|
208 | ```js
|
209 | require('ggit')
|
210 | .untrackedFiles()
|
211 | .then(function (list) {
|
212 | // list is Array of strings, could be empty
|
213 | console.log('untracked files are');
|
214 | console.log(list);
|
215 | })
|
216 | .done();
|
217 | ```
|
218 |
|
219 |
|
220 | ### commitPerLine
|
221 |
|
222 | Returns an object where for each key (filename) there is a list of commits for each line.
|
223 |
|
224 | * list of filenames
|
225 |
|
226 | ```js
|
227 | var perLine = require('ggit').commitPerLine;
|
228 | perLine(['foo.js', 'bar.js']).then(function (result) {
|
229 | /*
|
230 | {
|
231 | 'foo.js': [{
|
232 | commit: '3c6b01eb3c96db1cbdf277904545107ef97cbb56',
|
233 | author: 'Gleb Bahmutov',
|
234 | committer: 'Gleb Bahmutov',
|
235 | summary: 'cool commit',
|
236 | filename: 'foo.js',
|
237 | line: '// actual source line'
|
238 | },
|
239 | ...
|
240 | }],
|
241 | 'bar.js': [...]
|
242 | }
|
243 | */
|
244 | });
|
245 | ```
|
246 |
|
247 |
|
248 | ### numstat
|
249 |
|
250 | Returns info for a specific commit - number of lines changed, deleted.
|
251 | Same as `$ git show --numstat <id>`.
|
252 |
|
253 | ```js
|
254 | require('ggit')
|
255 | .numstat('5d3ee3')
|
256 | .then(function (result) {
|
257 | /* result is
|
258 | {
|
259 | commit: <full commit SHA>,
|
260 | author:
|
261 | message:
|
262 | date:
|
263 | changes: {
|
264 | 'filename 1': {
|
265 | filename: 'filename 1',
|
266 | added: 10,
|
267 | deleted: 3
|
268 | },
|
269 | ...
|
270 | }
|
271 | }
|
272 | */
|
273 | })
|
274 | .done();
|
275 | ```
|
276 |
|
277 |
|
278 | ### lastCommitId
|
279 |
|
280 | Returns last commit id
|
281 |
|
282 | ```js
|
283 | require('ggit')
|
284 | .lastCommitId()
|
285 | .then(function (str) {
|
286 | // str is full SHA id string
|
287 | })
|
288 | .done();
|
289 | ```
|
290 |
|
291 | You can pass options object as in `lastCommitId(options)` where
|
292 |
|
293 | * **file** - save id into the JSON file with the given `file` name.
|
294 |
|
295 |
|
296 | ### branchName
|
297 |
|
298 | Resolves with the current branch name
|
299 |
|
300 | ```js
|
301 | require('ggit').branchName()
|
302 | .then(function (name) {
|
303 | // name = "master" or whatever
|
304 | });
|
305 | ```
|
306 |
|
307 |
|
308 | ### changed-files
|
309 |
|
310 | Returns list of modified files
|
311 |
|
312 | ```javascript
|
313 | var changedFiles = require('ggit').changedFiles;
|
314 | changedFiles()
|
315 | .then(function (files) {})
|
316 | .catch(function (error) {});
|
317 | ```
|
318 |
|
319 | The object `files` groups filenames by modification property
|
320 |
|
321 | ```js
|
322 | {
|
323 | A: [...], // list of added files
|
324 | C: [...], // list of copied files
|
325 | M: [...], // list of modified files
|
326 | D: [...] // list of deleted files
|
327 | }
|
328 | // each item in the list is
|
329 | {
|
330 | diff: 'A' // or C, M, D
|
331 | name: 'src/something.js' // relative to the repo root
|
332 | filename: 'full path',
|
333 | before: 'file contents', // if available (for example M, D)
|
334 | after: 'file contents' // if available (for A, M)
|
335 | }
|
336 | ```
|
337 |
|
338 | This is a wrapper around two commands `git diff --name-status --diff-filter=ACMD`
|
339 | and `git status --porcelain`
|
340 |
|
341 |
|
342 |
|
343 |
|
344 | ### fileContents
|
345 |
|
346 | Returns the contents of a file at some point
|
347 |
|
348 | * filename - full or partial filename (from the repo's root)
|
349 | * at (optional) - checkpoint, HEAD by default
|
350 |
|
351 | ```javascript
|
352 | var fileContents = require('ggit').fileContents;
|
353 | fileContents(filename).then(function (text) { ... });
|
354 | ```
|
355 |
|
356 | Same as `git show <at>:<name>`
|
357 |
|
358 |
|
359 |
|
360 | ### commitMessage
|
361 |
|
362 | Returns the contents of the Git current commit message,
|
363 | usually for validation before the commit.
|
364 |
|
365 | ```js
|
366 | require('ggit').commitMessage()
|
367 | .then(function (text) {
|
368 | // do something with the message
|
369 | },
|
370 | function () {
|
371 | // file not found
|
372 | });
|
373 | ```
|
374 |
|
375 |
|
376 | ### getGitFolder
|
377 |
|
378 | Returns the root folder, equivalent to command
|
379 | line `git rev-parse --show-toplevel`
|
380 |
|
381 | ```javascript
|
382 | require('ggit').getGitFolder()
|
383 | .then(folder => {
|
384 | ...
|
385 | })
|
386 | ```
|
387 |
|
388 |
|
389 | ### tags
|
390 |
|
391 | > Requires `git` >= 2.0
|
392 |
|
393 | Returns list of tags in the given folder, including commit ids.
|
394 |
|
395 | ```js
|
396 | var tags = require('ggit').tags;
|
397 | tags().then(function (list) {
|
398 | /*
|
399 | each object in list is like
|
400 | {
|
401 | "commit": "7756b5609c5aae651f267fa3fc00763bcd276bf6",
|
402 | "tag": "v1.3.0"
|
403 | }
|
404 | */
|
405 | })
|
406 | ```
|
407 | You can return just tags that start with "v" by passing
|
408 | `true` to `tags`.
|
409 |
|
410 | ```js
|
411 | tags(true).then(function (list) {...})
|
412 | ```
|
413 |
|
414 | Oldest tag is returns as first object, latest tag is the
|
415 | last object in the list.
|
416 |
|
417 | If you have older `git` (like Travis does), it will automatically try to
|
418 | grab all the tags and sort them using
|
419 | [semantic sort](https://github.com/semver/node-semver#comparison)
|
420 |
|
421 | ### branchTags
|
422 |
|
423 | > Requires `git` >= 2.7
|
424 |
|
425 | Similar to `tags`, `branchTags` returns tags in the given folder,
|
426 | but only those tags accessible from the current branch. Any tags
|
427 | in the repository that point to a commit on another branch will
|
428 | not be returned by `branchTags`.
|
429 |
|
430 | ```js
|
431 | var branchTags = require('ggit').branchTags;
|
432 | branchTags().then(function (list) {
|
433 | /*
|
434 | each object in list is like
|
435 | {
|
436 | "commit": "7756b5609c5aae651f267fa3fc00763bcd276bf6",
|
437 | "tag": "v1.3.0"
|
438 | }
|
439 | */
|
440 | })
|
441 | ```
|
442 | You can return just tags that start with "v" by passing
|
443 | `true` to `branchTags`.
|
444 |
|
445 | ```js
|
446 | branchTags(true).then(function (list) {...})
|
447 | ```
|
448 |
|
449 | Oldest tag is returned as first object, latest tag is the
|
450 | last object in the list.
|
451 |
|
452 |
|
453 | ### fetchTags
|
454 |
|
455 | Fetches remote tags from origin.
|
456 |
|
457 | ```js
|
458 | var fetchTags = require('ggit').fetchTags;
|
459 | fetchTags().then(function () {
|
460 | // should be same as running command
|
461 | // git pull origin --tags
|
462 | })
|
463 | ```
|
464 |
|
465 | You can pass the branch name, by default will fetch
|
466 | from master
|
467 |
|
468 | ```js
|
469 | fetchTags('development')
|
470 | ```
|
471 |
|
472 |
|
473 |
|
474 |
|
475 |
|
476 | ## Development
|
477 |
|
478 | Edit source, run unit tests, run end to end tests and push the code
|
479 | back to Github. The NPM publishing happens automatically using
|
480 | [semantic release](https://github.com/semantic-release/semantic-release)
|
481 |
|
482 | ```sh
|
483 | npm test
|
484 | npm run commit
|
485 | git push
|
486 | ```
|
487 |
|
488 | To debug problems, run the command with `DEBUG=ggit` environment variable enabled
|
489 | to see verbose logging.
|
490 |
|
491 | ### Unit tests
|
492 |
|
493 | Some of the unit tests rely on extracting private functions from modules
|
494 | using [scope magic with `describe-it`](https://github.com/bahmutov/describe-it),
|
495 | which requires Node 4.2.2 and might not work with later Node versions.
|
496 |
|
497 | ### Related projects
|
498 |
|
499 | * [npm-utils](https://github.com/bahmutov/npm-utils) - small utils for working
|
500 | with NPM commands.
|
501 |
|
502 |
|
503 |
|
504 | ### Small print
|
505 |
|
506 | Author: Gleb Bahmutov © 2015
|
507 |
|
508 | * [@bahmutov](https://twitter.com/bahmutov)
|
509 | * [glebbahmutov.com](http://glebbahmutov.com)
|
510 | * [blog](http://glebbahmutov.com/blog/)
|
511 |
|
512 | License: [MIT](LICENSE) - do anything with the code, but don't blame uTest if it does not work.
|
513 |
|
514 | Spread the word: tweet, star on github, etc.
|
515 |
|
516 | Support: if you find any problems with this module, email / tweet / open
|
517 | [issue on Github](https://github.com/bahmutov/ggit/issues)
|
518 |
|
519 |
|