just-git 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -124
- package/dist/index.js +377 -367
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/blindmansion/just-git/actions/workflows/ci.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/just-git)
|
|
5
|
+
[](https://bundlejs.com/?q=just-git)
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
Pure TypeScript git implementation. Zero dependencies. 34 commands. Works in Node, Bun, Deno, and the browser.
|
|
8
|
+
|
|
9
|
+
Designed for sandboxed environments where shelling out to real git isn't possible or desirable. Targets faithful reproduction of real git's behavior and output. Operates on an abstract `FileSystem` interface — plug in an in-memory VFS, a real filesystem, or anything else. Pairs with [just-bash](https://github.com/vercel-labs/just-bash), which provides an in-memory filesystem and shell that just-git registers into as a custom command.
|
|
7
10
|
|
|
8
11
|
## Install
|
|
9
12
|
|
|
@@ -37,28 +40,26 @@ await bash.exec("git log --oneline");
|
|
|
37
40
|
|
|
38
41
|
`createGit(options?)` accepts:
|
|
39
42
|
|
|
40
|
-
| Option | Description
|
|
41
|
-
| --------------- |
|
|
42
|
-
| `identity` | Author/committer override. With `locked: true`, always wins over env vars and git config. Without `locked`, acts as a fallback.
|
|
43
|
-
| `credentials` | `(url) => HttpAuth \| null` callback for Smart HTTP transport auth.
|
|
44
|
-
| `disabled` | `GitCommandName[]` of subcommands to block (e.g. `["push", "rebase"]`).
|
|
45
|
-
| `network` | `{ allowed?: string[], fetch?: FetchFunction }` to restrict HTTP access and/or provide a custom `fetch`
|
|
46
|
-
| `resolveRemote` | `(url) => GitContext \| null` callback for cross-VFS remote resolution. See [Multi-agent collaboration](#multi-agent-collaboration).
|
|
43
|
+
| Option | Description |
|
|
44
|
+
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
45
|
+
| `identity` | Author/committer override. With `locked: true`, always wins over env vars and git config. Without `locked`, acts as a fallback. |
|
|
46
|
+
| `credentials` | `(url) => HttpAuth \| null` callback for Smart HTTP transport auth. |
|
|
47
|
+
| `disabled` | `GitCommandName[]` of subcommands to block (e.g. `["push", "rebase"]`). |
|
|
48
|
+
| `network` | `{ allowed?: string[], fetch?: FetchFunction }` to restrict HTTP access and/or provide a custom `fetch`. `allowed` accepts hostnames (`"github.com"`) or URL prefixes (`"https://github.com/myorg/"`). Set to `false` to block all network access. |
|
|
49
|
+
| `resolveRemote` | `(url) => GitContext \| null` callback for cross-VFS remote resolution. See [Multi-agent collaboration](#multi-agent-collaboration). |
|
|
47
50
|
|
|
48
51
|
```ts
|
|
49
52
|
const git = createGit({
|
|
50
53
|
identity: { name: "Agent Bot", email: "bot@company.com", locked: true },
|
|
51
54
|
credentials: async (url) => ({ type: "bearer", token: "ghp_..." }),
|
|
52
55
|
disabled: ["rebase"],
|
|
53
|
-
network:
|
|
56
|
+
network: false, // no HTTP access
|
|
54
57
|
});
|
|
55
58
|
```
|
|
56
59
|
|
|
57
60
|
## Middleware
|
|
58
61
|
|
|
59
|
-
Middleware wraps every `git <subcommand>` invocation. Each middleware receives a `CommandEvent` and a `next()` function. Call `next()` to proceed, or return an `ExecResult` to short-circuit. Middlewares compose in registration order (first registered = outermost).
|
|
60
|
-
|
|
61
|
-
The `CommandEvent` provides the execution context: `{ command, rawArgs, fs, cwd, env, stdin }`, plus optional `exec` and `signal` when available.
|
|
62
|
+
Middleware wraps every `git <subcommand>` invocation. Each middleware receives a `CommandEvent` and a `next()` function. Call `next()` to proceed, or return an `ExecResult` to short-circuit. Middlewares compose in registration order (first registered = outermost). `git.use()` returns an unsubscribe function.
|
|
62
63
|
|
|
63
64
|
```ts
|
|
64
65
|
// Audit log — record every command the agent runs
|
|
@@ -91,15 +92,11 @@ git.use(async (event, next) => {
|
|
|
91
92
|
});
|
|
92
93
|
```
|
|
93
94
|
|
|
94
|
-
`git.use()` returns an unsubscribe function to remove the middleware dynamically.
|
|
95
|
-
|
|
96
95
|
## Hooks
|
|
97
96
|
|
|
98
97
|
Hooks fire at specific points inside command execution (after middleware, inside operation logic). Register with `git.on(event, handler)`, which returns an unsubscribe function.
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
Pre-hooks can abort the operation by returning `{ abort: true, message? }`.
|
|
99
|
+
Pre-hooks can abort the operation by returning `{ abort: true, message? }`. Post-hooks are observational — return value is ignored.
|
|
103
100
|
|
|
104
101
|
```ts
|
|
105
102
|
// Block secrets from being committed
|
|
@@ -116,67 +113,16 @@ git.on("commit-msg", (event) => {
|
|
|
116
113
|
return { abort: true, message: "Commit message must follow conventional commits format" };
|
|
117
114
|
}
|
|
118
115
|
});
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
| Hook | Payload |
|
|
122
|
-
| ------------------ | --------------------------------------------------------------- |
|
|
123
|
-
| `pre-commit` | `{ index, treeHash }` |
|
|
124
|
-
| `commit-msg` | `{ message }` (mutable) |
|
|
125
|
-
| `merge-msg` | `{ message, treeHash, headHash, theirsHash }` (mutable message) |
|
|
126
|
-
| `pre-merge-commit` | `{ mergeMessage, treeHash, headHash, theirsHash }` |
|
|
127
|
-
| `pre-checkout` | `{ target, mode }` |
|
|
128
|
-
| `pre-push` | `{ remote, url, refs[] }` |
|
|
129
|
-
| `pre-fetch` | `{ remote, url, refspecs, prune, tags }` |
|
|
130
|
-
| `pre-clone` | `{ repository, targetPath, bare, branch }` |
|
|
131
|
-
| `pre-pull` | `{ remote, branch }` |
|
|
132
|
-
| `pre-rebase` | `{ upstream, branch }` |
|
|
133
|
-
| `pre-reset` | `{ mode, target }` |
|
|
134
|
-
| `pre-clean` | `{ dryRun, force, removeDirs, removeIgnored, onlyIgnored }` |
|
|
135
|
-
| `pre-rm` | `{ paths, cached, recursive, force }` |
|
|
136
|
-
| `pre-cherry-pick` | `{ mode, commit }` |
|
|
137
|
-
| `pre-revert` | `{ mode, commit }` |
|
|
138
|
-
| `pre-stash` | `{ action, ref }` |
|
|
139
|
-
|
|
140
|
-
### Post-hooks
|
|
141
|
-
|
|
142
|
-
Post-hooks are observational -- return value is ignored. Handlers are awaited in registration order.
|
|
143
116
|
|
|
144
|
-
```ts
|
|
145
117
|
// Feed agent activity to your UI or orchestration layer
|
|
146
118
|
git.on("post-commit", (event) => {
|
|
147
119
|
onAgentCommit({ hash: event.hash, branch: event.branch, message: event.message });
|
|
148
120
|
});
|
|
149
|
-
|
|
150
|
-
git.on("post-push", (event) => {
|
|
151
|
-
onAgentPush({ remote: event.remote, refs: event.refs });
|
|
152
|
-
});
|
|
153
121
|
```
|
|
154
122
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
| `post-merge` | `{ headHash, theirsHash, strategy, commitHash }` |
|
|
159
|
-
| `post-checkout` | `{ prevHead, newHead, isBranchCheckout }` |
|
|
160
|
-
| `post-push` | same payload as `pre-push` |
|
|
161
|
-
| `post-fetch` | `{ remote, url, refsUpdated }` |
|
|
162
|
-
| `post-clone` | `{ repository, targetPath, bare, branch }` |
|
|
163
|
-
| `post-pull` | `{ remote, branch, strategy, commitHash }` |
|
|
164
|
-
| `post-reset` | `{ mode, targetHash }` |
|
|
165
|
-
| `post-clean` | `{ removed, dryRun }` |
|
|
166
|
-
| `post-rm` | `{ removedPaths, cached }` |
|
|
167
|
-
| `post-cherry-pick` | `{ mode, commitHash, hadConflicts }` |
|
|
168
|
-
| `post-revert` | `{ mode, commitHash, hadConflicts }` |
|
|
169
|
-
| `post-stash` | `{ action, ok }` |
|
|
170
|
-
|
|
171
|
-
### Low-level events
|
|
172
|
-
|
|
173
|
-
Fire-and-forget events emitted on every object/ref write. Handler errors are caught and forwarded to `hooks.onError` (no-op by default).
|
|
174
|
-
|
|
175
|
-
| Event | Payload |
|
|
176
|
-
| -------------- | --------------------------- |
|
|
177
|
-
| `ref:update` | `{ ref, oldHash, newHash }` |
|
|
178
|
-
| `ref:delete` | `{ ref, oldHash }` |
|
|
179
|
-
| `object:write` | `{ type, hash }` |
|
|
123
|
+
Available pre-hooks: `pre-commit`, `commit-msg`, `merge-msg`, `pre-merge-commit`, `pre-checkout`, `pre-push`, `pre-fetch`, `pre-clone`, `pre-pull`, `pre-rebase`, `pre-reset`, `pre-clean`, `pre-rm`, `pre-cherry-pick`, `pre-revert`, `pre-stash`. Available post-hooks: `post-commit`, `post-merge`, `post-checkout`, `post-push`, `post-fetch`, `post-clone`, `post-pull`, `post-reset`, `post-clean`, `post-rm`, `post-cherry-pick`, `post-revert`, `post-stash`. Low-level events: `ref:update`, `ref:delete`, `object:write`.
|
|
124
|
+
|
|
125
|
+
See [HOOKS.md](HOOKS.md) for full payload types and the `CommandEvent` shape.
|
|
180
126
|
|
|
181
127
|
## Multi-agent collaboration
|
|
182
128
|
|
|
@@ -200,22 +146,33 @@ await setupBash.exec("echo 'hello' > README.md");
|
|
|
200
146
|
await setupBash.exec("git add . && git commit -m 'initial'");
|
|
201
147
|
|
|
202
148
|
const originCtx = await findGitDir(originFs, "/repo");
|
|
149
|
+
const resolve = (url: string) => (url === "/origin" ? originCtx : null);
|
|
203
150
|
|
|
204
151
|
// Each agent gets its own filesystem + resolveRemote pointing to origin
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
152
|
+
const alice = new Bash({
|
|
153
|
+
fs: new InMemoryFs(),
|
|
154
|
+
cwd: "/repo",
|
|
155
|
+
customCommands: [
|
|
156
|
+
createGit({
|
|
157
|
+
identity: { name: "Alice", email: "alice@example.com", locked: true },
|
|
158
|
+
resolveRemote: resolve,
|
|
159
|
+
}),
|
|
160
|
+
],
|
|
161
|
+
});
|
|
213
162
|
|
|
214
|
-
const
|
|
215
|
-
|
|
163
|
+
const bob = new Bash({
|
|
164
|
+
fs: new InMemoryFs(),
|
|
165
|
+
cwd: "/repo",
|
|
166
|
+
customCommands: [
|
|
167
|
+
createGit({
|
|
168
|
+
identity: { name: "Bob", email: "bob@example.com", locked: true },
|
|
169
|
+
resolveRemote: resolve,
|
|
170
|
+
}),
|
|
171
|
+
],
|
|
172
|
+
});
|
|
216
173
|
|
|
217
|
-
await alice.exec("git clone /origin /repo"
|
|
218
|
-
await bob.exec("git clone /origin /repo"
|
|
174
|
+
await alice.exec("git clone /origin /repo");
|
|
175
|
+
await bob.exec("git clone /origin /repo");
|
|
219
176
|
|
|
220
177
|
// Alice and Bob work independently, push to origin, fetch each other's changes
|
|
221
178
|
```
|
|
@@ -228,46 +185,47 @@ See [`examples/multi-agent.ts`](examples/multi-agent.ts) for a full working exam
|
|
|
228
185
|
|
|
229
186
|
See [CLI.md](CLI.md) for full usage details.
|
|
230
187
|
|
|
231
|
-
| Command | Flags / options
|
|
232
|
-
| --------------------------------- |
|
|
233
|
-
| `init [<dir>]` | `--bare`, `--initial-branch`
|
|
234
|
-
| `clone <repo> [<dir>]` | `--bare`, `-b <branch>`
|
|
235
|
-
| `blame <file>` | `-L <start>,<end>`, `-l`/`--long`, `-e`/`--show-email`, `-s`/`--suppress`, `-p`/`--porcelain`, `--line-porcelain`
|
|
236
|
-
| `add <paths>` | `.`, `--all`/`-A`, `--update`/`-u`, `--force`/`-f`, `-n`/`--dry-run`, glob pathspecs
|
|
237
|
-
| `rm <paths>` | `--cached`, `-r`, `-f`, `-n`/`--dry-run`, glob pathspecs
|
|
238
|
-
| `mv <src> <dst>` | `-f`, `-n`/`--dry-run`, `-k`
|
|
239
|
-
| `commit` | `-m`, `-F <file>` / `-F -`, `--allow-empty`, `--amend`, `--no-edit`, `-a`
|
|
240
|
-
| `status` | `-s`/`--short`, `--porcelain`, `-b`/`--branch`
|
|
241
|
-
| `log` | `--oneline`, `-n`, `--all`, `--reverse`, `--decorate`, `--format`/`--pretty`, `A..B`, `A...B`, `-- <path>`, `--author=`, `--grep=`, `--since`/`--after`, `--until`/`--before`
|
|
242
|
-
| `show [<object>]` | Commits (with diff), annotated tags, trees, blobs
|
|
243
|
-
| `diff` | `--cached`/`--staged`, `<commit>`, `<commit> <commit>`, `A..B`, `A...B`, `-- <path>`, `--stat`, `--shortstat`, `--numstat`, `--name-only`, `--name-status`
|
|
244
|
-
| `branch` | `-d`, `-D`, `-m`, `-M`, `-r`, `-a`/`--all`, `-v`/`-vv`, `-u`/`--set-upstream-to`
|
|
245
|
-
| `tag [<name>] [<commit>]` | `-a -m` (annotated), `-d`, `-l <pattern>`, `-f`
|
|
246
|
-
| `switch` | `-c`/`-C` (create/force-create), `--detach`/`-d`, `--orphan`, `-` (previous branch), `--guess`/`--no-guess`
|
|
247
|
-
| `restore` | `-s`/`--source`, `-S`/`--staged`, `-W`/`--worktree`, `-S -W` (both), `--ours`/`--theirs`, pathspec globs
|
|
248
|
-
| `checkout` | `-b`, `-B`, `--orphan`, detached HEAD, `-- <paths>`, `--ours`/`--theirs`, pathspec globs
|
|
249
|
-
| `reset [<commit>]` | `-- <paths>`, `--soft`, `--mixed`, `--hard`, pathspec globs
|
|
250
|
-
| `merge <branch>` | `--no-ff`, `--ff-only`, `--squash`, `-m`, `--abort`, `--continue`, conflict markers
|
|
251
|
-
| `revert <commit>` | `--abort`, `--continue`, `-n`/`--no-commit`, `--no-edit`, `-m`/`--mainline`
|
|
252
|
-
| `cherry-pick <commit>` | `--abort`, `--continue`, `--skip`, `-x`, `-m`/`--mainline`, `-n`/`--no-commit`, preserves original author
|
|
253
|
-
| `rebase <upstream>` | `--onto <newbase>`, `--abort`, `--continue`, `--skip`
|
|
254
|
-
| `stash` | `push`, `pop`, `apply`, `list`, `drop`, `show`, `clear`, `-m`, `-u`/`--include-untracked`, `stash@{N}`
|
|
255
|
-
| `remote` | `add`, `remove`/`rm`, `rename`, `set-url`, `get-url`, `-v`
|
|
256
|
-
| `config` | `get`, `set`, `unset`, `list`, `--list`/`-l`, `--unset`
|
|
257
|
-
| `fetch [<remote>] [<refspec>...]` | `--all`, `--tags`, `--prune`/`-p`
|
|
258
|
-
| `push [<remote>] [<refspec>...]` | `--force`/`-f`, `-u`/`--set-upstream`, `--all`, `--tags`, `--delete`/`-d`
|
|
259
|
-
| `pull [<remote>] [<branch>]` | `--ff-only`, `--no-ff`, `--rebase`/`-r`, `--no-rebase`
|
|
260
|
-
| `bisect` | `start`, `bad`/`good`/`new`/`old`, `skip`, `reset`, `log`, `replay`, `run`, `terms`, `visualize`/`view`, `--term-new`/`--term-old`, `--no-checkout`, `--first-parent`
|
|
261
|
-
| `clean` | `-f`, `-n`/`--dry-run`, `-d`, `-x`, `-X`, `-e`/`--exclude`
|
|
262
|
-
| `reflog` | `show [<ref>]`, `exists`, `-n`/`--max-count`
|
|
263
|
-
| `gc` | `--aggressive`
|
|
264
|
-
| `repack` | `-a`/`--all`, `-d`/`--delete`
|
|
265
|
-
| `rev-parse` | `--verify`, `--short`, `--abbrev-ref`, `--symbolic-full-name`, `--show-toplevel`, `--git-dir`, `--is-inside-work-tree`, `--is-bare-repository`, `--show-prefix`, `--show-cdup`
|
|
266
|
-
| `ls-files` | `-c`/`--cached`, `-m`/`--modified`, `-d`/`--deleted`, `-o`/`--others`, `-u`/`--unmerged`, `-s`/`--stage`, `--exclude-standard`, `-z`, `-t`
|
|
188
|
+
| Command | Flags / options |
|
|
189
|
+
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
190
|
+
| `init [<dir>]` | `--bare`, `--initial-branch` |
|
|
191
|
+
| `clone <repo> [<dir>]` | `--bare`, `-b <branch>` |
|
|
192
|
+
| `blame <file>` | `-L <start>,<end>`, `-l`/`--long`, `-e`/`--show-email`, `-s`/`--suppress`, `-p`/`--porcelain`, `--line-porcelain` |
|
|
193
|
+
| `add <paths>` | `.`, `--all`/`-A`, `--update`/`-u`, `--force`/`-f`, `-n`/`--dry-run`, glob pathspecs |
|
|
194
|
+
| `rm <paths>` | `--cached`, `-r`, `-f`, `-n`/`--dry-run`, glob pathspecs |
|
|
195
|
+
| `mv <src> <dst>` | `-f`, `-n`/`--dry-run`, `-k` |
|
|
196
|
+
| `commit` | `-m`, `-F <file>` / `-F -`, `--allow-empty`, `--amend`, `--no-edit`, `-a` |
|
|
197
|
+
| `status` | `-s`/`--short`, `--porcelain`, `-b`/`--branch` |
|
|
198
|
+
| `log` | `--oneline`, `-n`, `--all`, `--reverse`, `--decorate`, `--format`/`--pretty`, `-p`/`--patch`, `--stat`, `--name-status`, `--name-only`, `--shortstat`, `--numstat`, `A..B`, `A...B`, `-- <path>`, `--author=`, `--grep=`, `--since`/`--after`, `--until`/`--before` |
|
|
199
|
+
| `show [<object>]` | Commits (with diff), annotated tags, trees, blobs |
|
|
200
|
+
| `diff` | `--cached`/`--staged`, `<commit>`, `<commit> <commit>`, `A..B`, `A...B`, `-- <path>`, `--stat`, `--shortstat`, `--numstat`, `--name-only`, `--name-status` |
|
|
201
|
+
| `branch` | `-d`, `-D`, `-m`, `-M`, `-r`, `-a`/`--all`, `-v`/`-vv`, `-u`/`--set-upstream-to` |
|
|
202
|
+
| `tag [<name>] [<commit>]` | `-a -m` (annotated), `-d`, `-l <pattern>`, `-f` |
|
|
203
|
+
| `switch` | `-c`/`-C` (create/force-create), `--detach`/`-d`, `--orphan`, `-` (previous branch), `--guess`/`--no-guess` |
|
|
204
|
+
| `restore` | `-s`/`--source`, `-S`/`--staged`, `-W`/`--worktree`, `-S -W` (both), `--ours`/`--theirs`, pathspec globs |
|
|
205
|
+
| `checkout` | `-b`, `-B`, `--orphan`, detached HEAD, `-- <paths>`, `--ours`/`--theirs`, pathspec globs |
|
|
206
|
+
| `reset [<commit>]` | `-- <paths>`, `--soft`, `--mixed`, `--hard`, pathspec globs |
|
|
207
|
+
| `merge <branch>` | `--no-ff`, `--ff-only`, `--squash`, `-m`, `--abort`, `--continue`, conflict markers |
|
|
208
|
+
| `revert <commit>` | `--abort`, `--continue`, `-n`/`--no-commit`, `--no-edit`, `-m`/`--mainline` |
|
|
209
|
+
| `cherry-pick <commit>` | `--abort`, `--continue`, `--skip`, `-x`, `-m`/`--mainline`, `-n`/`--no-commit`, preserves original author |
|
|
210
|
+
| `rebase <upstream>` | `--onto <newbase>`, `--abort`, `--continue`, `--skip` |
|
|
211
|
+
| `stash` | `push`, `pop`, `apply`, `list`, `drop`, `show`, `clear`, `-m`, `-u`/`--include-untracked`, `stash@{N}` |
|
|
212
|
+
| `remote` | `add`, `remove`/`rm`, `rename`, `set-url`, `get-url`, `-v` |
|
|
213
|
+
| `config` | `get`, `set`, `unset`, `list`, `--list`/`-l`, `--unset` |
|
|
214
|
+
| `fetch [<remote>] [<refspec>...]` | `--all`, `--tags`, `--prune`/`-p` |
|
|
215
|
+
| `push [<remote>] [<refspec>...]` | `--force`/`-f`, `-u`/`--set-upstream`, `--all`, `--tags`, `--delete`/`-d` |
|
|
216
|
+
| `pull [<remote>] [<branch>]` | `--ff-only`, `--no-ff`, `--rebase`/`-r`, `--no-rebase` |
|
|
217
|
+
| `bisect` | `start`, `bad`/`good`/`new`/`old`, `skip`, `reset`, `log`, `replay`, `run`, `terms`, `visualize`/`view`, `--term-new`/`--term-old`, `--no-checkout`, `--first-parent` |
|
|
218
|
+
| `clean` | `-f`, `-n`/`--dry-run`, `-d`, `-x`, `-X`, `-e`/`--exclude` |
|
|
219
|
+
| `reflog` | `show [<ref>]`, `exists`, `-n`/`--max-count` |
|
|
220
|
+
| `gc` | `--aggressive` |
|
|
221
|
+
| `repack` | `-a`/`--all`, `-d`/`--delete` |
|
|
222
|
+
| `rev-parse` | `--verify`, `--short`, `--abbrev-ref`, `--symbolic-full-name`, `--show-toplevel`, `--git-dir`, `--is-inside-work-tree`, `--is-bare-repository`, `--show-prefix`, `--show-cdup` |
|
|
223
|
+
| `ls-files` | `-c`/`--cached`, `-m`/`--modified`, `-d`/`--deleted`, `-o`/`--others`, `-u`/`--unmerged`, `-s`/`--stage`, `--exclude-standard`, `-z`, `-t` |
|
|
267
224
|
|
|
268
225
|
### Transport
|
|
269
226
|
|
|
270
227
|
- **Local paths** -- direct filesystem transfer between repositories.
|
|
228
|
+
- **Cross-VFS** -- clone, fetch, and push between isolated in-memory filesystems via `resolveRemote`. See [Multi-agent collaboration](#multi-agent-collaboration).
|
|
271
229
|
- **Smart HTTP** -- clone, fetch, and push against real Git servers (e.g. GitHub) via Git Smart HTTP protocol. Auth via `credentials` option or `GIT_HTTP_BEARER_TOKEN` / `GIT_HTTP_USER` + `GIT_HTTP_PASSWORD` env vars.
|
|
272
230
|
|
|
273
231
|
### Internals
|
|
@@ -280,12 +238,29 @@ See [CLI.md](CLI.md) for full usage details.
|
|
|
280
238
|
- Packfiles with zlib compression for storage and transport
|
|
281
239
|
- Pathspec globs across `add`, `rm`, `diff`, `reset`, `checkout`, `restore`, `log`
|
|
282
240
|
|
|
283
|
-
##
|
|
241
|
+
## Testing
|
|
242
|
+
|
|
243
|
+
Targets high fidelity to real git (2.53.0). Tested with an [oracle framework](test/oracle/README.md) that generates hundreds of randomized git workflows totaling hundreds of thousands of operations, runs them against real git, then replays each step against just-git and compares repository state and command output. State comparison covers HEAD, refs, index, worktree, active operation state, and stash. Output comparison covers exit codes, stdout, and stderr.
|
|
244
|
+
|
|
245
|
+
When backed by a real filesystem (e.g. just-bash `ReadWriteFs`), interoperable with real git on the same repo, though less extensively tested than behavioral correctness.
|
|
246
|
+
|
|
247
|
+
## Without just-bash
|
|
284
248
|
|
|
285
|
-
|
|
249
|
+
`git.execute()` takes an args array and a `CommandContext`. Provide any `FileSystem` implementation:
|
|
286
250
|
|
|
287
|
-
|
|
251
|
+
```ts
|
|
252
|
+
import { createGit } from "just-git";
|
|
288
253
|
|
|
289
|
-
|
|
254
|
+
const git = createGit({ identity: { name: "Bot", email: "bot@example.com" } });
|
|
255
|
+
|
|
256
|
+
const result = await git.execute(["init"], {
|
|
257
|
+
fs: myFileSystem, // any FileSystem implementation
|
|
258
|
+
cwd: "/repo",
|
|
259
|
+
env: new Map(),
|
|
260
|
+
stdin: "",
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
console.log(result.exitCode); // 0
|
|
264
|
+
```
|
|
290
265
|
|
|
291
|
-
|
|
266
|
+
The `FileSystem` interface requires: `readFile`, `readFileBuffer`, `writeFile`, `exists`, `stat`, `mkdir`, `readdir`, `rm`. Optional: `lstat`, `readlink`, `symlink`.
|