isomorphic-jj 1.4.3 → 1.8.0
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/CHANGELOG.md +428 -0
- package/README.md +138 -29
- package/bin/isojj.js +273 -102
- package/dist/index.cjs +3401 -1683
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +3401 -1683
- package/dist/index.mjs.map +1 -1
- package/package.json +21 -7
- package/src/api/repository.js +1301 -745
- package/src/backend/isomorphic-git-backend.js +241 -138
- package/src/backend/lazy-git-backend.js +12 -19
- package/src/browser/helpers.js +8 -4
- package/src/core/background-ops.js +58 -41
- package/src/core/bookmark-store.js +12 -8
- package/src/core/change-graph.js +26 -29
- package/src/core/conflict-model.js +66 -26
- package/src/core/jj-checkout.js +8 -4
- package/src/core/jj-operation-store.js +21 -14
- package/src/core/jj-tree-state.js +16 -11
- package/src/core/jj-view-store.js +14 -7
- package/src/core/merge-driver-registry.js +92 -46
- package/src/core/operation-log.js +30 -33
- package/src/core/revset-engine.js +1114 -485
- package/src/core/storage-manager.js +73 -30
- package/src/core/tag-store.js +42 -12
- package/src/core/user-config.js +3 -1
- package/src/core/working-copy.js +125 -9
- package/src/core/workspace-manager.js +2 -2
- package/src/drivers/built-in-drivers.js +66 -33
- package/src/types.d.ts +67 -1
- package/src/utils/atomic-write.js +44 -0
- package/src/utils/errors.js +3 -3
- package/src/utils/id-generation.js +4 -4
- package/src/utils/mutex.js +63 -0
- package/src/utils/validation.js +6 -10
package/README.md
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
# isomorphic-jj
|
|
1
|
+
# @johnhenry/isomorphic-jj
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://github.com/johnhenry/isomorphic-jj)
|
|
5
|
-
[](LICENSE)
|
|
3
|
+
> **This package has moved to `@johnhenry/isomorphic-jj`.** This is the final release under the old name.
|
|
6
4
|
|
|
7
5
|
> **Jujutsu version control for JavaScript**—stable change IDs, fearless undo, and no staging area. Works in Node.js and browsers.
|
|
8
6
|
|
|
7
|
+
Full documentation: [opensource.johnhenry.me/isomorphic-jj](https://opensource.johnhenry.me/isomorphic-jj/)
|
|
8
|
+
|
|
9
|
+
> Previously published as `isomorphic-jj` (final release 1.8.0, deprecated in
|
|
10
|
+
> favor of this package). Renamed to `@johnhenry/isomorphic-jj` and restarted
|
|
11
|
+
> at 0.0.0 on import into the @johnhenry family — a new address and era, not
|
|
12
|
+
> a maturity signal.
|
|
13
|
+
|
|
14
|
+
[](https://www.npmjs.com/package/@johnhenry/isomorphic-jj)
|
|
15
|
+
[](https://github.com/johnhenry/isomorphic-jj/actions/workflows/test.yml)
|
|
16
|
+
[](LICENSE)
|
|
17
|
+
|
|
9
18
|
**What makes it different:**
|
|
10
19
|
- 🎯 **Stable change IDs** that survive rebases/squashes
|
|
11
20
|
- ↩️ **Complete undo** for any operation (not just commits)
|
|
@@ -14,7 +23,7 @@
|
|
|
14
23
|
- 🌐 **True isomorphic**—same API in Node, browsers, and Web Workers
|
|
15
24
|
|
|
16
25
|
```javascript
|
|
17
|
-
import { createJJ } from 'isomorphic-jj';
|
|
26
|
+
import { createJJ } from '@johnhenry/isomorphic-jj';
|
|
18
27
|
import git from 'isomorphic-git';
|
|
19
28
|
import fs from 'fs';
|
|
20
29
|
|
|
@@ -30,6 +39,60 @@ await jj.undo();
|
|
|
30
39
|
|
|
31
40
|
---
|
|
32
41
|
|
|
42
|
+
## Try it in 60 seconds
|
|
43
|
+
|
|
44
|
+
### CLI
|
|
45
|
+
|
|
46
|
+
Every method is reachable from the `isojj` CLI (`bin/isojj.js`). Run it with
|
|
47
|
+
`npx`, or install it globally (`npm i -g @johnhenry/isomorphic-jj`) and call
|
|
48
|
+
`isojj` directly:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx @johnhenry/isomorphic-jj init
|
|
52
|
+
echo "# hello" > README.md
|
|
53
|
+
npx @johnhenry/isomorphic-jj describe -m "Initial commit"
|
|
54
|
+
npx @johnhenry/isomorphic-jj new -m "Add a feature"
|
|
55
|
+
npx @johnhenry/isomorphic-jj log
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
Change History:
|
|
60
|
+
|
|
61
|
+
cb7b4e93fd23 Add a feature
|
|
62
|
+
You 9/2/2026, 7:20:30 AM
|
|
63
|
+
|
|
64
|
+
a2f6f5af8107 Initial commit
|
|
65
|
+
You 9/2/2026, 7:20:30 AM
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Run `npx @johnhenry/isomorphic-jj --help` for the full command list.
|
|
69
|
+
|
|
70
|
+
### Node.js
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
import { createJJ } from '@johnhenry/isomorphic-jj';
|
|
74
|
+
import fs from 'fs';
|
|
75
|
+
|
|
76
|
+
const jj = await createJJ({ fs, dir: './my-repo' });
|
|
77
|
+
await jj.init({ userName: 'You', userEmail: 'you@example.com' });
|
|
78
|
+
await jj.write({ path: 'README.md', data: '# hello\n' });
|
|
79
|
+
await jj.describe({ message: 'Initial commit' });
|
|
80
|
+
console.log(await jj.log({ limit: 5 }));
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Browser
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
import { createJJ } from '@johnhenry/isomorphic-jj';
|
|
87
|
+
import { createBrowserFS } from '@johnhenry/isomorphic-jj/browser';
|
|
88
|
+
|
|
89
|
+
const fs = createBrowserFS({ name: 'my-repo' });
|
|
90
|
+
const jj = await createJJ({ fs, dir: '/repo' });
|
|
91
|
+
// Same API as Node from here on — see examples/12-browser.mjs.
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
33
96
|
## Quick Start
|
|
34
97
|
|
|
35
98
|
**Coming from isomorphic-git?** Read the [Migration Guide](./MIGRATION_FROM_ISOMORPHIC_GIT.md) to see how isomorphic-jj simplifies your JavaScript version control workflow.
|
|
@@ -42,6 +105,43 @@ This showcases all 17 feature categories (including v1.0 enhancements) in ~3 sec
|
|
|
42
105
|
|
|
43
106
|
---
|
|
44
107
|
|
|
108
|
+
## Examples
|
|
109
|
+
|
|
110
|
+
The [`examples/`](./examples) directory has 12 numbered, runnable, self-asserting
|
|
111
|
+
scripts — each creates a repo in a temp dir, demonstrates one area, and cleans
|
|
112
|
+
up after itself. Run one with `npm run example:01` (etc.), or the whole set
|
|
113
|
+
(the same loop CI runs) with:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npm run examples
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
| # | What it shows |
|
|
120
|
+
|---|----------------|
|
|
121
|
+
| [01](./examples/01-init-commit-log.mjs) | The core loop: init → write → `describe()` → `new()` → `log()` |
|
|
122
|
+
| [02](./examples/02-stacked-changes.mjs) | Stable change IDs across a 3-layer stack; `edit()`+`amend()` a bottom layer |
|
|
123
|
+
| [03](./examples/03-history-editing.mjs) | `split()`, `squash({ into })`, `abandon()`/`unabandon()`, `duplicate()` |
|
|
124
|
+
| [04](./examples/04-branching-and-merging.mjs) | Diverging without branches; content merge vs. true merge changes |
|
|
125
|
+
| [05](./examples/05-conflicts.mjs) | First-class conflicts: dry-run preview, `conflicts.list()`/`resolve()` |
|
|
126
|
+
| [06](./examples/06-revsets.mjs) | The revset query language, end to end |
|
|
127
|
+
| [07](./examples/07-bookmarks-and-tags.mjs) | Bookmarks, tags, and remote tracking |
|
|
128
|
+
| [08](./examples/08-git-interop.mjs) | Real `git.clone()`/`push()`/`fetch()` against a local fixture, zero network |
|
|
129
|
+
| [09](./examples/09-config.mjs) | Config layers: persisted, programmatic, deep-merge, reset |
|
|
130
|
+
| [10](./examples/10-undo-and-oplog.mjs) | `undo()`/`redo()`, `operations.at()` time travel, `obslog()` |
|
|
131
|
+
| [11](./examples/11-file-operations.mjs) | The `file.*` namespace: historical `show()`, `annotate()`, `search()` |
|
|
132
|
+
| [12](./examples/12-browser.mjs) | Browser usage (IndexedDB fs, persistence, CORS proxy) as a reference |
|
|
133
|
+
|
|
134
|
+
See [`examples/README.md`](./examples/README.md) for details and conventions.
|
|
135
|
+
|
|
136
|
+
Three fuller example applications live under [`example/`](./example) — each
|
|
137
|
+
exercises the library from a different angle and documents the bugs it found:
|
|
138
|
+
|
|
139
|
+
- [`jj-review-tool`](./example/jj-review-tool) — a code-review CLI built on stacked changes and bookmarks.
|
|
140
|
+
- [`jj-storage-server`](./example/jj-storage-server) — a REST API using isomorphic-jj as a versioned document store.
|
|
141
|
+
- [`jj-wiki`](./example/jj-wiki) — a collaborative wiki exercising workspaces and conflict resolution.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
45
145
|
## What's New in v1.0
|
|
46
146
|
|
|
47
147
|
isomorphic-jj v1.0 achieves **complete JJ CLI semantic compatibility** while maintaining 100% backward compatibility:
|
|
@@ -76,6 +176,7 @@ isomorphic-jj v1.0 now implements virtually all commonly-used JJ CLI commands:
|
|
|
76
176
|
- **`git.remote.*`** - Complete remote management (list, add, remove, rename, setUrl)
|
|
77
177
|
- **`bookmark.rename()`** - Rename bookmarks
|
|
78
178
|
- **`bookmark.track/untrack/forget()`** - Remote bookmark management
|
|
179
|
+
- **`tag.track/untrack()`** - Remote tag management (jj v0.44)
|
|
79
180
|
- **`config.*`** - Configuration management (get, set, list)
|
|
80
181
|
- **`diff()`** - Show file differences between revisions
|
|
81
182
|
- **`next()` / `prev()`** - Navigate between parent/child revisions
|
|
@@ -85,10 +186,10 @@ isomorphic-jj v1.0 now implements virtually all commonly-used JJ CLI commands:
|
|
|
85
186
|
- **`operations.show/diff/restore()`** - Advanced operation log features
|
|
86
187
|
- **`remote.*`** - Convenience aliases for git operations (push, fetch, add)
|
|
87
188
|
|
|
88
|
-
See [
|
|
189
|
+
See [ROADMAP.md](./ROADMAP.md) for the release-by-release feature comparison and what's still planned.
|
|
89
190
|
|
|
90
191
|
### Testing & Quality
|
|
91
|
-
- **
|
|
192
|
+
- **1730 tests** passing — ~97% statement / 91% branch coverage
|
|
92
193
|
- **100% backward compatible** - All existing code continues to work
|
|
93
194
|
- **Zero breaking changes** - Deprecated features show warnings but still function
|
|
94
195
|
|
|
@@ -97,7 +198,7 @@ See [JJ_CLI_PARITY.md](./JJ_CLI_PARITY.md) for complete feature comparison.
|
|
|
97
198
|
### Installation
|
|
98
199
|
|
|
99
200
|
```bash
|
|
100
|
-
npm install isomorphic-jj isomorphic-git
|
|
201
|
+
npm install @johnhenry/isomorphic-jj isomorphic-git
|
|
101
202
|
```
|
|
102
203
|
|
|
103
204
|
For browsers, also install:
|
|
@@ -108,7 +209,7 @@ npm install @isomorphic-git/lightning-fs
|
|
|
108
209
|
### Basic Workflow
|
|
109
210
|
|
|
110
211
|
```javascript
|
|
111
|
-
import { createJJ } from 'isomorphic-jj';
|
|
212
|
+
import { createJJ } from '@johnhenry/isomorphic-jj';
|
|
112
213
|
import git from 'isomorphic-git';
|
|
113
214
|
import fs from 'fs';
|
|
114
215
|
import http from 'isomorphic-git/http/node';
|
|
@@ -147,8 +248,8 @@ console.log(log);
|
|
|
147
248
|
### Browser Usage
|
|
148
249
|
|
|
149
250
|
```javascript
|
|
150
|
-
import { createJJ } from 'isomorphic-jj';
|
|
151
|
-
import { createBrowserFS } from 'isomorphic-jj/browser';
|
|
251
|
+
import { createJJ } from '@johnhenry/isomorphic-jj';
|
|
252
|
+
import { createBrowserFS } from '@johnhenry/isomorphic-jj/browser';
|
|
152
253
|
import git from 'isomorphic-git';
|
|
153
254
|
import http from 'isomorphic-git/http/web';
|
|
154
255
|
|
|
@@ -494,7 +595,7 @@ await jj.undo();
|
|
|
494
595
|
Merge drivers enable smart merging of structured files like JSON, package.json, and YAML:
|
|
495
596
|
|
|
496
597
|
```javascript
|
|
497
|
-
import { jsonDriver, packageJsonDriver, yamlDriver, markdownDriver } from 'isomorphic-jj';
|
|
598
|
+
import { jsonDriver, packageJsonDriver, yamlDriver, markdownDriver } from '@johnhenry/isomorphic-jj';
|
|
498
599
|
|
|
499
600
|
// Register merge drivers for different file types
|
|
500
601
|
jj.mergeDrivers.register({
|
|
@@ -625,7 +726,7 @@ const bookmarks = await jj.bookmark.list();
|
|
|
625
726
|
### Browser Support
|
|
626
727
|
|
|
627
728
|
```javascript
|
|
628
|
-
import { createBrowserFS, requestPersistentStorage } from 'isomorphic-jj/browser';
|
|
729
|
+
import { createBrowserFS, requestPersistentStorage } from '@johnhenry/isomorphic-jj/browser';
|
|
629
730
|
|
|
630
731
|
// Request persistent storage (prevents eviction)
|
|
631
732
|
const persistent = await requestPersistentStorage();
|
|
@@ -634,14 +735,14 @@ const persistent = await requestPersistentStorage();
|
|
|
634
735
|
const fs = createBrowserFS({ backend: 'idb', name: 'my-repo' });
|
|
635
736
|
|
|
636
737
|
// Check browser capabilities
|
|
637
|
-
import { detectCapabilities } from 'isomorphic-jj/browser';
|
|
738
|
+
import { detectCapabilities } from '@johnhenry/isomorphic-jj/browser';
|
|
638
739
|
const caps = detectCapabilities();
|
|
639
740
|
if (caps.indexedDB && caps.serviceWorker) {
|
|
640
741
|
// Enable offline support
|
|
641
742
|
}
|
|
642
743
|
|
|
643
744
|
// Get storage quota
|
|
644
|
-
import { getStorageQuota } from 'isomorphic-jj/browser';
|
|
745
|
+
import { getStorageQuota } from '@johnhenry/isomorphic-jj/browser';
|
|
645
746
|
const quota = await getStorageQuota();
|
|
646
747
|
console.log(`Using ${quota.percentage}% of available storage`);
|
|
647
748
|
```
|
|
@@ -794,7 +895,7 @@ Full API documentation available in [TypeScript definitions](./src/types.d.ts).
|
|
|
794
895
|
### Main Interface
|
|
795
896
|
|
|
796
897
|
```typescript
|
|
797
|
-
import { createJJ, type JJ, type CreateJJOptions } from 'isomorphic-jj';
|
|
898
|
+
import { createJJ, type JJ, type CreateJJOptions } from '@johnhenry/isomorphic-jj';
|
|
798
899
|
|
|
799
900
|
const jj: JJ = await createJJ(options: CreateJJOptions);
|
|
800
901
|
```
|
|
@@ -898,9 +999,10 @@ repo/
|
|
|
898
999
|
|
|
899
1000
|
## Project Status
|
|
900
1001
|
|
|
901
|
-
**Current Version**:
|
|
902
|
-
**Test Coverage**:
|
|
903
|
-
**
|
|
1002
|
+
**Current Version**: 0.2.0 (`@johnhenry/isomorphic-jj`; same library/API lineage as the old `isomorphic-jj`, which reached v1.7.0 before the rename — see the provenance note at the top of this file)
|
|
1003
|
+
**Test Coverage**: 1730 tests passing, ~97% statements / 91% branches
|
|
1004
|
+
**JJ CLI parity**: tracks Jujutsu through v0.44
|
|
1005
|
+
**Status**: Actively developed; broad JJ CLI semantic parity, used in the examples/apps in this repo and in [JJHub](#related-projects). Not yet 1.0 — API surface can still shift; pin a version and read the CHANGELOG before upgrading.
|
|
904
1006
|
|
|
905
1007
|
**Completed:**
|
|
906
1008
|
- ✅ v0.1: Core JJ experience (stable IDs, undo, bookmarks, revsets)
|
|
@@ -908,13 +1010,12 @@ repo/
|
|
|
908
1010
|
- ✅ v0.3: Git backend, conflicts, workspaces, browser support
|
|
909
1011
|
- ✅ v0.4: Shallow clones, advanced revsets, event system
|
|
910
1012
|
- ✅ v0.5: Custom merge drivers, enhanced revsets (time-based, graph analytics), conflict resolution enhancements
|
|
1013
|
+
- ✅ v1.0: Full JJ CLI semantic parity, complete `file.*`/`operations.*`/`git.*` namespaces
|
|
1014
|
+
- ✅ v1.5: Parity refresh tracking jj through **v0.43** — new revsets (`change_id`, `commit_id`, `subject`, `author_name`/`email`, `committer*`, `signed`, `divergent`, `merges`, `forks`, `first_parent`, `first_ancestors`, `fork_point`, `merge_point`, `exactly`, `present`, `coalesce`, `remote_tags`, `ancestors(x, depth)`), working `tags()`/`remote_tags()` revsets, and new commands: `revert()`, `redo()`, `sign()`/`unsign()`, `file.search()`, `bookmark.advance()`, `tag.set()`. See [CHANGELOG.md](./CHANGELOG.md).
|
|
1015
|
+
- ✅ 0.1.0 (post-rename): Parity refresh tracking jj through **v0.44** — `tag.track()`/`tag.untrack()`, the `builtin_log()` revset alias, and `file.search({ nameOnly: true })`; `git_refs()`/`git_head()` documented as deprecated (jj removed both in v0.43). See [CHANGELOG.md](./CHANGELOG.md) for what was deliberately left for a maintainer call (`jj run`, fetch-time remote tag/bookmark import).
|
|
1016
|
+
- ✅ 0.2.0: Storage-layer audit fixes — same-process storage locking, `undo()` reverting in-place graph/tag mutations, ambiguous change-id detection, categorized `push()` error codes, a conflict-marker newline fix, atomic protobuf writes, and open-ended revset ranges (`..b`, `a..`, `::`). See [CHANGELOG.md](./CHANGELOG.md).
|
|
911
1017
|
|
|
912
|
-
|
|
913
|
-
- Repository analytics and debugging tools
|
|
914
|
-
- Interactive workflows
|
|
915
|
-
- Performance optimizations
|
|
916
|
-
|
|
917
|
-
See [ROADMAP.md](./ROADMAP.md) for detailed plans through v1.0.
|
|
1018
|
+
See [ROADMAP.md](./ROADMAP.md) for detailed plans, and [CHANGELOG.md](./CHANGELOG.md) for the release history.
|
|
918
1019
|
|
|
919
1020
|
---
|
|
920
1021
|
|
|
@@ -922,7 +1023,7 @@ See [ROADMAP.md](./ROADMAP.md) for detailed plans through v1.0.
|
|
|
922
1023
|
|
|
923
1024
|
### Requirements
|
|
924
1025
|
|
|
925
|
-
- **Node.js**:
|
|
1026
|
+
- **Node.js**: 20.0.0 or higher (uses the Web Crypto global, stabilized in Node 20; Node 18 is EOL)
|
|
926
1027
|
- **Browsers**: Chrome 90+, Firefox 88+, Safari 14+, Edge 90+
|
|
927
1028
|
- **Optional**: Git CLI (for JJ CLI interop testing)
|
|
928
1029
|
|
|
@@ -984,7 +1085,7 @@ A: Yes! Colocated repos expose normal Git commits. Git users never see JJ metada
|
|
|
984
1085
|
A: Comparable to isomorphic-git for Git operations. JJ metadata (JSON) is fast in Node, acceptable in browsers. Large histories need pagination.
|
|
985
1086
|
|
|
986
1087
|
**Q: Does this support all JJ features?**
|
|
987
|
-
A:
|
|
1088
|
+
A: Broad semantic parity (tracks Jujutsu through v0.44), not every CLI/UX detail — it's a library, not a terminal UI. See [ROADMAP.md](./ROADMAP.md) for what's planned and what's deliberately out of scope.
|
|
988
1089
|
|
|
989
1090
|
**Q: Can I migrate my Git repo?**
|
|
990
1091
|
A: Yes! `jj.git.init()` works on existing Git repositories.
|
|
@@ -996,6 +1097,16 @@ A: JJ's model genuinely improves common workflows—stable change IDs, fearless
|
|
|
996
1097
|
|
|
997
1098
|
## Related Projects
|
|
998
1099
|
|
|
1100
|
+
### JJHub
|
|
1101
|
+
|
|
1102
|
+
[JJHub](https://jjhub.erisera.com) is a Jujutsu-native overlay on GitHub, built
|
|
1103
|
+
on this library (it uses `createJJ` directly): stable change IDs and stacked
|
|
1104
|
+
PRs on top of your existing GitHub repos, platform-wide undo, and an MCP
|
|
1105
|
+
server so coding agents get the same fearless-undo, no-staging-area workflow.
|
|
1106
|
+
Install the CLI with `npm i -g jjhub`.
|
|
1107
|
+
|
|
1108
|
+
### Others
|
|
1109
|
+
|
|
999
1110
|
- [isomorphic-git](https://isomorphic-git.org/) - Pure JS Git implementation (our foundation)
|
|
1000
1111
|
- [Jujutsu](https://jj-vcs.github.io/jj/) - The original JJ version control system
|
|
1001
1112
|
- [simple-git](https://github.com/steveukx/git-js) - Git wrapper for Node.js
|
|
@@ -1015,5 +1126,3 @@ Built on the shoulders of:
|
|
|
1015
1126
|
- [isomorphic-git](https://github.com/isomorphic-git/isomorphic-git) by William Hilton
|
|
1016
1127
|
- [Jujutsu](https://github.com/martinvonz/jj) by Martin von Zweigbergk
|
|
1017
1128
|
- The Git and JavaScript communities
|
|
1018
|
-
|
|
1019
|
-
**Status**: v1.0.0 | **Tests**: 371 passing | **Ready for**: Production use
|