nano-git 0.1.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/README.md +407 -0
- package/dist/backend/file-backend.d.mts +26 -0
- package/dist/backend/file-backend.mjs +83 -0
- package/dist/backend/file.d.mts +2 -0
- package/dist/backend/file.mjs +2 -0
- package/dist/backend/index.d.mts +2 -0
- package/dist/backend/index.mjs +1 -0
- package/dist/backend/memory-backend.d.mts +25 -0
- package/dist/backend/memory-backend.mjs +33 -0
- package/dist/backend/memory.d.mts +2 -0
- package/dist/backend/memory.mjs +2 -0
- package/dist/backend/types.d.mts +90 -0
- package/dist/core/errors.d.mts +124 -0
- package/dist/core/errors.mjs +168 -0
- package/dist/core/hash-digest.d.mts +35 -0
- package/dist/core/hash-digest.mjs +50 -0
- package/dist/core/hash-file.d.mts +20 -0
- package/dist/core/hash-file.mjs +27 -0
- package/dist/core/hash-path.d.mts +17 -0
- package/dist/core/hash-path.mjs +35 -0
- package/dist/core/types/odb.d.mts +63 -0
- package/dist/core/types/refs.d.mts +140 -0
- package/dist/core/types/refs.mjs +19 -0
- package/dist/core/types/shallow.d.mts +52 -0
- package/dist/core/types.d.mts +154 -0
- package/dist/core/types.mjs +43 -0
- package/dist/errors.d.mts +2 -0
- package/dist/errors.mjs +2 -0
- package/dist/hash-file.d.mts +2 -0
- package/dist/hash-file.mjs +2 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.mjs +14 -0
- package/dist/objects/author.d.mts +25 -0
- package/dist/objects/author.mjs +45 -0
- package/dist/objects/blob.d.mts +15 -0
- package/dist/objects/blob.mjs +20 -0
- package/dist/objects/codec.d.mts +46 -0
- package/dist/objects/codec.mjs +84 -0
- package/dist/objects/commit.d.mts +26 -0
- package/dist/objects/commit.mjs +160 -0
- package/dist/objects/index.d.mts +8 -0
- package/dist/objects/index.mjs +8 -0
- package/dist/objects/raw.d.mts +85 -0
- package/dist/objects/raw.mjs +111 -0
- package/dist/objects/tag.d.mts +26 -0
- package/dist/objects/tag.mjs +148 -0
- package/dist/objects/tree.d.mts +22 -0
- package/dist/objects/tree.mjs +66 -0
- package/dist/odb/file-utils.mjs +136 -0
- package/dist/odb/file.d.mts +22 -0
- package/dist/odb/file.mjs +66 -0
- package/dist/odb/memory.d.mts +22 -0
- package/dist/odb/memory.mjs +54 -0
- package/dist/pack/composite-store.d.mts +76 -0
- package/dist/pack/composite-store.mjs +133 -0
- package/dist/pack/constants.mjs +48 -0
- package/dist/pack/crc32.mjs +38 -0
- package/dist/pack/delta-apply.d.mts +21 -0
- package/dist/pack/delta-apply.mjs +71 -0
- package/dist/pack/delta-create.d.mts +28 -0
- package/dist/pack/delta-create.mjs +151 -0
- package/dist/pack/index.d.mts +16 -0
- package/dist/pack/index.mjs +13 -0
- package/dist/pack/object-header.d.mts +36 -0
- package/dist/pack/object-header.mjs +72 -0
- package/dist/pack/ofs-delta-offset.d.mts +35 -0
- package/dist/pack/ofs-delta-offset.mjs +59 -0
- package/dist/pack/pack-builder-types.d.mts +19 -0
- package/dist/pack/pack-builder.d.mts +52 -0
- package/dist/pack/pack-builder.mjs +80 -0
- package/dist/pack/pack-encoding.mjs +76 -0
- package/dist/pack/pack-index-reader.d.mts +57 -0
- package/dist/pack/pack-index-reader.mjs +90 -0
- package/dist/pack/pack-index-types.d.mts +16 -0
- package/dist/pack/pack-index-writer.d.mts +45 -0
- package/dist/pack/pack-index-writer.mjs +106 -0
- package/dist/pack/pack-reader-resolver.mjs +104 -0
- package/dist/pack/pack-reader-types.d.mts +31 -0
- package/dist/pack/pack-reader-types.mjs +22 -0
- package/dist/pack/pack-reader-utils.mjs +61 -0
- package/dist/pack/pack-reader.d.mts +81 -0
- package/dist/pack/pack-reader.mjs +171 -0
- package/dist/pack/pack-store-loader.mjs +79 -0
- package/dist/pack/pack-store-types.d.mts +16 -0
- package/dist/pack/pack-store.d.mts +55 -0
- package/dist/pack/pack-store.mjs +114 -0
- package/dist/pack/pack-writer.mjs +96 -0
- package/dist/pack/varint.d.mts +34 -0
- package/dist/pack/varint.mjs +57 -0
- package/dist/refs/file.d.mts +6 -0
- package/dist/refs/file.mjs +222 -0
- package/dist/refs/fs-utils.mjs +30 -0
- package/dist/refs/memory.d.mts +14 -0
- package/dist/refs/memory.mjs +104 -0
- package/dist/refs/names.d.mts +57 -0
- package/dist/refs/names.mjs +80 -0
- package/dist/refs/resolve.d.mts +33 -0
- package/dist/refs/resolve.mjs +55 -0
- package/dist/refs/shallow/file.d.mts +17 -0
- package/dist/refs/shallow/file.mjs +61 -0
- package/dist/refs/shallow/memory.d.mts +18 -0
- package/dist/refs/shallow/memory.mjs +33 -0
- package/dist/repository/core.d.mts +3 -0
- package/dist/repository/core.mjs +2 -0
- package/dist/repository/create.d.mts +22 -0
- package/dist/repository/create.mjs +43 -0
- package/dist/repository/file.d.mts +43 -0
- package/dist/repository/file.mjs +82 -0
- package/dist/repository/import/import-glob.mjs +44 -0
- package/dist/repository/import/import-plan-builder.mjs +625 -0
- package/dist/repository/import/import-session-types.d.mts +280 -0
- package/dist/repository/import/import-session.mjs +96 -0
- package/dist/repository/import/import-view.mjs +133 -0
- package/dist/repository/memory.d.mts +17 -0
- package/dist/repository/memory.mjs +33 -0
- package/dist/repository/ops/fetch-operations.mjs +20 -0
- package/dist/repository/ops/fetch-types.d.mts +82 -0
- package/dist/repository/ops/fetch-url.mjs +82 -0
- package/dist/repository/ops/fs-object-operations.mjs +31 -0
- package/dist/repository/ops/maintenance-operations.mjs +62 -0
- package/dist/repository/ops/maintenance-types.d.mts +42 -0
- package/dist/repository/ops/object-operations.mjs +65 -0
- package/dist/repository/ops/object-types.d.mts +109 -0
- package/dist/repository/ops/push-operations.mjs +16 -0
- package/dist/repository/ops/push-resolution.mjs +17 -0
- package/dist/repository/ops/push-types.d.mts +72 -0
- package/dist/repository/ops/push-url.mjs +45 -0
- package/dist/repository/ops/reachability.mjs +60 -0
- package/dist/repository/ops/ref-operations.mjs +86 -0
- package/dist/repository/ops/ref-types.d.mts +70 -0
- package/dist/repository/tree/tree-patch.d.mts +64 -0
- package/dist/repository/tree/tree-patch.mjs +268 -0
- package/dist/repository/tree/tree-walk.d.mts +46 -0
- package/dist/repository/tree/tree-walk.mjs +65 -0
- package/dist/repository/tree/tree-writer.mjs +68 -0
- package/dist/repository/types.d.mts +36 -0
- package/dist/sha1.d.mts +4 -0
- package/dist/sha1.mjs +4 -0
- package/dist/transport/client/receive-pack/http.d.mts +33 -0
- package/dist/transport/client/receive-pack/http.mjs +99 -0
- package/dist/transport/client/receive-pack/push-error.d.mts +23 -0
- package/dist/transport/client/receive-pack/push-error.mjs +32 -0
- package/dist/transport/client/receive-pack/push-pack-plan.d.mts +28 -0
- package/dist/transport/client/receive-pack/push-pack-plan.mjs +60 -0
- package/dist/transport/client/receive-pack/push-policy.d.mts +19 -0
- package/dist/transport/client/receive-pack/push-policy.mjs +64 -0
- package/dist/transport/client/receive-pack/push-ref-plan.d.mts +45 -0
- package/dist/transport/client/receive-pack/push-ref-plan.mjs +108 -0
- package/dist/transport/client/receive-pack/push-report.d.mts +28 -0
- package/dist/transport/client/receive-pack/push-report.mjs +84 -0
- package/dist/transport/client/receive-pack/push-request-plan.mjs +52 -0
- package/dist/transport/client/receive-pack/push.d.mts +32 -0
- package/dist/transport/client/receive-pack/push.mjs +97 -0
- package/dist/transport/client/receive-pack/request.d.mts +39 -0
- package/dist/transport/client/receive-pack/request.mjs +46 -0
- package/dist/transport/client/receive-pack/response.d.mts +26 -0
- package/dist/transport/client/receive-pack/response.mjs +52 -0
- package/dist/transport/client/receive-pack/result.d.mts +34 -0
- package/dist/transport/client/receive-pack/result.mjs +100 -0
- package/dist/transport/client/upload-pack/capability-advertisement.d.mts +56 -0
- package/dist/transport/client/upload-pack/capability-advertisement.mjs +130 -0
- package/dist/transport/client/upload-pack/fetch.d.mts +109 -0
- package/dist/transport/client/upload-pack/fetch.mjs +392 -0
- package/dist/transport/client/upload-pack/http.d.mts +29 -0
- package/dist/transport/client/upload-pack/http.mjs +79 -0
- package/dist/transport/client/upload-pack/ls-refs.d.mts +75 -0
- package/dist/transport/client/upload-pack/ls-refs.mjs +150 -0
- package/dist/transport/client/upload-pack/object-info.d.mts +65 -0
- package/dist/transport/client/upload-pack/object-info.mjs +111 -0
- package/dist/transport/client/upload-pack/types.d.mts +153 -0
- package/dist/transport/http/index.d.mts +3 -0
- package/dist/transport/http/index.mjs +2 -0
- package/dist/transport/http/smart-http.d.mts +46 -0
- package/dist/transport/http/smart-http.mjs +176 -0
- package/dist/transport/http/types.d.mts +27 -0
- package/dist/transport/index.d.mts +9 -0
- package/dist/transport/index.mjs +8 -0
- package/dist/transport/protocol/object-graph.d.mts +63 -0
- package/dist/transport/protocol/object-graph.mjs +149 -0
- package/dist/transport/protocol/pkt-line.d.mts +109 -0
- package/dist/transport/protocol/pkt-line.mjs +195 -0
- package/dist/transport/protocol/ref-advertisement.mjs +185 -0
- package/dist/transport/protocol/ref-collection.d.mts +38 -0
- package/dist/transport/protocol/ref-collection.mjs +63 -0
- package/dist/transport/protocol/ref-match.d.mts +39 -0
- package/dist/transport/protocol/ref-match.mjs +42 -0
- package/dist/transport/protocol/refspec.d.mts +44 -0
- package/dist/transport/protocol/refspec.mjs +79 -0
- package/dist/transport/protocol/side-band.d.mts +65 -0
- package/dist/transport/protocol/side-band.mjs +142 -0
- package/dist/transport/protocol/transport-capabilities.mjs +46 -0
- package/dist/transport/protocol/types.d.mts +148 -0
- package/dist/transport/protocol/update-refs.d.mts +68 -0
- package/dist/transport/protocol/update-refs.mjs +126 -0
- package/dist/transport/receive-pack.d.mts +11 -0
- package/dist/transport/receive-pack.mjs +11 -0
- package/dist/transport/server/receive-pack/advertise.d.mts +28 -0
- package/dist/transport/server/receive-pack/advertise.mjs +88 -0
- package/dist/transport/server/receive-pack/handler.d.mts +30 -0
- package/dist/transport/server/receive-pack/handler.mjs +156 -0
- package/dist/transport/server/receive-pack/index.d.mts +6 -0
- package/dist/transport/server/receive-pack/index.mjs +6 -0
- package/dist/transport/server/receive-pack/parse.d.mts +17 -0
- package/dist/transport/server/receive-pack/parse.mjs +80 -0
- package/dist/transport/server/receive-pack/report-status.mjs +64 -0
- package/dist/transport/server/receive-pack/service.d.mts +41 -0
- package/dist/transport/server/receive-pack/service.mjs +39 -0
- package/dist/transport/server/receive-pack/types.d.mts +56 -0
- package/dist/transport/server/receive-pack/types.mjs +25 -0
- package/dist/transport/server/receive-pack/unpack.mjs +119 -0
- package/dist/transport/server/upload-pack/advertise.d.mts +20 -0
- package/dist/transport/server/upload-pack/advertise.mjs +30 -0
- package/dist/transport/server/upload-pack/command.d.mts +43 -0
- package/dist/transport/server/upload-pack/command.mjs +56 -0
- package/dist/transport/server/upload-pack/fetch.d.mts +43 -0
- package/dist/transport/server/upload-pack/fetch.mjs +217 -0
- package/dist/transport/server/upload-pack/index.d.mts +7 -0
- package/dist/transport/server/upload-pack/index.mjs +7 -0
- package/dist/transport/server/upload-pack/ls-refs.d.mts +38 -0
- package/dist/transport/server/upload-pack/ls-refs.mjs +113 -0
- package/dist/transport/server/upload-pack/service.d.mts +40 -0
- package/dist/transport/server/upload-pack/service.mjs +51 -0
- package/dist/transport/server/upload-pack/types.d.mts +11 -0
- package/dist/transport/server/upload-pack/types.mjs +21 -0
- package/dist/transport/upload-pack.d.mts +7 -0
- package/dist/transport/upload-pack.mjs +6 -0
- package/package.json +98 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { createRepoImportOperations } from "../import/import-session.mjs";
|
|
2
|
+
import { parseRefSpec } from "../../transport/protocol/refspec.mjs";
|
|
3
|
+
//#region src/repository/ops/fetch-url.ts
|
|
4
|
+
/**
|
|
5
|
+
* 仓库 fetch 内部编排
|
|
6
|
+
*
|
|
7
|
+
* 将 repo.fetch(url) 委托给 ImportSession 完成实际工作。
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* 按 URL fetch
|
|
11
|
+
*/
|
|
12
|
+
async function runFetchToUrl(backend, url, options) {
|
|
13
|
+
const ops = createRepoImportOperations(backend);
|
|
14
|
+
const source = {
|
|
15
|
+
url,
|
|
16
|
+
token: options?.token,
|
|
17
|
+
headers: options?.headers
|
|
18
|
+
};
|
|
19
|
+
const session = await ops.openImportSession(source);
|
|
20
|
+
if (options?.refSpecs) return applyCustomRefSpecs(session, options);
|
|
21
|
+
return applyDefaultMapping(session, options);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 默认 fetch 映射:远端所有 refs → 本地同名 refs + HEAD 更新
|
|
25
|
+
*/
|
|
26
|
+
async function applyDefaultMapping(session, options) {
|
|
27
|
+
const plan = session.plan();
|
|
28
|
+
const branches = session.select("refs/heads/*");
|
|
29
|
+
if (branches.refs.length > 0) plan.materialize(branches).toNamespace("refs/heads/*", {
|
|
30
|
+
policy: { mode: "fast-forward" },
|
|
31
|
+
prune: options?.prune
|
|
32
|
+
});
|
|
33
|
+
if (!options?.noTags) {
|
|
34
|
+
const tags = session.select("refs/tags/*");
|
|
35
|
+
if (tags.refs.length > 0) plan.materialize(tags).toNamespace("refs/tags/*", { policy: { mode: "fast-forward" } });
|
|
36
|
+
}
|
|
37
|
+
const defaultBranch = session.defaultBranch();
|
|
38
|
+
if (defaultBranch.refs.length > 0) plan.materialize(defaultBranch).setHead();
|
|
39
|
+
return convertToFetchResult(await plan.apply());
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 自定义 refSpec 映射
|
|
43
|
+
*/
|
|
44
|
+
async function applyCustomRefSpecs(session, options) {
|
|
45
|
+
const plan = session.plan();
|
|
46
|
+
for (const specStr of options.refSpecs ?? []) {
|
|
47
|
+
const spec = parseRefSpec(specStr);
|
|
48
|
+
const srcPattern = spec.isWildcard ? `${spec.srcPattern}*` : spec.srcPattern;
|
|
49
|
+
const dstPattern = spec.isWildcard ? `${spec.dstPattern}*` : spec.dstPattern;
|
|
50
|
+
const isForce = specStr.startsWith("+") || spec.force || options.force;
|
|
51
|
+
const view = session.select(srcPattern);
|
|
52
|
+
if (view.refs.length > 0) {
|
|
53
|
+
const policy = isForce ? { mode: "replace" } : { mode: "fast-forward" };
|
|
54
|
+
plan.materialize(view).toNamespace(dstPattern, { policy });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return convertToFetchResult(await plan.apply());
|
|
58
|
+
}
|
|
59
|
+
function convertToFetchResult(result) {
|
|
60
|
+
const updatedRefs = [];
|
|
61
|
+
for (const [refName, newHash] of result.updatedRefs) updatedRefs.push({
|
|
62
|
+
refName,
|
|
63
|
+
oldHash: null,
|
|
64
|
+
newHash,
|
|
65
|
+
success: true,
|
|
66
|
+
forced: false
|
|
67
|
+
});
|
|
68
|
+
for (const refName of result.deletedRefs) updatedRefs.push({
|
|
69
|
+
refName,
|
|
70
|
+
oldHash: null,
|
|
71
|
+
newHash: null,
|
|
72
|
+
success: true,
|
|
73
|
+
forced: false
|
|
74
|
+
});
|
|
75
|
+
return {
|
|
76
|
+
updatedRefs,
|
|
77
|
+
objectCount: result.importedObjects,
|
|
78
|
+
progress: []
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
export { runFetchToUrl };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { writeTreeRecursive } from "../tree/tree-writer.mjs";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
//#region src/repository/ops/fs-object-operations.ts
|
|
4
|
+
/**
|
|
5
|
+
* 仓库文件系统对象操作组装
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* 创建文件系统对象操作集合
|
|
9
|
+
*
|
|
10
|
+
* @param objects - 对象数据库
|
|
11
|
+
* @param writeBlob - 基础 blob 写入能力
|
|
12
|
+
* @returns 文件系统对象操作集合
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* const fsOps = createRepositoryFsObjectOperations(objects, writeBlob);
|
|
17
|
+
* const hash = fsOps.writeBlobFile("/tmp/file.txt");
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
function createRepositoryFsObjectOperations(objects, writeBlob) {
|
|
21
|
+
return {
|
|
22
|
+
writeBlobFile(filePath) {
|
|
23
|
+
return writeBlob(readFileSync(filePath));
|
|
24
|
+
},
|
|
25
|
+
writeTree(dirPath) {
|
|
26
|
+
return writeTreeRecursive(objects, dirPath);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { createRepositoryFsObjectOperations };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { listReachableObjects } from "./reachability.mjs";
|
|
2
|
+
//#region src/repository/ops/maintenance-operations.ts
|
|
3
|
+
/**
|
|
4
|
+
* 仓库打包与维护操作组装
|
|
5
|
+
*
|
|
6
|
+
* GC 编排策略:
|
|
7
|
+
* 1. 如果有 pack 支持,先 repack 可达对象(替换旧 pack)
|
|
8
|
+
* 2. 如果后端 ObjectDatabase 支持 delete,清理不可达的 loose 对象
|
|
9
|
+
* 3. 刷新 pack 视图
|
|
10
|
+
*
|
|
11
|
+
* 不再依赖 RepositoryPackSupport.gc()——GC 是仓库层的编排职责,
|
|
12
|
+
* RepositoryPackSupport 只负责 packfile 层面的读写。
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* 创建仓库维护相关操作
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const ops = createMaintenanceRepositoryOperations(objects, refs, packs);
|
|
20
|
+
* const reachable = ops.listReachableObjects();
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
function createMaintenanceRepositoryOperations(objects, refs, packs) {
|
|
24
|
+
return {
|
|
25
|
+
writePack(hashes) {
|
|
26
|
+
if (!packs) throw new Error("Backend does not support packfile writes");
|
|
27
|
+
return packs.writeFromSource(objects, hashes ?? objects.list());
|
|
28
|
+
},
|
|
29
|
+
repack(options) {
|
|
30
|
+
if (!packs) throw new Error("Backend does not support repack");
|
|
31
|
+
const hashes = options?.hashes ? Array.from(options.hashes) : Array.from(objects.list());
|
|
32
|
+
const result = packs.repack(objects, {
|
|
33
|
+
hashes,
|
|
34
|
+
replaceExistingPacks: options?.replaceExistingPacks
|
|
35
|
+
});
|
|
36
|
+
if (options?.pruneLoose) for (const hash of hashes) objects.delete?.(hash);
|
|
37
|
+
packs.source.refresh();
|
|
38
|
+
return result;
|
|
39
|
+
},
|
|
40
|
+
listReachableObjects() {
|
|
41
|
+
return listReachableObjects(objects, refs);
|
|
42
|
+
},
|
|
43
|
+
gc(options) {
|
|
44
|
+
const reachable = listReachableObjects(objects, refs);
|
|
45
|
+
const reachableSet = new Set(reachable);
|
|
46
|
+
let result;
|
|
47
|
+
if (packs) {
|
|
48
|
+
result = packs.repack(objects, {
|
|
49
|
+
hashes: reachable,
|
|
50
|
+
replaceExistingPacks: options?.replaceExistingPacks
|
|
51
|
+
});
|
|
52
|
+
packs.source.refresh();
|
|
53
|
+
}
|
|
54
|
+
if (options?.pruneLoose ?? true) {
|
|
55
|
+
for (const hash of objects.list()) if (!reachableSet.has(hash)) objects.delete?.(hash);
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
export { createMaintenanceRepositoryOperations };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SHA1 } from "../../core/types.mjs";
|
|
2
|
+
import { PackBuildResult } from "../../pack/pack-builder-types.mjs";
|
|
3
|
+
import { RepositoryGCOptions, RepositoryRepackOptions } from "../../backend/types.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/repository/ops/maintenance-types.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* 仓库维护相关操作
|
|
8
|
+
*/
|
|
9
|
+
interface RepositoryMaintenanceOperations {
|
|
10
|
+
/**
|
|
11
|
+
* 将指定对象写入新的 packfile
|
|
12
|
+
*
|
|
13
|
+
* 未提供哈希列表时,默认打包仓库当前可见的全部对象。
|
|
14
|
+
*/
|
|
15
|
+
writePack(hashes?: SHA1[]): PackBuildResult;
|
|
16
|
+
/**
|
|
17
|
+
* 重写仓库 pack 布局
|
|
18
|
+
*
|
|
19
|
+
* 默认行为:
|
|
20
|
+
* - 打包当前可见的全部对象
|
|
21
|
+
* - 删除旧 pack 文件
|
|
22
|
+
* - 保留 loose objects
|
|
23
|
+
*/
|
|
24
|
+
repack(options?: RepositoryRepackOptions): PackBuildResult;
|
|
25
|
+
/**
|
|
26
|
+
* 列出从 HEAD、所有分支和所有标签可达的对象
|
|
27
|
+
*/
|
|
28
|
+
listReachableObjects(): SHA1[];
|
|
29
|
+
/**
|
|
30
|
+
* 执行基于可达对象的 gc
|
|
31
|
+
*
|
|
32
|
+
* 默认行为:
|
|
33
|
+
* - 只保留从 HEAD、分支、标签可达的对象
|
|
34
|
+
* - 如果有 pack 支持:删除旧 pack 文件,创建包含可达对象的新 pack
|
|
35
|
+
* - 如果没有 pack 支持(如内存仓库):只删除不可达对象
|
|
36
|
+
*
|
|
37
|
+
* @returns 有 pack 支持时返回新 pack 的构建结果,否则返回 undefined
|
|
38
|
+
*/
|
|
39
|
+
gc(options?: RepositoryGCOptions): PackBuildResult | undefined;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { RepositoryMaintenanceOperations };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { hashObject } from "../../core/hash-digest.mjs";
|
|
2
|
+
import { readObject, writeObject } from "../../objects/raw.mjs";
|
|
3
|
+
import { createV2HttpTransport } from "../../transport/client/upload-pack/http.mjs";
|
|
4
|
+
import { objectInfo } from "../../transport/client/upload-pack/object-info.mjs";
|
|
5
|
+
import { patchTree } from "../tree/tree-patch.mjs";
|
|
6
|
+
//#region src/repository/ops/object-operations.ts
|
|
7
|
+
/**
|
|
8
|
+
* 仓库对象操作组装
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* 创建仓库对象相关操作
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const ops = createObjectRepositoryOperations(store);
|
|
16
|
+
* const hash = ops.writeBlob(Buffer.from("hello"));
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
function createObjectRepositoryOperations(objects) {
|
|
20
|
+
function writeBlob(data) {
|
|
21
|
+
return writeObject(objects, {
|
|
22
|
+
type: "blob",
|
|
23
|
+
content: data
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
hashObject(data) {
|
|
28
|
+
return hashObject("blob", data);
|
|
29
|
+
},
|
|
30
|
+
writeBlob,
|
|
31
|
+
catFile(hash) {
|
|
32
|
+
return readObject(objects, hash);
|
|
33
|
+
},
|
|
34
|
+
catFileType(hash) {
|
|
35
|
+
return readObject(objects, hash).type;
|
|
36
|
+
},
|
|
37
|
+
listObjects() {
|
|
38
|
+
return objects.list();
|
|
39
|
+
},
|
|
40
|
+
createTree(entries) {
|
|
41
|
+
return writeObject(objects, {
|
|
42
|
+
type: "tree",
|
|
43
|
+
entries
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
createCommit(tree, parents, message, author, committer) {
|
|
47
|
+
return writeObject(objects, {
|
|
48
|
+
type: "commit",
|
|
49
|
+
tree,
|
|
50
|
+
parents,
|
|
51
|
+
author,
|
|
52
|
+
committer: committer ?? author,
|
|
53
|
+
message
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
patchTree(rootHash, ops) {
|
|
57
|
+
return patchTree(objects, rootHash, ops);
|
|
58
|
+
},
|
|
59
|
+
async fetchObjectInfo(url, oids, token) {
|
|
60
|
+
return objectInfo(createV2HttpTransport(url, { token }), oids);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { createObjectRepositoryOperations };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { GitAuthor, GitObject, SHA1, TreeEntry } from "../../core/types.mjs";
|
|
2
|
+
import { ObjectInfoQueryResult } from "../../transport/client/upload-pack/object-info.mjs";
|
|
3
|
+
import { TreePatchOp, TreePatchResult } from "../tree/tree-patch.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/repository/ops/object-types.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* 仓库对象核心操作
|
|
8
|
+
*/
|
|
9
|
+
interface RepositoryObjectOperations {
|
|
10
|
+
/**
|
|
11
|
+
* 计算数据的 blob 哈希(不写入存储)
|
|
12
|
+
*
|
|
13
|
+
* 等价于 `git hash-object --stdin`
|
|
14
|
+
*/
|
|
15
|
+
hashObject(data: Buffer): SHA1;
|
|
16
|
+
/**
|
|
17
|
+
* 将数据作为 blob 写入对象存储
|
|
18
|
+
*
|
|
19
|
+
* 等价于 `git hash-object -w --stdin`
|
|
20
|
+
*/
|
|
21
|
+
writeBlob(data: Buffer): SHA1;
|
|
22
|
+
/**
|
|
23
|
+
* 读取对象
|
|
24
|
+
*
|
|
25
|
+
* 等价于 `git cat-file -p <hash>`
|
|
26
|
+
*/
|
|
27
|
+
catFile(hash: SHA1): GitObject;
|
|
28
|
+
/**
|
|
29
|
+
* 获取对象类型
|
|
30
|
+
*
|
|
31
|
+
* 等价于 `git cat-file -t <hash>`
|
|
32
|
+
*/
|
|
33
|
+
catFileType(hash: SHA1): string;
|
|
34
|
+
/**
|
|
35
|
+
* 列出仓库当前可见的所有对象哈希
|
|
36
|
+
*
|
|
37
|
+
* 返回值同时包含 loose objects 和 packed objects。
|
|
38
|
+
*/
|
|
39
|
+
listObjects(): SHA1[];
|
|
40
|
+
/**
|
|
41
|
+
* 从 tree 条目列表创建 tree 对象
|
|
42
|
+
*/
|
|
43
|
+
createTree(entries: TreeEntry[]): SHA1;
|
|
44
|
+
/**
|
|
45
|
+
* 创建 commit 对象
|
|
46
|
+
*
|
|
47
|
+
* 等价于 `git commit-tree <tree> -p <parent> -m <message>`
|
|
48
|
+
*/
|
|
49
|
+
createCommit(tree: SHA1, parents: SHA1[], message: string, author: GitAuthor, committer?: GitAuthor): SHA1;
|
|
50
|
+
/**
|
|
51
|
+
* 对已有 tree 执行增量 patch 操作
|
|
52
|
+
*
|
|
53
|
+
* 无需完整重构整棵树,只更新受影响的路径。
|
|
54
|
+
* 支持增(upsert)、删(delete)、改(upsert)文件及符号链接,
|
|
55
|
+
* 自动创建缺失的中间目录。
|
|
56
|
+
*
|
|
57
|
+
* @param rootHash - 根 tree 哈希
|
|
58
|
+
* @param ops - patch 操作列表(同路径多次操作最后一个生效)
|
|
59
|
+
* @returns patch 结果
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const result = repo.patchTree(rootHash, [
|
|
64
|
+
* { op: "upsert", path: "src/main.ts", mode: "100644", hash: blobHash },
|
|
65
|
+
* { op: "delete", path: "old.ts" },
|
|
66
|
+
* ]);
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
patchTree(rootHash: SHA1, ops: TreePatchOp[]): TreePatchResult;
|
|
70
|
+
/**
|
|
71
|
+
* 查询远端对象信息(协议 v2 object-info)
|
|
72
|
+
*
|
|
73
|
+
* 批量查询远端对象的元数据(如 size),无需下载对象内容。
|
|
74
|
+
* 仅在远端支持 Git Wire 协议 v2 时可用。
|
|
75
|
+
*
|
|
76
|
+
* @param url - 远端仓库 URL
|
|
77
|
+
* @param oids - 要查询的 OID 列表
|
|
78
|
+
* @param token - 可选认证 token
|
|
79
|
+
* @returns 对象信息列表(含 size 等元数据)
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* const result = await repo.fetchObjectInfo("https://github.com/user/repo", [
|
|
84
|
+
* "95d09f2b10159347eece71399a7e2e907ea3df4f",
|
|
85
|
+
* ]);
|
|
86
|
+
* console.log(result.objects[0]?.size); // 文件大小
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
fetchObjectInfo(url: string, oids: string[], token?: string): Promise<ObjectInfoQueryResult>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 文件系统对象操作扩展
|
|
93
|
+
*/
|
|
94
|
+
interface RepositoryFsObjectOperations {
|
|
95
|
+
/**
|
|
96
|
+
* 将文件作为 blob 写入对象存储
|
|
97
|
+
*
|
|
98
|
+
* 等价于 `git hash-object -w <file>`
|
|
99
|
+
*/
|
|
100
|
+
writeBlobFile(filePath: string): SHA1;
|
|
101
|
+
/**
|
|
102
|
+
* 将目录递归写入 tree 对象
|
|
103
|
+
*
|
|
104
|
+
* 等价于 `git write-tree`(但基于指定目录而非暂存区)
|
|
105
|
+
*/
|
|
106
|
+
writeTree(dirPath: string): SHA1;
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { RepositoryFsObjectOperations, RepositoryObjectOperations };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import "../../transport/client/receive-pack/push-error.mjs";
|
|
2
|
+
import { runPushToUrl } from "./push-url.mjs";
|
|
3
|
+
//#region src/repository/ops/push-operations.ts
|
|
4
|
+
/**
|
|
5
|
+
* 创建仓库 push 操作集合
|
|
6
|
+
*
|
|
7
|
+
* @param backend - 仓库后端
|
|
8
|
+
* @returns push 操作集合
|
|
9
|
+
*/
|
|
10
|
+
function createPushRepositoryOperations(backend) {
|
|
11
|
+
return { async push(url, options) {
|
|
12
|
+
return runPushToUrl(backend, url, options);
|
|
13
|
+
} };
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { createPushRepositoryOperations };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/repository/ops/push-resolution.ts
|
|
2
|
+
/**
|
|
3
|
+
* 解析 effective push shallow 边界
|
|
4
|
+
*
|
|
5
|
+
* 三态规则(`pushShallowBoundaries` 为 override,勿将 `[]` 当 falsy):
|
|
6
|
+
* - `options.pushShallowBoundaries === undefined`:回退 `backendShallow`(即 `backend.shallow.read()`)
|
|
7
|
+
* - `options.pushShallowBoundaries === []`:显式无边界,不使用 `backend.shallow`
|
|
8
|
+
* - `options.pushShallowBoundaries === [...]`:显式边界集合
|
|
9
|
+
*
|
|
10
|
+
* 输出为最终传给 transport 的 `shallowBoundaries` 数组;仅当 options 与 backend 均未提供时为 `undefined`。
|
|
11
|
+
*/
|
|
12
|
+
function resolveEffectivePushBoundaries(options, backendShallow) {
|
|
13
|
+
if (options?.pushShallowBoundaries !== void 0) return options.pushShallowBoundaries;
|
|
14
|
+
if (backendShallow !== void 0) return backendShallow;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { resolveEffectivePushBoundaries };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { SHA1 } from "../../core/types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/repository/ops/push-types.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* 仓库 push 操作选项
|
|
6
|
+
*
|
|
7
|
+
* 纯 push 行为参数,不包含传输层细节。
|
|
8
|
+
*
|
|
9
|
+
* 认证:支持 token/headers 透传到 transport。
|
|
10
|
+
* 边界:pushShallowBoundaries 是 repository 层语义(不是 transport 泄漏),优先级高于 backend.shallow。
|
|
11
|
+
*/
|
|
12
|
+
interface RepositoryPushOptions {
|
|
13
|
+
/**
|
|
14
|
+
* refspec 列表,格式如 "refs/heads/main:refs/heads/main"
|
|
15
|
+
* 默认为将当前分支推送到远端同名分支(等价于 `git push <url>`)
|
|
16
|
+
*/
|
|
17
|
+
readonly refSpecs?: string[];
|
|
18
|
+
/** 是否强制推送(--force),等价于 refspec 的 + 前缀 */
|
|
19
|
+
readonly force?: boolean;
|
|
20
|
+
/** 认证 token(用于 bearer 或 basic auth),由 repository 层透传 */
|
|
21
|
+
readonly token?: string;
|
|
22
|
+
/** 自定义请求头,由 repository 层透传 */
|
|
23
|
+
readonly headers?: Record<string, string>;
|
|
24
|
+
/**
|
|
25
|
+
* 推送时已知的浅克隆边界(repository 层 override,非 transport 泄漏)。
|
|
26
|
+
* - 传入(含空数组 `[]`)即覆盖 `backend.shallow`,不再回退
|
|
27
|
+
* - 传 `[]` 表示显式不使用 `backend.shallow` 中的边界
|
|
28
|
+
* - 不传(`undefined`)才回退 `backend.shallow.read()`
|
|
29
|
+
*/
|
|
30
|
+
readonly pushShallowBoundaries?: SHA1[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 单条引用更新结果(repository 自有语义)
|
|
34
|
+
*/
|
|
35
|
+
interface PushRefUpdateResult {
|
|
36
|
+
/** 引用名称,如 "refs/heads/main" */
|
|
37
|
+
readonly refName: string;
|
|
38
|
+
/** 更新前的哈希(服务端原有值) */
|
|
39
|
+
readonly oldHash: SHA1 | null;
|
|
40
|
+
/** 更新后的哈希 */
|
|
41
|
+
readonly newHash: SHA1 | null;
|
|
42
|
+
/** 是否成功 */
|
|
43
|
+
readonly success: boolean;
|
|
44
|
+
/** 失败时的错误消息 */
|
|
45
|
+
readonly error?: string;
|
|
46
|
+
/** 是否强制更新 */
|
|
47
|
+
readonly forced: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 仓库 push 操作结果(repository 自有语义)
|
|
51
|
+
*/
|
|
52
|
+
interface RepositoryPushResult {
|
|
53
|
+
/** 已更新的引用列表 */
|
|
54
|
+
readonly pushedRefs: readonly PushRefUpdateResult[];
|
|
55
|
+
/** 推送的对象数量 */
|
|
56
|
+
readonly objectCount: number;
|
|
57
|
+
/** 服务端返回的进度消息 */
|
|
58
|
+
readonly progress: readonly string[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 仓库 push 操作接口
|
|
62
|
+
*/
|
|
63
|
+
interface RepositoryPushOperations {
|
|
64
|
+
/**
|
|
65
|
+
* 推送到远端仓库
|
|
66
|
+
*
|
|
67
|
+
* 等价于 `git push <url>`。
|
|
68
|
+
*/
|
|
69
|
+
push(url: string, options?: RepositoryPushOptions): Promise<RepositoryPushResult>;
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { RepositoryPushOperations };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { createReceivePackHttpClient } from "../../transport/client/receive-pack/http.mjs";
|
|
2
|
+
import { push } from "../../transport/client/receive-pack/push.mjs";
|
|
3
|
+
import { resolveEffectivePushBoundaries } from "./push-resolution.mjs";
|
|
4
|
+
//#region src/repository/ops/push-url.ts
|
|
5
|
+
/**
|
|
6
|
+
* 仓库 push 内部编排
|
|
7
|
+
*
|
|
8
|
+
* 支持 preAdvertised、transportFactory 注入。
|
|
9
|
+
* 使用 v1 receive-pack 协议进行推送。
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* 按 URL push(不依赖任何命名 endpoint 配置)
|
|
13
|
+
*/
|
|
14
|
+
async function runPushToUrl(backend, url, options, preAdvertised, transportFactory) {
|
|
15
|
+
return runPushWithUrl(backend, url, options, preAdvertised, transportFactory);
|
|
16
|
+
}
|
|
17
|
+
async function runPushWithUrl(backend, pushUrl, options, preAdvertised, transportFactory) {
|
|
18
|
+
const transport = (transportFactory ?? ((url) => createReceivePackHttpClient(url, {
|
|
19
|
+
token: options?.token,
|
|
20
|
+
headers: options?.headers
|
|
21
|
+
})))(pushUrl, options);
|
|
22
|
+
const advertisement = preAdvertised ?? await transport.advertise();
|
|
23
|
+
const transportResult = await push(backend.objects, backend.refs, transport, advertisement, {
|
|
24
|
+
refSpecs: options?.refSpecs,
|
|
25
|
+
force: options?.force,
|
|
26
|
+
shallowBoundaries: resolveEffectivePushBoundaries(options, backend.shallow.read())
|
|
27
|
+
});
|
|
28
|
+
return convertPushResult(transportResult.refUpdates, transportResult.objectCount, transportResult.progress);
|
|
29
|
+
}
|
|
30
|
+
function convertPushResult(refUpdates, objectCount, progress) {
|
|
31
|
+
return {
|
|
32
|
+
pushedRefs: refUpdates.map((u) => ({
|
|
33
|
+
refName: u.refName,
|
|
34
|
+
oldHash: u.oldHash,
|
|
35
|
+
newHash: u.newHash,
|
|
36
|
+
success: u.success,
|
|
37
|
+
error: u.error,
|
|
38
|
+
forced: u.forced ?? false
|
|
39
|
+
})),
|
|
40
|
+
objectCount,
|
|
41
|
+
progress
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { runPushToUrl };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { readObject } from "../../objects/raw.mjs";
|
|
2
|
+
import { HEADS_PREFIX, HEAD_REF, TAGS_PREFIX } from "../../core/types/refs.mjs";
|
|
3
|
+
import { resolveRefHash } from "../../refs/resolve.mjs";
|
|
4
|
+
//#region src/repository/ops/reachability.ts
|
|
5
|
+
/**
|
|
6
|
+
* 仓库可达性遍历工具
|
|
7
|
+
*
|
|
8
|
+
* 负责从 refs 出发遍历所有可达 Git 对象。
|
|
9
|
+
*/
|
|
10
|
+
function listRootRefs(refs) {
|
|
11
|
+
const rootRefs = /* @__PURE__ */ new Set([HEAD_REF]);
|
|
12
|
+
for (const ref of refs.list(HEADS_PREFIX)) rootRefs.add(ref);
|
|
13
|
+
for (const ref of refs.list(TAGS_PREFIX)) rootRefs.add(ref);
|
|
14
|
+
return Array.from(rootRefs).sort();
|
|
15
|
+
}
|
|
16
|
+
function collectReachableObjectHashesFrom(source, hash, reachable) {
|
|
17
|
+
const stack = [hash];
|
|
18
|
+
while (stack.length > 0) {
|
|
19
|
+
const current = stack.pop();
|
|
20
|
+
if (reachable.has(current)) continue;
|
|
21
|
+
reachable.add(current);
|
|
22
|
+
const obj = readObject(source, current);
|
|
23
|
+
switch (obj.type) {
|
|
24
|
+
case "blob": break;
|
|
25
|
+
case "tree":
|
|
26
|
+
for (const entry of obj.entries) if (!reachable.has(entry.hash)) stack.push(entry.hash);
|
|
27
|
+
break;
|
|
28
|
+
case "commit":
|
|
29
|
+
if (!reachable.has(obj.tree)) stack.push(obj.tree);
|
|
30
|
+
for (const parent of obj.parents) if (!reachable.has(parent)) stack.push(parent);
|
|
31
|
+
break;
|
|
32
|
+
case "tag":
|
|
33
|
+
if (!reachable.has(obj.object)) stack.push(obj.object);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 列出从 HEAD、所有分支和所有标签可达的对象哈希
|
|
40
|
+
*
|
|
41
|
+
* @param source - 对象源
|
|
42
|
+
* @param refs - 引用存储
|
|
43
|
+
* @returns 排序后的可达对象哈希列表
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const hashes = listReachableObjects(source, refs);
|
|
48
|
+
* console.log(hashes.length);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
function listReachableObjects(source, refs) {
|
|
52
|
+
const reachable = /* @__PURE__ */ new Set();
|
|
53
|
+
for (const ref of listRootRefs(refs)) {
|
|
54
|
+
const hash = resolveRefHash(refs, ref);
|
|
55
|
+
if (hash) collectReachableObjectHashesFrom(source, hash, reachable);
|
|
56
|
+
}
|
|
57
|
+
return Array.from(reachable).sort();
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
export { listReachableObjects };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { RepositoryError } from "../../core/errors.mjs";
|
|
2
|
+
import { readObject, writeObject } from "../../objects/raw.mjs";
|
|
3
|
+
import { HEADS_PREFIX, HEAD_REF, TAGS_PREFIX } from "../../core/types/refs.mjs";
|
|
4
|
+
import { branchNameToRef, tagNameToRef } from "../../refs/names.mjs";
|
|
5
|
+
import { resolveRefHash, resolveSymbolicRef, resolveTargetHash } from "../../refs/resolve.mjs";
|
|
6
|
+
//#region src/repository/ops/ref-operations.ts
|
|
7
|
+
/**
|
|
8
|
+
* 仓库引用操作组装
|
|
9
|
+
*/
|
|
10
|
+
function ensureRefDoesNotExist(backend, ref, kind, name) {
|
|
11
|
+
if (backend.refs.read(ref) !== null) throw new RepositoryError(`${kind} already exists: ${name}`);
|
|
12
|
+
}
|
|
13
|
+
function listShortRefs(backend, prefix) {
|
|
14
|
+
return backend.refs.list(prefix).map((ref) => ref.slice(prefix.length));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 创建仓库引用相关操作
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const ops = createRefRepositoryOperations(backend);
|
|
22
|
+
* ops.createBranch("main");
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
function createRefRepositoryOperations(backend) {
|
|
26
|
+
const { objects, refs } = backend;
|
|
27
|
+
function getCurrentBranch() {
|
|
28
|
+
const symbolicRef = resolveSymbolicRef(refs, HEAD_REF);
|
|
29
|
+
if (!symbolicRef || !symbolicRef.startsWith("refs/heads/")) return null;
|
|
30
|
+
return symbolicRef.slice(HEADS_PREFIX.length);
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
updateRef(ref, hash) {
|
|
34
|
+
refs.write(ref, hash);
|
|
35
|
+
},
|
|
36
|
+
readRef(ref) {
|
|
37
|
+
return resolveRefHash(refs, ref);
|
|
38
|
+
},
|
|
39
|
+
getCurrentBranch,
|
|
40
|
+
createBranch(name, hash) {
|
|
41
|
+
const ref = branchNameToRef(name);
|
|
42
|
+
ensureRefDoesNotExist(backend, ref, "Branch", name);
|
|
43
|
+
refs.write(ref, resolveTargetHash(refs, hash));
|
|
44
|
+
},
|
|
45
|
+
readBranch(name) {
|
|
46
|
+
return resolveRefHash(refs, branchNameToRef(name));
|
|
47
|
+
},
|
|
48
|
+
listBranches() {
|
|
49
|
+
return listShortRefs(backend, HEADS_PREFIX);
|
|
50
|
+
},
|
|
51
|
+
deleteBranch(name) {
|
|
52
|
+
if (getCurrentBranch() === name) throw new RepositoryError(`Cannot delete current branch: ${name}`);
|
|
53
|
+
refs.delete(branchNameToRef(name));
|
|
54
|
+
},
|
|
55
|
+
createTag(name, hash) {
|
|
56
|
+
const ref = tagNameToRef(name);
|
|
57
|
+
ensureRefDoesNotExist(backend, ref, "Tag", name);
|
|
58
|
+
refs.write(ref, resolveTargetHash(refs, hash));
|
|
59
|
+
},
|
|
60
|
+
createAnnotatedTag(name, target, message, tagger, objectType) {
|
|
61
|
+
const ref = tagNameToRef(name);
|
|
62
|
+
ensureRefDoesNotExist(backend, ref, "Tag", name);
|
|
63
|
+
const tagHash = writeObject(objects, {
|
|
64
|
+
type: "tag",
|
|
65
|
+
object: target,
|
|
66
|
+
objectType: objectType ?? readObject(objects, target).type,
|
|
67
|
+
tag: name,
|
|
68
|
+
tagger,
|
|
69
|
+
message
|
|
70
|
+
});
|
|
71
|
+
refs.write(ref, tagHash);
|
|
72
|
+
return tagHash;
|
|
73
|
+
},
|
|
74
|
+
readTag(name) {
|
|
75
|
+
return resolveRefHash(refs, tagNameToRef(name));
|
|
76
|
+
},
|
|
77
|
+
listTags() {
|
|
78
|
+
return listShortRefs(backend, TAGS_PREFIX);
|
|
79
|
+
},
|
|
80
|
+
deleteTag(name) {
|
|
81
|
+
refs.delete(tagNameToRef(name));
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
export { createRefRepositoryOperations };
|