Sync files between worktrees.
Find a file
2026-04-16 17:14:39 +08:00
src feat: add copy/overwrite flags 2026-04-16 17:14:39 +08:00
.gitignore feat: init the repo 2026-04-03 14:25:49 +08:00
.scalafmt.conf feat: init the repo 2026-04-03 14:25:49 +08:00
package-native.sh feat: init the repo 2026-04-03 14:25:49 +08:00
project.scala feat: init the repo 2026-04-03 14:25:49 +08:00
README.md feat: add copy/overwrite flags 2026-04-16 17:14:39 +08:00

syncedtrees workspace

syncedtrees/ 是这个工具自己的 Scala CLI 工作区。

设计更新

相较于之前的单文件原型,这个工作区版本做了这些升级:

  • 动态发现 worktree:通过 git worktree list --porcelain 实时发现,而不是在配置里维护 tree 列表。
  • Schema 驱动配置读取:配置会被反序列化为 RawConfig / ResolvedConfig,并结合 Cats Validated 做语义校验。
  • Cats Effect 架构:主流程和副作用都通过 IO 组织,便于扩展和测试。
  • os-lib 系统操作:命令执行采用 os.proc,简化子进程调用和输出处理。
  • 独立 workspace源码、测试、scalafmt、打包产物都放在 syncedtrees/ 下管理。

目录结构

syncedtrees/
  .scalafmt.conf
  project.scala
  README.md
  package-native.sh
  dist/
  src/
    main/scala/syncedtrees/
    test/scala/syncedtrees/

运行

从 workspace 根目录的上一层执行:

scala-cli run --server=false syncedtrees -- --help
scala-cli run --server=false syncedtrees -- init ./tree-a
scala-cli run --server=false syncedtrees -- status '*'
scala-cli run --server=false syncedtrees -- sync tree-b
scala-cli run --server=false syncedtrees -- cleanup tree-b
scala-cli run --server=false syncedtrees -- exec tree-b pwd
scala-cli run --server=false syncedtrees -- new tree-c feat/my-branch main

注意:像 --config--dry-run--verbose 这样的全局参数需要放在子命令之前。例如:

scala-cli run --server=false syncedtrees -- --config ./custom.conf init ./tree-a
scala-cli run --server=false syncedtrees -- --dry-run sync tree-b

配置

默认配置仍然在工作区根目录的 syncedtrees.conf。 如果还没有配置文件,先运行:

scala-cli run --server=false syncedtrees -- init ./tree-a

init 会:

  • 校验传入路径是否是 git repo / worktree
  • 生成 starter syncedtrees.conf
  • 自动填入 primaryTreeprimaryTreePathdefaultBaseBranch
  • 输出后续操作提示

支持 camelCase也兼容 kebab-case

  • basePath / base-path
  • sharedRoot / shared-root
  • primaryTree / primary-tree
  • defaultBaseBranch / default-base-branch
  • treeSettings / tree-settings
  • disabledLinks / disabled-links

links 里的每一项支持这些字段:

  • name
  • source
  • target
  • optional
  • overwrite
  • copy

例如:

links = [
  {
    name = "agents-md"
    source = "AGENTS.md"
    target = "AGENTS.md"
    overwrite = true
    copy = true
  }
]

其中 copy = true 时,sync 会把 source 复制到目标位置;如果 source 是目录,会递归复制目录内容,而不是创建符号链接。overwrite = true 时,如果目标位置已经有旧文件、旧目录,或者旧的符号链接(包括 drifted symlink会先清理目标再复制/创建;默认是 false,会保持现状并继续报 blockedcleanup 会删除 copy = true 且内容仍与 source 对应的受管文件或目录,也会继续删除普通 link 模式生成的符号链接;如果 copy 目标已经被本地改动到不再匹配 source则会跳过避免误删本地内容。

运行时不再依赖代码内置默认业务配置;如果配置项缺失或为空,会直接报错并提示修正。

打包 native image

已提供脚本:

./syncedtrees/package-native.sh

脚本会优先使用你当前 SDKMAN 环境里已经可用的 native-image 如果当前 SDK 没有 native-image,则自动回退到 scala-cli 通过 coursier 拉取 graalvm-java21 来完成打包。脚本默认传递 --no-fallback,因此会尽量产出 真正可独立运行的 native binary而不是 fallback image。

它会产出:

  • syncedtrees/dist/syncedtrees

也可以手动执行:

scala-cli --power package --server=false syncedtrees \
  --native-image \
  --graalvm-args --no-fallback \
  --jvm graalvm-java21 \
  --main-class syncedtrees.Main \
  -f \
  -o syncedtrees/dist/syncedtrees

测试与格式化

scala-cli compile --server=false syncedtrees
scala-cli test --server=false syncedtrees
scala-cli fmt syncedtrees