nano-git 0.1.0 → 0.2.1

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.
Files changed (45) hide show
  1. package/README.md +58 -1
  2. package/dist/backend/sqlite.d.mts +44 -0
  3. package/dist/backend/sqlite.mjs +59 -0
  4. package/dist/core/errors.d.mts +71 -1
  5. package/dist/core/errors.mjs +99 -1
  6. package/dist/errors.d.mts +2 -2
  7. package/dist/errors.mjs +2 -2
  8. package/dist/index.d.mts +2 -1
  9. package/dist/log/index.d.mts +3 -0
  10. package/dist/log/index.mjs +2 -0
  11. package/dist/log/types.d.mts +71 -0
  12. package/dist/log/walk.d.mts +37 -0
  13. package/dist/log/walk.mjs +274 -0
  14. package/dist/odb/sqlite.d.mts +23 -0
  15. package/dist/odb/sqlite.mjs +83 -0
  16. package/dist/refs/shallow/sqlite.d.mts +23 -0
  17. package/dist/refs/shallow/sqlite.mjs +61 -0
  18. package/dist/refs/sqlite.d.mts +23 -0
  19. package/dist/refs/sqlite.mjs +135 -0
  20. package/dist/remote/http.d.mts +51 -0
  21. package/dist/remote/http.mjs +74 -0
  22. package/dist/remote/types.d.mts +20 -0
  23. package/dist/repository/import/import-session-types.d.mts +3 -16
  24. package/dist/repository/ops/object-operations.mjs +0 -5
  25. package/dist/repository/ops/object-types.d.mts +0 -21
  26. package/dist/repository/sqlite.d.mts +28 -0
  27. package/dist/repository/sqlite.mjs +45 -0
  28. package/dist/transport/upload-pack.d.mts +1 -1
  29. package/dist/transport/upload-pack.mjs +1 -1
  30. package/dist/workdir/change-log.mjs +63 -0
  31. package/dist/workdir/core.d.mts +166 -0
  32. package/dist/workdir/core.mjs +2 -0
  33. package/dist/workdir/ids.mjs +20 -0
  34. package/dist/workdir/memory-backend.mjs +21 -0
  35. package/dist/workdir/memory.d.mts +2 -0
  36. package/dist/workdir/memory.mjs +2 -0
  37. package/dist/workdir/nodes.mjs +112 -0
  38. package/dist/workdir/origin.mjs +55 -0
  39. package/dist/workdir/overlay.mjs +95 -0
  40. package/dist/workdir/path.mjs +70 -0
  41. package/dist/workdir/session-internal.mjs +141 -0
  42. package/dist/workdir/session.d.mts +18 -0
  43. package/dist/workdir/session.mjs +380 -0
  44. package/dist/workdir/write-tree.mjs +97 -0
  45. package/package.json +21 -3
package/README.md CHANGED
@@ -8,13 +8,14 @@
8
8
  - ✅ **SHA-1 哈希计算** — 与 Git 完全兼容的对象哈希
9
9
  - ✅ **Git 对象模型** — 支持 blob、tree、commit、tag 四种对象类型
10
10
  - ✅ **对象序列化/反序列化** — 完整的二进制格式支持
11
- - ✅ **对象存储** — 文件系统存储和内存存储两种模式
11
+ - ✅ **对象存储** — 文件系统存储、内存存储和 SQLite 存储三种模式
12
12
  - ✅ **Packfile 支持** — 读取、写入、索引生成、delta 编解码
13
13
  - ✅ **引用管理** — refs 验证、解析、存储(文件系统 + 内存)
14
14
  - ✅ **仓库 API** — 类似 Git plumbing 命令的高层接口(init、hash-object、cat-file、commit-tree、update-ref 等)
15
15
  - ✅ **增量 Tree Patch** — 不经暂存区直接修改目录结构(`patchTree`、`readTree`、`walkTree`)
16
16
  - ✅ **可达性遍历与 GC** — 基于 refs 的可达对象收集、repack、gc
17
17
  - ✅ **Smart HTTP 传输** — 基于 Bun fetch 的 Git 协议客户端,支持 `fetch()`/`push()` 与完整的 Import Session 物化流程
18
+ - ✅ **远端查询 API** — 将 refs 快照、`object-info` 等纯远端能力独立出 `Repository`
18
19
  - ✅ **类型安全** — 完整的 TypeScript 类型定义
19
20
  - ✅ **Reference Transaction** — 批量 ref 更新的原子性保障,支持 Hooks 回调与自动回滚
20
21
 
@@ -55,6 +56,22 @@ await repo.fetch("https://github.com/user/repo.git");
55
56
  console.log(repo.listBranches());
56
57
  ```
57
58
 
59
+ ### 查询远端 refs / object-info
60
+
61
+ ```typescript
62
+ import { createHttpRemote } from "nano-git/remote/http";
63
+
64
+ const remote = createHttpRemote({
65
+ url: "https://github.com/user/repo.git",
66
+ });
67
+
68
+ const snapshot = await remote.readRefAdvertisement();
69
+ console.log(snapshot.defaultBranch);
70
+
71
+ const info = await remote.fetchObjectInfo(["95d09f2b10159347eece71399a7e2e907ea3df4f"]);
72
+ console.log(info.objects[0]?.size);
73
+ ```
74
+
58
75
  ### 内存仓库完整工作流
59
76
 
60
77
  ```typescript
@@ -138,6 +155,43 @@ repo.updateRef("refs/heads/main", commitHash);
138
155
 
139
156
  `openRepository()` 默认会同时读取 `.git/objects/` 下的 loose objects 和 `.git/objects/pack/` 下的 packed objects,因此可以直接打开经过 `git gc` 或 `git repack` 的真实仓库(包括裸仓库)。搭配 `initRepository()` 的第二个参数可初始化为裸仓库布局。
140
157
 
158
+ ### 使用 SQLite 仓库(Bun 运行时)
159
+
160
+ 适用于需要持久化但又不想管理松散文件的场景——
161
+ 所有对象和引用存在一个 `.sqlite` 文件中。
162
+
163
+ ```typescript
164
+ import { createSqliteRepository } from "nano-git/repository/sqlite";
165
+
166
+ // 创建或打开 SQLite 持久化仓库(支持 using 自动释放)
167
+ using repo = createSqliteRepository("/tmp/cache.sqlite");
168
+
169
+ // 与普通 repo 使用方式完全一致
170
+ const hash = repo.writeBlob(Buffer.from("persistent data"));
171
+ const treeHash = repo.createTree([{ mode: "100644", name: "data.txt", hash }]);
172
+ const commitHash = repo.createCommit(treeHash, [], "SQLite commit", {
173
+ name: "You",
174
+ email: "you@example.com",
175
+ timestamp: Math.floor(Date.now() / 1000),
176
+ timezone: "+0800",
177
+ });
178
+ console.log(`Committed: ${commitHash}`);
179
+
180
+ // 作用域结束时自动关闭数据库连接
181
+ ```
182
+
183
+ 也可拆分使用底层后端:
184
+
185
+ ```typescript
186
+ import { createSqliteRepositoryBackend } from "nano-git/backend/sqlite";
187
+ import { createRepository } from "nano-git/repository/core";
188
+
189
+ const backend = createSqliteRepositoryBackend("/tmp/repo.sqlite");
190
+ const repo = createRepository(backend);
191
+ // 用完记得释放
192
+ backend[Symbol.dispose]();
193
+ ```
194
+
141
195
  ### 生成 Packfile
142
196
 
143
197
  ```typescript
@@ -305,6 +359,8 @@ bun run examples/demo.ts
305
359
 
306
360
  本库默认入口 `"nano-git"` 直接提供高频的纯计算能力:类型、错误、对象编解码、refs 工具和 SHA-1 工具。
307
361
  带 `node:fs` / `node:zlib` 的运行时能力通过子路径显式导入,例如 `nano-git/repository/file`、`nano-git/pack`、`nano-git/transport/http`。
362
+ 纯远端查询能力通过 `nano-git/remote/http` 导入。
363
+ 基于 `bun:sqlite` 的存储后端通过 `nano-git/odb/sqlite`、`nano-git/refs/sqlite`、`nano-git/backend/sqlite`、`nano-git/repository/sqlite` 等子路径导入。
308
364
  tree-shaking 主要依赖模块本身的无副作用结构,而不是把所有 API 都拆成叶子级子路径。完整入口表见 `package.json` 的 `exports` 与 `src/index.ts` 的 JSDoc。
309
365
 
310
366
  ## Git 对象模型
@@ -381,6 +437,7 @@ bun test
381
437
  - [x] 可达性遍历与 GC(repack、gc)
382
438
  - [x] **Smart HTTP 传输** — pkt-line 编解码、ref 广告解析、side-band 解复用、Fetch / Push 协议、Import Session 集成
383
439
  - [x] **Reference Transaction** — 批量 ref 更新原子性、lock-then-rename 文件事务、生命周期 Hooks
440
+ - [x] **SQLite 存储后端** — 基于 `bun:sqlite` 的单文件持久化,支持对象/refs/shallow 存储、ACID 事务、`Symbol.dispose` 生命周期管理
384
441
 
385
442
  - [x] **Smart HTTP 服务端(upload-pack)** — 类 git-http-backend、框架无关的 HTTP handler,支持 ls-refs 和 fetch 命令,协议实现与编排器解耦
386
443
  - [x] **Smart HTTP 服务端(v1 receive-pack)** — 服务端 push 支持,基于 v1 协议,含 ref 广告、packfile 解包、ref 校验与 report-status
@@ -0,0 +1,44 @@
1
+ import { RepositoryBackend } from "./types.mjs";
2
+
3
+ //#region src/backend/sqlite.d.ts
4
+ /** 创建 SQLite 仓库后端的可选参数 */
5
+ interface CreateSqliteRepositoryBackendOptions {
6
+ /** 开启 WAL 模式,默认 true */
7
+ readonly walMode?: boolean;
8
+ }
9
+ /**
10
+ * SQLite 仓库后端(含资源释放能力)
11
+ *
12
+ * 在 RepositoryBackend 的基础上增加了 [Symbol.dispose](),
13
+ * 支持 `using backend = createSqliteRepositoryBackend(...)` 语法。
14
+ */
15
+ interface SqliteRepositoryBackend extends RepositoryBackend {
16
+ /** 释放 SQLite 数据库连接 */
17
+ [Symbol.dispose](): void;
18
+ }
19
+ /**
20
+ * 创建基于 SQLite 文件的完整仓库后端
21
+ *
22
+ * 内部创建 Database 实例并组合三个子 store。
23
+ * 返回的 backend 实现了 [Symbol.dispose](),可使用 `using` 语法
24
+ * 或在不再使用时手动调用 `backend[Symbol.dispose]()`。
25
+ *
26
+ * @param dbPath - SQLite 数据库文件路径
27
+ * @returns 实现了 SqliteRepositoryBackend 的仓库后端(可用 `using` 管理)
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * // 使用 using 自动释放(推荐)
32
+ * using backend = createSqliteRepositoryBackend("/tmp/repo.sqlite");
33
+ * const repo = createRepository(backend);
34
+ *
35
+ * // 或手动管理
36
+ * const backend = createSqliteRepositoryBackend("/tmp/repo.sqlite");
37
+ * const repo = createRepository(backend);
38
+ * // ... 使用完毕 ...
39
+ * backend[Symbol.dispose]();
40
+ * ```
41
+ */
42
+ declare function createSqliteRepositoryBackend(dbPath: string, options?: CreateSqliteRepositoryBackendOptions): SqliteRepositoryBackend;
43
+ //#endregion
44
+ export { CreateSqliteRepositoryBackendOptions, SqliteRepositoryBackend, createSqliteRepositoryBackend };
@@ -0,0 +1,59 @@
1
+ import { HEADS_PREFIX, HEAD_REF } from "../core/types/refs.mjs";
2
+ import { createSqliteObjectStore } from "../odb/sqlite.mjs";
3
+ import { createSqliteRefStore } from "../refs/sqlite.mjs";
4
+ import { createSqliteShallowStore } from "../refs/shallow/sqlite.mjs";
5
+ import { Database } from "bun:sqlite";
6
+ //#region src/backend/sqlite.ts
7
+ /**
8
+ * 基于 SQLite 的仓库后端
9
+ *
10
+ * 将 SQLite 中的 objects、refs、shallow 存储
11
+ * 组合为统一的 RepositoryBackend。
12
+ *
13
+ * 支持 [Symbol.dispose]() 释放数据库连接,
14
+ * 可使用 `using` 语法管理生命周期。
15
+ */
16
+ /**
17
+ * 创建基于 SQLite 文件的完整仓库后端
18
+ *
19
+ * 内部创建 Database 实例并组合三个子 store。
20
+ * 返回的 backend 实现了 [Symbol.dispose](),可使用 `using` 语法
21
+ * 或在不再使用时手动调用 `backend[Symbol.dispose]()`。
22
+ *
23
+ * @param dbPath - SQLite 数据库文件路径
24
+ * @returns 实现了 SqliteRepositoryBackend 的仓库后端(可用 `using` 管理)
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * // 使用 using 自动释放(推荐)
29
+ * using backend = createSqliteRepositoryBackend("/tmp/repo.sqlite");
30
+ * const repo = createRepository(backend);
31
+ *
32
+ * // 或手动管理
33
+ * const backend = createSqliteRepositoryBackend("/tmp/repo.sqlite");
34
+ * const repo = createRepository(backend);
35
+ * // ... 使用完毕 ...
36
+ * backend[Symbol.dispose]();
37
+ * ```
38
+ */
39
+ function createSqliteRepositoryBackend(dbPath, options = {}) {
40
+ const db = new Database(dbPath);
41
+ if (options.walMode !== false) db.run("PRAGMA journal_mode = WAL");
42
+ db.run("CREATE TABLE IF NOT EXISTS objects (hash TEXT PRIMARY KEY, type TEXT NOT NULL, content BLOB NOT NULL)");
43
+ db.run("CREATE TABLE IF NOT EXISTS refs (name TEXT PRIMARY KEY, target TEXT NOT NULL)");
44
+ db.run("CREATE TABLE IF NOT EXISTS shallow (hash TEXT PRIMARY KEY)");
45
+ db.run("INSERT OR IGNORE INTO refs (name, target) VALUES (?, ?)", [HEAD_REF, `ref: ${HEADS_PREFIX}main`]);
46
+ return {
47
+ gitDir: dbPath,
48
+ objects: createSqliteObjectStore(db),
49
+ refs: createSqliteRefStore(db),
50
+ shallow: createSqliteShallowStore(db),
51
+ packs: null,
52
+ /** 释放 SQLite 数据库连接 */
53
+ [Symbol.dispose]() {
54
+ db.close();
55
+ }
56
+ };
57
+ }
58
+ //#endregion
59
+ export { createSqliteRepositoryBackend };
@@ -120,5 +120,75 @@ declare class TransactionError extends GitError {
120
120
  declare class PreconditionCheckError extends GitError {
121
121
  constructor(message: string);
122
122
  }
123
+ /**
124
+ * 虚拟路径未找到错误
125
+ *
126
+ * 当操作的路径在 session 中不存在时抛出。
127
+ */
128
+ declare class VirtualPathNotFoundError extends GitError {
129
+ /** 不存在的路径 */
130
+ path: string;
131
+ constructor(path: string, message?: string);
132
+ }
133
+ /**
134
+ * 虚拟路径已存在错误
135
+ *
136
+ * 当创建的路径已在 session 中存在时抛出。
137
+ */
138
+ declare class VirtualPathAlreadyExistsError extends GitError {
139
+ /** 已存在的路径 */
140
+ path: string;
141
+ constructor(path: string, message?: string);
142
+ }
143
+ /**
144
+ * 非目录错误
145
+ *
146
+ * 当期望路径为目录但实际不是时抛出。
147
+ */
148
+ declare class VirtualNotDirectoryError extends GitError {
149
+ /** 路径 */
150
+ path: string;
151
+ constructor(path: string, message?: string);
152
+ }
153
+ /**
154
+ * 非文件错误
155
+ *
156
+ * 当期望路径为文件但实际不是时抛出。
157
+ */
158
+ declare class VirtualNotFileError extends GitError {
159
+ /** 路径 */
160
+ path: string;
161
+ constructor(path: string, message?: string);
162
+ }
163
+ /**
164
+ * 非符号链接错误
165
+ *
166
+ * 当期望路径为符号链接但实际不是时抛出。
167
+ */
168
+ declare class VirtualNotSymlinkError extends GitError {
169
+ /** 路径 */
170
+ path: string;
171
+ constructor(path: string, message?: string);
172
+ }
173
+ /**
174
+ * 虚拟工作目录 origin 不可用错误
175
+ *
176
+ * 当操作的路径在 repo 中的 origin 对象缺失时抛出(弱保证场景)。
177
+ */
178
+ declare class VirtualOriginUnavailableError extends GitError {
179
+ /** 路径 */
180
+ path: string;
181
+ constructor(path: string, message?: string);
182
+ }
183
+ /**
184
+ * 虚拟工作目录 revert 不支持错误
185
+ *
186
+ * 当对纯新建节点调用 revert 时抛出,因为其没有可恢复的 origin。
187
+ */
188
+ declare class VirtualRevertNotSupportedError extends GitError {
189
+ /** 路径 */
190
+ path: string;
191
+ constructor(path: string, message?: string);
192
+ }
123
193
  //#endregion
124
- export { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError };
194
+ export { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError, VirtualNotDirectoryError, VirtualNotFileError, VirtualNotSymlinkError, VirtualOriginUnavailableError, VirtualPathAlreadyExistsError, VirtualPathNotFoundError, VirtualRevertNotSupportedError };
@@ -164,5 +164,103 @@ var PreconditionCheckError = class extends GitError {
164
164
  this.name = "PreconditionCheckError";
165
165
  }
166
166
  };
167
+ /**
168
+ * 虚拟路径未找到错误
169
+ *
170
+ * 当操作的路径在 session 中不存在时抛出。
171
+ */
172
+ var VirtualPathNotFoundError = class extends GitError {
173
+ /** 不存在的路径 */
174
+ path;
175
+ constructor(path, message) {
176
+ super(message ?? `Virtual path not found: ${path}`);
177
+ this.name = "VirtualPathNotFoundError";
178
+ this.path = path;
179
+ }
180
+ };
181
+ /**
182
+ * 虚拟路径已存在错误
183
+ *
184
+ * 当创建的路径已在 session 中存在时抛出。
185
+ */
186
+ var VirtualPathAlreadyExistsError = class extends GitError {
187
+ /** 已存在的路径 */
188
+ path;
189
+ constructor(path, message) {
190
+ super(message ?? `Virtual path already exists: ${path}`);
191
+ this.name = "VirtualPathAlreadyExistsError";
192
+ this.path = path;
193
+ }
194
+ };
195
+ /**
196
+ * 非目录错误
197
+ *
198
+ * 当期望路径为目录但实际不是时抛出。
199
+ */
200
+ var VirtualNotDirectoryError = class extends GitError {
201
+ /** 路径 */
202
+ path;
203
+ constructor(path, message) {
204
+ super(message ?? `Virtual path is not a directory: ${path}`);
205
+ this.name = "VirtualNotDirectoryError";
206
+ this.path = path;
207
+ }
208
+ };
209
+ /**
210
+ * 非文件错误
211
+ *
212
+ * 当期望路径为文件但实际不是时抛出。
213
+ */
214
+ var VirtualNotFileError = class extends GitError {
215
+ /** 路径 */
216
+ path;
217
+ constructor(path, message) {
218
+ super(message ?? `Virtual path is not a file: ${path}`);
219
+ this.name = "VirtualNotFileError";
220
+ this.path = path;
221
+ }
222
+ };
223
+ /**
224
+ * 非符号链接错误
225
+ *
226
+ * 当期望路径为符号链接但实际不是时抛出。
227
+ */
228
+ var VirtualNotSymlinkError = class extends GitError {
229
+ /** 路径 */
230
+ path;
231
+ constructor(path, message) {
232
+ super(message ?? `Virtual path is not a symlink: ${path}`);
233
+ this.name = "VirtualNotSymlinkError";
234
+ this.path = path;
235
+ }
236
+ };
237
+ /**
238
+ * 虚拟工作目录 origin 不可用错误
239
+ *
240
+ * 当操作的路径在 repo 中的 origin 对象缺失时抛出(弱保证场景)。
241
+ */
242
+ var VirtualOriginUnavailableError = class extends GitError {
243
+ /** 路径 */
244
+ path;
245
+ constructor(path, message) {
246
+ super(message ?? `Virtual origin unavailable for: ${path}`);
247
+ this.name = "VirtualOriginUnavailableError";
248
+ this.path = path;
249
+ }
250
+ };
251
+ /**
252
+ * 虚拟工作目录 revert 不支持错误
253
+ *
254
+ * 当对纯新建节点调用 revert 时抛出,因为其没有可恢复的 origin。
255
+ */
256
+ var VirtualRevertNotSupportedError = class extends GitError {
257
+ /** 路径 */
258
+ path;
259
+ constructor(path, message) {
260
+ super(message ?? `Virtual revert not supported for purely new path: ${path}`);
261
+ this.name = "VirtualRevertNotSupportedError";
262
+ this.path = path;
263
+ }
264
+ };
167
265
  //#endregion
168
- export { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError };
266
+ export { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError, VirtualNotDirectoryError, VirtualNotFileError, VirtualNotSymlinkError, VirtualOriginUnavailableError, VirtualPathAlreadyExistsError, VirtualPathNotFoundError, VirtualRevertNotSupportedError };
package/dist/errors.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError } from "./core/errors.mjs";
2
- export { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError };
1
+ import { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError, VirtualNotDirectoryError, VirtualNotFileError, VirtualNotSymlinkError, VirtualOriginUnavailableError, VirtualPathAlreadyExistsError, VirtualPathNotFoundError, VirtualRevertNotSupportedError } from "./core/errors.mjs";
2
+ export { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError, VirtualNotDirectoryError, VirtualNotFileError, VirtualNotSymlinkError, VirtualOriginUnavailableError, VirtualPathAlreadyExistsError, VirtualPathNotFoundError, VirtualRevertNotSupportedError };
package/dist/errors.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError } from "./core/errors.mjs";
2
- export { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError };
1
+ import { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError, VirtualNotDirectoryError, VirtualNotFileError, VirtualNotSymlinkError, VirtualOriginUnavailableError, VirtualPathAlreadyExistsError, VirtualPathNotFoundError, VirtualRevertNotSupportedError } from "./core/errors.mjs";
2
+ export { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError, VirtualNotDirectoryError, VirtualNotFileError, VirtualNotSymlinkError, VirtualOriginUnavailableError, VirtualPathAlreadyExistsError, VirtualPathNotFoundError, VirtualRevertNotSupportedError };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { GitAuthor, GitBlob, GitCommit, GitCommitExtraHeader, GitObject, GitTag, GitTree, ObjectType, RawGitObject, SHA1, TreeEntry, assertObjectType, sha1 } from "./core/types.mjs";
2
2
  import { PackRepackOptions, RepositoryBackend, RepositoryGCOptions, RepositoryPackSupport, RepositoryRepackOptions } from "./backend/types.mjs";
3
3
  import { CircularReferenceError, DeltaError, GitError, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, PackError, PackIndexError, PreconditionCheckError, RefNotFoundError, RepositoryError, TransactionError } from "./core/errors.mjs";
4
+ import { RemoteSource } from "./remote/types.mjs";
4
5
  import { FileRepository, Repository } from "./repository/types.mjs";
5
6
  import { hashData, hashObject } from "./core/hash-digest.mjs";
6
7
  import { isValidSHA1 } from "./core/hash-path.mjs";
@@ -13,4 +14,4 @@ import { deserialize, deserializeContent, serialize, serializeContent } from "./
13
14
  import { decodeObject, encodeObject, readObject, tryReadObject, writeObject } from "./objects/raw.mjs";
14
15
  import { branchNameToRef, normalizeShortRefName, tagNameToRef, validateRefName, validateRefPrefix } from "./refs/names.mjs";
15
16
  import { resolveRefHash, resolveSymbolicRef, resolveTargetHash } from "./refs/resolve.mjs";
16
- export { CircularReferenceError, DeltaError, type FileRepository, type GitAuthor, type GitBlob, type GitCommit, type GitCommitExtraHeader, GitError, type GitObject, type GitTag, type GitTree, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, type ObjectType, PackError, PackIndexError, type PackRepackOptions, PreconditionCheckError, type RawGitObject, RefNotFoundError, type Repository, type RepositoryBackend, RepositoryError, type RepositoryGCOptions, type RepositoryPackSupport, type RepositoryRepackOptions, type SHA1, TransactionError, type TreeEntry, assertObjectType, branchNameToRef, decodeObject, deserialize, deserializeBlob, deserializeCommit, deserializeContent, deserializeTag, deserializeTree, encodeObject, formatAuthor, hashData, hashObject, isValidSHA1, normalizeShortRefName, parseAuthor, readObject, resolveRefHash, resolveSymbolicRef, resolveTargetHash, serialize, serializeBlob, serializeCommit, serializeContent, serializeTag, serializeTree, sha1, tagNameToRef, tryReadObject, validateRefName, validateRefPrefix, writeObject };
17
+ export { CircularReferenceError, DeltaError, type FileRepository, type GitAuthor, type GitBlob, type GitCommit, type GitCommitExtraHeader, GitError, type GitObject, type GitTag, type GitTree, InvalidObjectError, InvalidPackError, InvalidSHA1Error, ObjectNotFoundError, type ObjectType, PackError, PackIndexError, type PackRepackOptions, PreconditionCheckError, type RawGitObject, RefNotFoundError, type RemoteSource, type Repository, type RepositoryBackend, RepositoryError, type RepositoryGCOptions, type RepositoryPackSupport, type RepositoryRepackOptions, type SHA1, TransactionError, type TreeEntry, assertObjectType, branchNameToRef, decodeObject, deserialize, deserializeBlob, deserializeCommit, deserializeContent, deserializeTag, deserializeTree, encodeObject, formatAuthor, hashData, hashObject, isValidSHA1, normalizeShortRefName, parseAuthor, readObject, resolveRefHash, resolveSymbolicRef, resolveTargetHash, serialize, serializeBlob, serializeCommit, serializeContent, serializeTag, serializeTree, sha1, tagNameToRef, tryReadObject, validateRefName, validateRefPrefix, writeObject };
@@ -0,0 +1,3 @@
1
+ import { CommitWalkOrder, LogEntry, LogWalkOptions } from "./types.mjs";
2
+ import { walkLogEntries } from "./walk.mjs";
3
+ export { type CommitWalkOrder, type LogEntry, type LogWalkOptions, walkLogEntries };
@@ -0,0 +1,2 @@
1
+ import { walkLogEntries } from "./walk.mjs";
2
+ export { walkLogEntries };
@@ -0,0 +1,71 @@
1
+ import { GitCommit, SHA1 } from "../core/types.mjs";
2
+
3
+ //#region src/log/types.d.ts
4
+ /** 单条提交日志条目 */
5
+ interface LogEntry {
6
+ /** 提交哈希 */
7
+ readonly hash: SHA1;
8
+ /** 解码后的提交对象 */
9
+ readonly commit: GitCommit;
10
+ }
11
+ /** 提交遍历排序策略 */
12
+ type CommitWalkOrder = "date" | "topo";
13
+ /** 日志遍历选项 */
14
+ interface LogWalkOptions {
15
+ /**
16
+ * 遍历起点哈希列表。
17
+ *
18
+ * 为空时立即返回空结果。
19
+ * 调用方应自行将 ref 名称(如 HEAD、branch names)解析为 SHA1。
20
+ */
21
+ readonly from?: SHA1[];
22
+ /**
23
+ * 排除哈希列表(及其所有祖先)。
24
+ *
25
+ * 等价于 `git log <from> ^<exclude>` 或 `<exclude>..<from>` 范围语法。
26
+ * 被排除的提交及其全部祖先不会出现在结果中。
27
+ */
28
+ readonly exclude?: SHA1[];
29
+ /**
30
+ * 最多输出的提交数量。
31
+ *
32
+ * 等价于 `git log --max-count=<n>`。
33
+ */
34
+ readonly maxCount?: number;
35
+ /**
36
+ * 跳过开头 N 个提交再输出。
37
+ *
38
+ * 等价于 `git log --skip=<n>`。
39
+ */
40
+ readonly skip?: number;
41
+ /**
42
+ * 提交排序策略。
43
+ *
44
+ * - `"date"`(默认):按提交时间降序。时间相同时不保证严格拓扑序,
45
+ * 但在实践中 parent 的 timestamp 通常 ≤ child,结果与 git log 默认一致。
46
+ * - `"topo"`:严格拓扑排序,所有子提交在父提交之前输出。
47
+ * 同层级的提交按时间戳降序。需要预先收集全部提交,额外开销较大。
48
+ */
49
+ readonly order?: CommitWalkOrder;
50
+ /**
51
+ * 仅输出此 Unix 时间戳(含)之后的提交。
52
+ *
53
+ * 等价于 `git log --since=<timestamp>`。
54
+ */
55
+ readonly since?: number;
56
+ /**
57
+ * 仅输出此 Unix 时间戳(含)之前的提交。
58
+ *
59
+ * 等价于 `git log --until=<timestamp>`。
60
+ */
61
+ readonly until?: number;
62
+ /**
63
+ * 仅沿第一条父链行走。
64
+ *
65
+ * 启用后只追踪每个提交的第一个 parent,忽略 merge 的其他分支。
66
+ * 等价于 `git log --first-parent`。
67
+ */
68
+ readonly firstParent?: boolean;
69
+ }
70
+ //#endregion
71
+ export { CommitWalkOrder, LogEntry, LogWalkOptions };
@@ -0,0 +1,37 @@
1
+ import { ObjectSource } from "../core/types/odb.mjs";
2
+ import { LogEntry, LogWalkOptions } from "./types.mjs";
3
+
4
+ //#region src/log/walk.d.ts
5
+ /**
6
+ * 遍历提交历史日志
7
+ *
8
+ * 从指定的起点哈希出发,沿 parent 链回溯,按指定排序策略输出提交。
9
+ * 不涉及 ref 解析——调用方需自行将 ref 名称解析为 SHA1。
10
+ *
11
+ * @param source - 对象源(通常是 `Repository.objects`)
12
+ * @param options - 遍历选项
13
+ * @returns 按序输出的提交日志条目生成器
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const headHash = resolveRefHash(repo.refs, "HEAD")!;
18
+ * for (const entry of walkLogEntries(repo.objects, { from: [headHash], maxCount: 5 })) {
19
+ * console.log(entry.hash, entry.commit.subject);
20
+ * }
21
+ * ```
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * // 等价于 git log --oneline --since=1600000000 --until=1700000000
26
+ * for (const entry of walkLogEntries(repo.objects, {
27
+ * from: [headHash],
28
+ * since: 1600000000,
29
+ * until: 1700000000,
30
+ * })) {
31
+ * console.log(entry.hash.slice(0, 7), entry.commit.message.split("\n")[0]);
32
+ * }
33
+ * ```
34
+ */
35
+ declare function walkLogEntries(source: ObjectSource, options?: LogWalkOptions): Generator<LogEntry, void, undefined>;
36
+ //#endregion
37
+ export { walkLogEntries };