The `git` CLI is structured as a series of sub-commands - `git branch` has nothing in common with `git version`, for example. Each of these is modelled as its own file in `src/subcommands`, and should export a default object with the following structure:
```js
export default {
// The subcommand's name
name: 'help',
// A string or array of strings, for how the subcommand is run. Shown in the help.
usage: [
'git help [-a|--all]',
'git help <command>',
],
// A description, shown in the help.
description: `Display help information for git itself, or a subcommand.`,
// Arguments object, passed to `parseArgs()`
args: {
allowPositionals: true,
options: {
all: {
// The one deviation from parseArgs() is that each option gets a description,
// which is shown in the help output.
description: 'List all available subcommands.',
type: 'boolean',
}
},
},
// Function to actually run the subcommand.
// The return value can be a posix-style exit code, or a plain `return` as a shorthand for 0.
// Throwing errors is allowed.
// Throwing the special `SHOW_USAGE` value defined in `src/help.js` can be used to print the command usage text.
execute: async (ctx) => {
// ctx has the following structure:
ctx = {
io: {
stdout, // Function that takes a string, and prints it to stdout
stderr, // Function that takes a string, and prints it to stderr
},
fs, // A filesystem implementation, for isomorphic-git
args, // An object returned from `parseArgs()`.
env, // Object containing environment variables, such as PWD for the current working directory.
}
}
}
```
These are them listed in `src/subcommands/__exports__.js`, which can be automatically generated by running `packages/phoenix/tools/gen.js packages/git/src/subcommands` from the Puter repo root. But it's not hard to modify manually.
## Common patterns
### Shared options
It's common in a few places that options are shared between commands, for example options related to formatting commits are shared by `git log` and `git show`.
In these cases, those options are defined in an object in `src/format.js` with an accompanying function to process their results into a more convenient format.
For example, `diff_formatting_options` and `process_diff_formatting_options(options)`:
Some of the options are shorthands for others; some "imply" another; and some are set by default under certain conditions.
All this is handled in one place instead of in each subcommand that needs them.
### Repo root
Since the `git` command may be run from a repository, a subdirectory, or a non-repository, you can locate the git directory like so:
The `dir` and `gitdir` variables can then be passed to isomorphic-git methods that expect them.
If no repository is found, this will throw an error, which is then printed to stderr.
(isomorphic-git's `git.findRoot()` does not implement checks for a `.git` text file that points to an alternative directory that git's metadata is stored in. We should maybe upstream this.)