UNPKG

isomorphic-git

Version:

Node library for interacting with git repositories, circa 2017

214 lines (166 loc) 6.89 kB
# isomorphic-git [![Build Status](https://travis-ci.org/wmhilton/esgit.svg?branch=master)](https://travis-ci.org/wmhilton/esgit) Node library for interacting with git repositories, circa 2017 (Originally I was going to call it `esgit` but the name is too similar to another project called [`es-git`](https://github.com/es-git/es-git).) # Progress Porcelain: - [x] git init - [x] git clone - [x] Github API protocol (only signed commits) - [ ] HTTP smart protocol + cors-buster - [x] git checkout - [ ] update index correctly when checking out - [x] git list (ls-files) - [x] git add - [x] git remove - [ ] git status - [x] git commit - [x] git push (due to CORS, use https://github-cors.now.sh instead of https://github.com) - [ ] git pull - [ ] git diff - [ ] git merge - [x] `esgit` CLI Plumbing: - [ ] read-tree - [x] git listCommits (rev-list) - [x] git pack (pack-objects) - [ ] git list packed objects (verify-pack) - [ ] git unpack-objects Note: There appears to be no a way to *push* signed commits back to Github using their API (v3 or v4), so I think we will have to use smart HTTP, packfiles, and an anti-CORS proxy. ## High-level API (unstable) This is analogous to the "porcelain" git commands. There is a single function `git()` that serves as a fluent command builder. Examples: ```js import git from 'esgit' // Create a new empty repo git('test').init() // Clone from a Github repository to the current working directory. // Just like it's counterpart, clone is really just shorthand for git.init(); git.fetch(); git.checkout(); git('.').githubToken(process.env.GITHUB_TOKEN).clone('https://github.com/wmhilton/esgit') // Checkout a commitish git('.').checkout('master') // List files in the index git('.').list() // Add files to the index git('.').add('README.md') // Remove files from the index git('.').remove('.env') // Create a new commit (there's actually several more options for date, committer) git('.') .add('a.txt') .author('Mr. Test') .email('mrtest@example.com') .signingKey('-----BEGIN PGP PRIVATE KEY BLOCK-----...') .commit('Added the a.txt file') // Manually add a remote (git clone should be doing this but it doesn't (yet)) git('.') .setConfig('remote "origin".url', 'https://github-cors.now.sh/wmhilton/test.empty') // Push a branch back to Github git('.') .githubToken(process.env.GITHUB_TOKEN) .remote('origin') .push('refs/heads/master') // TODO: git.merge(), git.pull(), git.status(), git.diff(), git.tag(), git.branch(), etc // And if you need to work with bare repos there are // equivalents to the `--git-dir` and `--work-tree` options git().gitdir('my-bare-repo').workdir('/var/www/website') ``` ### CLI I realized I could "translate" command line options into JavaScript chained commands without hard-coding any knowledge of the API if I kept the chained commands very predictable. I built a purely a generic translator and it worked surprisingly well. So you can do *any* current or future esgit commands using the included `esgit` CLI. It always starts with an implicit `git('.')` so it defaults to working in the current working directory. ``` // Create a new empty repo esgit --gitdir=test init // Clone from a Github repository to the current working directory. // Just like it's counterpart, clone is really just shorthand for git.init(); git.fetch(); git.checkout(); esgit --githubToken=$GITHUB_TOKEN clone https://github.com/wmhilton/esgit // Checkout a commitish esgit checkout master // List files in the index esgit list // Add files to the index esgit add README.md // Remove files from the index esgit remove .env // Create a new commit (there's actually several more options for date, committer) esgit add a.txt esgit --author='Mr. Test' --email=mrtest@example.com --signingKey="$(cat private.key)" commit 'Added the a.txt file' // And if you need to work with bare repos there are // equivalents to the `--git-dir` and `--work-tree` options esgit --gitdir=my-bare-repo --workdir=/var/www/website ``` ## Low-level API (also unstable) The high-level makes some assumptions (like you have a file-system and network access) that might not be well suited to your embedded git-based concept thingy. Fear not! I am purposefully building this library as a series of small modules so you can pick and choose features as you need them. ### Individual commands Each command is available as its own file, so hopefully with a bit of finagling you will be able to do: ```js const add = require('esgit/lib/commands/add.js') const checkout = require('esgit/lib/commands/checkout.js') const config = require('esgit/lib/commands/config.js') const fetch = require('esgit/lib/commands/fetch.js') const init = require('esgit/lib/commands/init.js') const list = require('esgit/lib/commands/list.js') const remove = require('esgit/lib/commands/remove.js') // Example checkout({ workdir: '.', gitdir: '.git', ref: 'master', remote: 'origin' }) .then() ``` ### Individual objects Only interested in commit objects? Import just the GitCommit class. And so on: ```js const GitBlob = require('esgit/lib/models/GitBlob.js') const GitCommit = require('esgit/lib/models/GitCommit.js') const GitTree = require('esgit/lib/models/GitTree.js') const GitObject = require('esgit/lib/models/GitObject.js') // Example const commit = GitCommit.from(`tree 0370383003493b845c73fb4316355a18f0e346fe parent c9efafe888804a58e333ec1b64ca58f9c4c92414 author Will Hilton <wmhilton@gmail.com> 1503898987 -0400 committer Will Hilton <wmhilton@gmail.com> 1503899426 -0400 gpgsig -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJZo68iAAoJEJYJuKWSi6a5WesP/31Ie7uNJcLU1+yEch1ubuhS J9PfAna2iUflQANNq8BCyufW8Nq3ZA+nyRvaA499VqLkiuEI6nMUwWVPdhuYUG4s P7QP85NXn1w1DRNfbb2K6USz40P3a108GqhOpDCLP55kRfcxyJZIymD/WtHKji7T 3ubE0meMYHOsx9a76Roo9DOHiqy3gAZsiwqvvqToD/IrmPmRv3qCqFBPrKKMW7la DZGPFHV9bhJfaGTT42lu0vTjv5itdLwfCLReh3LuQ1TAq5b6hhvwguE+M+X8qA11 KXxxyQf06wt3+o8pjxxUHttVsuiS68yxzeTQOWe8pk/E5oaEqOx6O9stDvSfZatm 2LvFR++0axDMANluuStAoDhTMrqUqLQ3iWeay+xpivrP7mWnLM/bzrPShQVSkFPP VkKedKiaaCGKTEY4xa/RBQvQ3WqDnNogY5t6bOolPvC5/D5n3grkzOpI7WQqh8EN +6eYOOYTTPShi5gnBTSwFdSBKG4aWJI5moQtQJ1wQtc4Zhm4jKbp7OLPn1GJEET6 QwnURymv4mkDuvyPUki5nsP5U+xzWObp8PlqE4SCbSiV4D5FqF5uVmeh4E15WsTP y2l3fT2JUVecDXOLot3MSceiakrgoKNsYQlM+e/+XHwuZ41nZ/OuSCBGjhRn0UDI 1qMqffk5gWiTsZFwLjBV =gsxy -----END PGP SIGNATURE----- Add a .git/index parserializer`) commit.parseHeaders() /* { tree: '0370383003493b845c73fb4316355a18f0e346fe', parent: [ 'c9efafe888804a58e333ec1b64ca58f9c4c92414' ], author: { name: 'Will Hilton', email: 'wmhilton@gmail.com', timestamp: 1503898987, timezoneOffset: 240 }, committer: { name: 'Will Hilton', email: 'wmhilton@gmail.com', timestamp: 1503899426, timezoneOffset: 240 }, gpgsig: '-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v1' } */ ```