fs
You need to pass a file system into isomorphic-git
functions that do anything that involves files (which is most things in git).
In Node, you can pass the builtin fs
module.
In the browser it's more involved because there's no standard 'fs' module.
But you can use any module that implements enough of the fs
API.
Node's fs
If you're only using isomorphic-git in Node, you can just use the native fs
module:
const git = require('isomorphic-git');
const fs = require('fs');
const files = await git.listFiles({ fs, dir: __dirname });
console.log(files)
LightningFS
If you are writing code for the browser, you will need something that emulates the fs
API.
While BrowserFS (see next section) has more features, LightningFS might very well fit your needs.
It was designed from scratch for isomorphic-git
(by the same author) to eek out more performance
for fewer bytes. As an added bonus it's dead simple to configure.
<script src="https://unpkg.com/@isomorphic-git/lightning-fs"></script>
<script src="https://unpkg.com/isomorphic-git"></script>
<script>
const fs = new LightningFS('my-app')
const files = git.listFiles({ fs, dir: '/' });
console.log(files);
</script>
You can configure LightningFS to load files from an HTTP server as well, which makes it easy to prepopulate a browser file system with a directory on your server. See the LightningFS documentation for an example of how to do this.
BrowserFS
At the time of writing, the most complete option is BrowserFS. It has a few more steps involved to set up than in Node, as seen below:
<script src="https://unpkg.com/browserfs@beta"></script>
<script src="https://unpkg.com/isomorphic-git"></script>
<script>
BrowserFS.configure({ fs: "IndexedDB", options: {} }, function (err) {
if (err) return console.log(err);
const fs = BrowserFS.BFSRequire("fs");
const files = git.listFiles({ fs dir: '/' });
console.log(files);
});
</script>
Besides IndexedDB, BrowserFS supports many different backends with different performance characteristics (some backends support sync operations, some only async), as well as different features such as proxying a static file server as a read-only file system, mounting ZIP files as file systems, or overlaying a writeable in-memory filesystem on top of a read-only filesystem. You don't need to know all these features, but familiarizing yourself with the different options may be necessary if you hit a storage limit or performance bottleneck in the IndexedDB backend I suggested above.
An advanced example usage is in the old unit tests for isomorphic-git. It uses HTTPRequestFS to mount (read-only) the test fixtures directory which is stored on the server, then adds a read-write InMemoryFS layer using OverlayFS so that the tests can modify files locally. In between tests it empties the InMemoryFS, restoring the file system to a pristine state. The current unit tests use LightningFS instead, which was built with this HTTP-backed overlay behavior by default, because I find it so useful.
fs
Implementing your own There are actually TWO possible interfaces for an fs
object: the classic "callback" API and the newer "promise" API. If your fs
object provides an enumerable promises
property, isomorphic-git
will use the "promise" API exclusively.
Using the "callback" API
A "callback" fs
object must implement the following subset of node's fs
module:
- fs.readFile(path[, options], callback)
- fs.writeFile(file, data[, options], callback)
- fs.unlink(path, callback)
- fs.readdir(path[, options], callback)
- fs.mkdir(path[, mode], callback)
- fs.rmdir(path, callback)
- fs.stat(path[, options], callback)
- fs.lstat(path[, options], callback)
- fs.readlink(path[, options], callback) (optional ¹)
- fs.symlink(target, path[, type], callback) (optional ¹)
- fs.chmod(path, mode, callback) (optional ²)
Internally, isomorphic-git
wraps the provided "callback" API functions using pify
.
As of node v12 the fs.promises
API has been stabilized. (lightning-fs
also provides a fs.promises
API!) Nowadays, wrapping the callback functions
with pify
is redundant and potentially less performant than using the native promisified versions. Plus, if you're writing your own fs
implementation,
the fs.promises
API lets you write straightforward implementations using async / await
without the messy optional argument handling the callback API needs.
Therefore a second API is now supported...
Using the "promise" API (preferred)
A "promise" fs
object must implement the same set functions as a "callback" implementation, but it implements the promisified versions, and they should all be on a property called promises
:
- fs.promises.readFile(path[, options])
- fs.promises.writeFile(file, data[, options])
- fs.promises.unlink(path)
- fs.promises.readdir(path[, options])
- fs.promises.mkdir(path[, mode])
- fs.promises.rmdir(path)
- fs.promises.stat(path[, options])
- fs.promises.lstat(path[, options])
- fs.promises.readlink(path[, options]) (optional ¹)
- fs.promises.symlink(target, path[, type]) (optional ¹)
- fs.promises.chmod(path, mode) (optional ²)
¹ readlink
and symlink
are only needed to work with git repos that contain symlinks.
² Right now, isomorphic-git rewrites the file if it needs to change its mode. In the future, if chmod
is available it will use that.