Repository navigation
Description
使用场景
我用同一个私有仓库(LingYingNX/backup)集中备份多款工具的配置,按工具分子目录:
Hindsight知识库备份/magpie备份/DSH备份/(本次为 DSH 配置同步新建)
这是我长期形成的「一个仓库 + 每个工具一个子目录」的备份习惯,便于统一管理、统一权限、统一查看提交历史。
问题
dsh-config-manager 的 Git 通道只能配置「仓库地址」一个字段,快照固定写到仓库根目录下的 snapshots/、snapshots-encrypted/、blobs/,没有子目录 / 路径前缀选项:
src/sync/sync-config.ts:
export interface GitConfig { repoUrl: string }src/sync/git/git-transport.ts:171-187:
const SNAPSHOTS_REL = 'snapshots'
const SNAPSHOTS_ENCRYPTED_REL = 'snapshots-encrypted'
const BLOBS_REL = 'blobs'上传路径统一拼在工作副本根。结果是:只要在这个仓库里启用 DSH 同步,snapshots/ 等目录就会散落在仓库顶层,与 Hindsight知识库备份/、magpie备份/、DSH备份/ 平级,破坏「每个工具一个独立目录」的结构;如果为了保持整洁而换一个专用仓库,又多出一个仓库要管理。
S3 通道有「对象键前缀」、Gist 通道有「文件名前缀」,说明框架本身支持带前缀的存储布局,只是 Git 通道没有暴露这个能力。
期望方案
给 Git 通道增加一个可选的「仓库内子目录 / 路径前缀」配置项(例如 subdir: "DSH备份"),所有快照写入 subdir/snapshots/、subdir/snapshots-encrypted/、subdir/blobs/,读取、比对、清理、接管历史等逻辑同样以该前缀为根。
参考实现要点:
- 配置项:
GitConfig增加可选subdir(或pathPrefix),默认空 = 当前行为,保证向后兼容;UI 放在「仓库地址」下一行,标注「可选,留空则写入仓库根目录」。 - 路径拼接:
git-transport.ts中所有${SNAPSHOTS_REL}/...统一改为${prefix}${SNAPSHOTS_REL}/...,并对前缀做合法性校验(禁止绝对路径、..、反斜杠、以.git开头等)。 - sparse-checkout:
cloneIntoWorkDir()的sparse-checkout set --cone snapshots snapshots-encrypted blobs也要带上前缀(cone 模式下传subdir/snapshots这类路径即可)。 - adopt 边界:
ADOPT_ROOT_ALLOW的顶层白名单要按前缀调整,避免把带前缀的仓库误判为「另有用途的仓库」而拒绝接管历史。 - 兼容与迁移:老配置(无
subdir)行为完全不变;从「根」切到「子目录」时给出提示,说明两侧快照历史不互通(或提供一次性迁移)。
备选方案
- 保持现状,另建一个专用私有仓库给 DSH 使用:能解决隔离问题,但仓库数量变多,不符合「一个仓库集中管理」的习惯。
- 改用 WebDAV / S3 通道:这两条通道本来就有子目录 / 前缀,但需要额外的服务端,成本更高。
- 由插件在 git 层硬编码一个固定子目录(例如统一写
dsh-config-manager/):至少不污染仓库顶层,但仍不可配置,不如做成可选前缀。
补充
仓库现状截图(根目录下按工具划分的多个备份目录):
Triage 诊断(AI)
This was generated by AI during triage.
状态:未实现。诊断完成,4 项设计决策已由维护者拍板;agent brief 已发,票转 ready-for-agent。
现状核对
GitConfig只有repoUrl,git 通道没有前缀字段。- 三处同步目录(明文快照 / 加密快照 / 内容寻址 blob)是模块级常量,上传、下载、删除、GC、远端统计全在仓库根上拼路径。
- 同一能力在 S3(
prefix)与 gist(filePrefix)已有先例,git 缺这一层;诉求成立,分类enhancement。
变更面
路径常量与拼接、sparse 面(SYNC_ROOT_DIRS)、adopt 判据(ADOPT_ROOT_ALLOW)、GitTransportOptions 与 host 装配、sync-config 的 v2 解析与写入、通道配置 UI、对外契约 docs/contracts/sync-channel-v1.md 的通道布局表。
定案(2026-11-09 维护者拍板)
- 前缀变更 → 强制重建工作副本:复用既有 relink / adopt / reclone 入口;前缀纳入工作副本身份判定,不符即报「需重建」,不做静默迁移。
- adopt 改判
<subdir>/子树:只要求该子树下只出现三类同步目录,仓库顶层允许有别的目录(多工具备份仓库的正常形态);子树内出现陌生条目仍拒绝。 - 不做快照迁移:根 ↔ 子目录切换只提示「两侧历史不互通」。
- 前缀口径:允许 UTF-8(中文目录)与嵌套;拒绝绝对路径、
..、反斜杠、空段、首尾斜杠、.git段。
下一步:AFK agent 按 brief 实施;完成后按 issue-intake-response 回访报告者。
进度
- 进度:100%(2026-11-09T22:06:23+01:00):已实现并本地验证通过(typecheck / npm test 5525 通过 / build 全绿),尚未发版
Activity
github-actions commentedon Nov 9, 2026
感谢反馈!🙏 我通常会在 48 小时内回复;这条已加上
needs-triage,进度会体现在标签上。Thanks for the report! I usually reply within 48h. This issue is labeled
needs-triage; progress shows up in the labels.如果还没写,补上这几项能少好几轮来回 / Adding these saves round trips:
xiajiajun516 commentedon Nov 9, 2026
Agent Brief
Category: enhancement
Summary: git 同步通道增加可选的「仓库内子目录前缀」,让多工具共用一个备份仓库时各自独立。
Current behavior:
git 通道的配置只有仓库地址(
GitConfig只有repoUrl)。三处同步目录——明文快照目录、加密快照目录、内容寻址 blob 目录——是模块级常量,上传、下载、删除、GC、远端快照统计都直接拼在工作副本根上。首次 clone 的 sparse-checkout 面与adopt模式的顶层白名单也由同一组常量派生。结果是:在一个已按工具分好子目录的备份仓库里启用 DSH 同步,这三个目录会落在仓库顶层,破坏「一个工具一个目录」的结构。Desired behavior:
subdir,语义对齐 S3 的prefix):缺省或空 = 现有行为(写仓库根);配置后所有同步目录都落到<subdir>/之下,读写、比对、删除、GC、远端统计、sparse 面、adopt 判据全部以该前缀为根。a/b);拒绝绝对路径、..、反斜杠、空段、首尾斜杠、.git段。校验失败回结构化错误码,不静默丢弃该值。adopt在设了前缀时改判<subdir>/子树:只要求该子树下只出现三类同步目录;仓库顶层允许出现别的目录(多工具备份仓库的正常形态)。子树下出现陌生条目仍然拒绝。Key interfaces:
GitConfig:新增可选前缀字段。v2 命名空间的解析与写入都必须显式搬运它——当前解析只构造{ repoUrl },不显式搬字段会被静默丢掉。GitTransportOptions:新增同一前缀字段,由 host 装配处从配置传入。validateCloudPrefix的口径(禁绝对路径、..、反斜杠、空段),扩展为允许 UTF-8 与嵌套段,并补.git段与首尾斜杠拒绝;错误码并入同族的既有错误码集合。SYNC_ROOT_DIRS、adopt 白名单ADOPT_ROOT_ALLOW):改为按前缀派生,不再在模块顶层固化。Acceptance criteria:
subdir: "DSH备份"后 push 的快照落在DSH备份/snapshots/…、DSH备份/snapshots-encrypted/…、DSH备份/blobs/…,仓库顶层不出现这三个目录<subdir>/下三个目录,且不 materialize 仓库里其它工具目录adopt在多工具仓库(顶层含别的工具目录)上成功;<subdir>/下出现陌生条目仍被拒绝a/b通过;绝对路径、..、反斜杠、空段、首尾斜杠、.git段被拒并回错误码CHANGELOG.md的## [Unreleased]有用户可见条目Out of scope:
xiajiajun516 commentedon Nov 9, 2026
已在 v0.7.0 修复并发布。
Git 通道现在可以在同步设置里填一个仓库内子目录前缀(例如
DSH备份/),快照就落在这个子目录下;留空仍是原来的仓库根布局,行为不变。升级:
dsh plugin --profile web add dsh-config-manager@latest(桌面版在插件页更新后重启)。自证三步:
DSH备份/,保存;DSH备份/snapshots/…而不是根目录下的snapshots/;