// DOCS · 双端同步

双端同步 · Dual Syncv2 · 已自动化

Win(autumn)/ mac 双机协作基础设施。两套彼此独立的系统:个人文件同步(每天自动)与 网站代码 git 部署(手动触发)。

⚡ 三步速查 · 忘了怎么用就看这里
  1. 个人文件(todo-hub / WorkBuddy 记忆与技能) 什么都不用做。每天 08:00 自动推送到 GitHub + ECS 双备份。
  2. 换到另一台机器开工前 先拉一次对端改动,避免覆盖: ~/.sync/sync.sh pull
  3. 改网站 这条链路不自动,改完要手动发布(见第 5 节)。或者直接告诉八戒「把 XX 发到网站」,由他走 ECS 通道处理。
v2 更新(2026-08-07): 个人文件同步已接入每日自动化。此前需手动 sync.sh push,现由 launchd 每天 08:00 自动执行,并入 daily.sh 第 4 步。
⚠️ 唯一铁律:绝不覆盖坤哥修改的线上网站文件。 其余都是手段。任何发布动作都先备份、可回滚。

1. 两套系统,别搞混

系统管什么是否自动
A. 个人文件同步
~/.sync/sync.sh
todo-hub 任务数据、WorkBuddy 的记忆 / 技能 / 配置。双机之间保持一致,同时做异地备份。 ✅ 每天 08:00
B. 网站代码部署
site-code + site-deploy.sh
likun.im 的页面代码。本地改 → 推 git → 预览站验收 → 正式发布。 ✋ 手动触发

两者共用同一台 ECS 和同一套 SSH 凭据,但仓库不同、流程不同、风险不同。日常绝大多数情况只会碰到 A(而 A 已经不需要你动手)。

2. A · 个人文件同步(已自动)

2.1 架构

本机真实位置(mac / Win)
   │  sync.sh push:按白名单镜像进 ~/.sync/repo
   ▼
~/.sync/repo(git 工作区)
   │  git push(双远端,各自独立成败)
   ├─▶ GitHub: imlikun/sync-workspace(备份A · 私有)
   └─▶ ECS:    /srv/sync/backup.git    (备份B · 裸仓)
              └─ 另有 Gitee sync-audit 仅用于三方对账

2.2 同步范围(白名单,配置在 ~/.sync/sync.conf)

是白名单不是全盘同步——没列进去的目录不会被碰,也不会被备份。

2.3 强制排除(~/.sync/.syncignore)

以下内容永远不进仓库,即使落在白名单目录里:

这就是为什么保险库口令不会被同步走。 VAULT_MASTER 存在 .env 里,被 .syncignore 拦下,不会出现在 GitHub 上。保险库口令的冗余走的是另一套机制(见 保险库文档 第 8 节),两者互不干扰。

2.4 自动化怎么跑的

launchd: com.appin.todo-hub-daily  每天 08:00
   └─▶ ~/todo-hub/skill/wb-todo-hub/scripts/daily.sh
         [1/4] 刷新看板并部署到 /tasks/
         [2/4] 备份 todo-hub 数据到 ECS(保留 7 份)
         [3/4] 保险库 master 三点体检
         [4/4] 双端同步 push(GitHub + ECS)   ← 本节

日志在 ~/todo-hub/logs/daily-*.log,保留最近 14 天。第 4 步成功时记录 ✅ 双端同步完成(GitHub + ECS)。

2.5 安全性:为什么自动 push 不会出事

2.6 手动命令(需要时才用)

~/.sync/sync.sh status          # 双机在线状态 / 锁 / 待交接任务
~/.sync/sync.sh pull            # 拉对端改动到本机(换机开工前跑)
~/.sync/sync.sh push "说明"      # 立即同步(不等 08:00)
~/.sync/sync.sh audit           # 三方对账(GitHub vs ECS)
~/.sync/sync.sh handoff T-1 "交接说明"   # 把任务交给对端
~/.sync/sync.sh takeover T-1    # 认领对端交来的任务
~/.sync/sync.sh restore         # 从远端恢复本机文件

3. 心跳与交接

每次 push 会自动更新本机心跳,status 里能看到对端是在线还是离线。这不是实时通信——它的用途是换机时判断对端有没有未同步的改动。

4. B · 网站代码 git 部署(手动)

~/Projects/site-code(真实编辑位置;Win 在 /c/Users/Kun.li/Projects/site-code)
   │  git push(一次推双远端)
   ├─▶ GitHub: imlikun/site-code(备份A)
   └─▶ ECS 裸仓: /srv/sync/site-code.git(备份B)
            └─ post-receive hook → /www/wwwroot/preview.likun.im(预览 · 单向投影)
正式发布(在 ECS 执行): /usr/local/bin/site-deploy.sh [commit]
cd ~/Projects/site-code
git add -A && git commit -m "说明"
git push github main && git push ecs main

# 看效果:http://preview.likun.im
# 验收 OK → 正式发布:
ssh appin-server '/usr/local/bin/site-deploy.sh'
# 回滚:ssh appin-server '/usr/local/bin/site-deploy.sh <旧commit>'
发布守卫: site-deploy.sh 发布前会 diff 线上与 git。若线上有未入库的改动 → 拒绝发布(exit 1),提示先把线上文件拉回本地入库。--force 可跳过,慎用。

另一条路:直接让八戒改站

本站近期的实际改动(/hub.html、/docs/、/accounts/ 等)走的是 ECS 即真相源 通道:下载线上文件 → 本地改 → 上传覆盖,不经过 git。这条路更快,代价是改动不进 site-code 仓库历史。

两条路混用的风险: 若 ECS 上有八戒直接改过的文件,之后再走 git 发布,守卫会检测到差异并拒绝,需要先把线上改动拉回 site-code 入库。这是设计如此——宁可拦下,也不覆盖。

5. 关键资源清单

资源位置
个人同步 CLI~/.sync/sync.sh
个人同步配置~/.sync/sync.conf(白名单 SYNC_PATHS)
排除规则~/.sync/.syncignore
本地 git 工作区~/.sync/repo
备份A · GitHubimlikun/sync-workspace(私有)
备份B · ECS 裸仓ssh://root@101.133.136.140/srv/sync/backup.git
对账仓Gitee imlikun/sync-audit
自动化入口~/todo-hub/skill/wb-todo-hub/scripts/daily.sh(第 4 步)
定时配置~/Library/LaunchAgents/com.appin.todo-hub-daily.plist
运行日志~/todo-hub/logs/daily-*.log
网站代码~/Projects/site-code
网站备份A / Bimlikun/site-code / ECS /srv/sync/site-code.git
预览站 / 正式站preview.likun.im / likun.im
发布脚本ECS /usr/local/bin/site-deploy.sh
换机任务书~/Projects/site-code/tools/macos-deploy-guide.md(三次握手)

6. 排障

现象处理
日志出现 push: 1/2 成功某个远端不可达(GitHub 常因本机代理间歇断流)。跑 sync.sh audit 对账,下次自动 push 会补齐。
日志出现 rebase 冲突两台机器改了同一文件。到 ~/.sync/repo 手动解决冲突后再 push。不要强推。
status 显示对端"离线/未知"只表示对端最近没 push 过,不是故障。对端开机跑一次 push 即恢复。
网站发布被拒绝线上有未入库改动(很可能是八戒直接改的)。先把线上文件拉回 site-code 提交,再发布。
某个文件死活同步不过去先查是否命中 .syncignore(密钥、大文件、本机状态类会被强制排除),再查是否在 SYNC_PATHS 白名单内。

7. 已知边界