唠唠闲话

最近在使用 Trae 的 Remote - SSH 功能时遇到了一个令人头疼的问题:无法连接 SSH 服务器。经过一番排查,发现问题根源在于国内网络环境无法顺畅访问 GitHub,而 Remote SSH 每次连接时都需要从 GitHub 下载 vscodium-rh-linux-x64-*.tar.gz 文件。

一个临时方法是手动下载文件,并上传到服务器,参考这里:Remote - SSH for Trae 连接问题解决方案

但这个方式比较繁琐,每次连接都需要手动操作。

为此,我开始寻找替代的文件同步方案,突然想起了 Unison 这个强大的工具。与传统的 rsync 不同,Unison 支持双向同步,非常适合开发场景。

什么是 Unison?

Unison 是一个跨平台的文件同步工具,支持双向同步,可以在本地和远程系统之间保持文件的一致性。与 rsync 的单向同步不同,Unison 能够:

  • 双向同步:检测并合并两个位置的更改
  • 智能冲突处理:当同一文件在两个位置都被修改时,会提示用户选择
  • 跨平台支持:支持 Windows、macOS、Linux 等多种操作系统
  • 增量同步:只传输发生变化的部分,提高效率
  • 支持 SSH:可以通过 SSH 进行安全的远程同步

GitHub 项目地址:https://github.com/bcpierce00/unison

Unison 的核心特性

1. 双向同步机制

说到文件同步,很多人第一反应就是 rsync。确实,rsync 很强大,但它有个致命的局限——只能单向同步。想像一下,你在办公室电脑上修改了代码,回家后用家里的电脑继续工作,第二天回到办公室还得想办法把家里的修改同步回来,是不是很麻烦?

Unison 的双向同步就解决了这个痛点。它会聪明地跟踪两边的文件变化,不管是新建、删除还是修改,都能准确识别。比如你在公司创建了 main.py,回家后在同样的目录下写了 utils.py,Unison 会把两个文件都保留下来,而不是简单地用一边覆盖另一边。这种机制特别适合我这种经常在不同设备间切换工作的人。

2. 冲突检测与处理

说到冲突,这是双向同步最让人头疼的问题。想像一下,同一个文件,你在公司把函数名从 getUser 改成了 fetchUser,而家里的电脑上却把参数从 id 改成了 userId。传统的同步工具遇到这种情况就傻眼了,要么随便选一个,要么干脆报错。

Unison 的处理方式让我觉得很贴心。它会停下来告诉你:"嘿,这个文件两边都改了,你看看怎么处理?"你可以选择保留公司的版本、家里的版本,或者两个版本都留着(会自动加上后缀)。有时候我还会借此机会重新审视代码,把两边的修改手动合并一下。虽然多了个步骤,但至少不会丢失任何工作成果。

3. 高效的传输算法

作为一个经常需要同步大量代码和数据的开发者,传输效率是我特别关心的问题。Unison 在这方面做得相当不错——它只传输文件的变化部分,而不是整个文件。想像一下你要同步一个 100MB 的日志文件,只改了几行内容,Unison 只会传输这几行的差异,而不是重新传整个 100MB。

更棒的是它支持压缩传输,对于文本文件这种压缩率高的内容,传输速度能提升不少。有时候网络不稳定,传输中断了也不用担心,Unison 支持断点续传,下次同步时会从中断的地方继续。这些细节虽然不起眼,但用起来真的能省不少时间和流量。

安装 Unison

macOS 安装

1
2
3
4
5
# 使用 Homebrew
brew install unison

# 或者使用 MacPorts
sudo port install unison

Ubuntu/Debian 安装

1
2
sudo apt-get update
sudo apt-get install unison

CentOS/RHEL 安装

1
2
3
sudo yum install unison
# 或者
sudo dnf install unison

Windows 安装

  1. 下载 Windows 版本的 Unison
  2. 解压到指定目录
  3. 将目录添加到系统 PATH

Unison 基础使用方法

Unison 是实时同步吗?

先回答一个很多朋友都会问的问题:Unison 不是实时同步的。它不像 Dropbox 或 Syncthing 那样有后台进程一直监控文件变化。相反,Unison 需要你手动运行命令才会开始同步。

这其实是把双刃剑。坏处是你得记得同步,不然两边文件可能会越来越不同步。好处是你完全掌控同步的时机——比如我在编译大型项目时,就不希望中间文件被同步过去占用带宽,等编译完成后再统一同步就好了。

如果你确实需要更频繁的同步,可以:

  • 设置定时任务(cron)每隔几分钟自动同步
  • 用文件监控工具(如 inotify)检测变化后自动调用 Unison
  • 或者就跟我一样,养成习惯在切换设备前手动同步一下

基本语法

1
unison [选项] 根目录1 根目录2

本地同步示例

1
2
3
4
5
# 同步两个本地目录
unison /path/to/dir1 /path/to/dir2

# 使用图形界面
unison -ui graphic /path/to/dir1 /path/to/dir2

远程同步示例

1
2
3
4
5
# 通过 SSH 同步本地目录和远程目录
unison /local/path ssh://username@remote.host//remote/path

# 指定 SSH 端口
unison /local/path ssh://username@remote.host:2222//remote/path

实战:使用 Unison 同步本地和远程服务器文件夹

场景设定

假设我们有以下需求:

  • 本地开发目录:/Users/dev/project
  • 远程服务器目录:/home/user/project
  • 服务器地址:example.com
  • 用户名:developer

步骤 1:配置 SSH 免密登录

首先确保可以通过 SSH 免密登录远程服务器:

1
2
3
4
5
# 生成 SSH 密钥(如果还没有)
ssh-keygen -t rsa -b 4096

# 将公钥复制到远程服务器
ssh-copy-id developer@example.com

步骤 2:创建 Unison 配置文件

在主目录下创建 .unison 目录和配置文件:

1
2
mkdir -p ~/.unison
vim ~/.unison/project.prf

配置文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Unison 配置文件
root = /Users/dev/project
root = ssh://developer@example.com//home/user/project

# 忽略的文件和目录
ignore = Name {.git,.DS_Store,*.log,node_modules}

# 同步选项
auto = true
batch = true
times = true
owner = true
group = true
perms = 1023

# 压缩传输
compress = true

# 显示进度
terse = true

步骤 3:首次同步

1
2
3
4
5
# 使用配置文件进行同步
unison project

# 或者直接指定路径
unison /Users/dev/project ssh://developer@example.com//home/user/project

首次同步时,Unison 会扫描两个目录的所有文件,建立同步档案。这个过程可能需要一些时间,具体取决于文件数量和大小。

步骤 4:日常同步

配置完成后,日常同步就很简单了:

1
2
3
4
5
6
7
8
9
# 使用配置文件
unison project

# 或者创建别名简化命令
echo 'alias sync-project="unison project"' >> ~/.bashrc
source ~/.bashrc

# 然后只需执行
sync-project

步骤 5:处理冲突

当同一个文件在本地和远程都被修改时,Unison 会提示:

1
conflict: file.txt has been modified in both roots

这时你可以选择:

  • 保留本地版本
  • 保留远程版本
  • 保留两个版本(会自动重命名)
  • 手动合并

高级用法和技巧

1. 排除特定文件类型

1
unison /local/path ssh://user@host//remote/path -ignore 'Name *.tmp' -ignore 'Name .git'

2. 只同步特定文件类型

1
unison /local/path ssh://user@host//remote/path -ignore 'Name *' -include 'Name *.py' -include 'Name *.js'

3. 测试模式(不实际同步)

1
unison /local/path ssh://user@host//remote/path -testserver

4. 静默模式

1
unison /local/path ssh://user@host//remote/path -silent

5. 详细输出模式

1
unison /local/path ssh://user@host//remote/path -verbose

Unison vs 其他同步工具

Unison vs rsync

特性 Unison rsync
同步方向 双向 单向
冲突检测
文件跟踪
学习曲线 中等 简单
适用场景 开发协作 备份镜像

Unison vs Syncthing

特性 Unison Syncthing
同步方式 手动/定时 实时
配置复杂度 中等 简单
资源占用 中等
网络要求 点对点 点对点
冲突解决 手动选择 自动处理

实际应用场景

1. 本地开发与远程部署

在本地开发代码,通过 Unison 同步到远程服务器进行测试和部署。

2. 多设备文件同步

在多台开发机器之间同步项目文件,保持工作环境一致。

3. 文档协作

团队成员之间同步文档目录,支持离线编辑和冲突处理。

4. 数据备份

定期将重要数据同步到远程服务器,实现异地备份。

常见问题与解决方案

Q1: 同步时出现权限错误

解决方案:确保 SSH 用户有足够的权限访问远程目录,可以在配置文件中设置适当的权限选项。

Q2: 大文件同步速度慢

解决方案:启用压缩传输,考虑分批同步,或者使用更快的网络连接。

Q3: 频繁出现冲突

解决方案:建立良好的工作流程,避免同时在多个地方修改同一文件。

Q4: 同步档案损坏

解决方案:删除 .unison 目录中的档案文件,重新进行首次同步。

最佳实践建议

  1. 定期同步:建立定时同步的习惯,避免大量更改堆积
  2. 合理排除:使用 ignore 规则排除不需要同步的文件
  3. 备份重要数据:在进行大规模同步前,备份重要文件
  4. 测试配置:在生产环境使用前,先用测试数据验证配置
  5. 监控同步状态:定期检查同步日志,及时发现和解决问题

实时同步方案对比

不过话说回来,很多朋友看完会问:"那我要真正的实时同步怎么办?"确实,Unison 虽然强大,但手动触发的机制有时候还是不够及时。根据我这些年的使用经验,给你推荐几个真正的实时同步方案:

Syncthing - 去中心化的实时同步

这是我个人最推荐的实时同步方案。Syncthing 采用 P2P 架构,每个设备都是对等节点,文件变化会立即触发同步。最棒的是它完全免费开源,不需要中心服务器,数据直接在你的设备间传输。

我用 Syncthing 同步笔记和配置文件,体验非常流畅。比如在公司的 iMac 上修改了一个 Markdown 文件,家里的 MacBook 几乎秒级就能收到更新。而且 Syncthing 的冲突处理也很智能,很少需要手动干预。

Nextcloud - 自建私有云方案

如果你更重视数据控制权和团队协作功能,Nextcloud 是个不错的选择。它提供了完整的私有云解决方案,客户端会实时监控本地文件夹变化并立即上传。

我之前在一个小团队里用过 Nextcloud,除了文件同步,还能在线协作编辑文档、管理日程,功能很全面。不过维护成本相对较高,需要有稳定的服务器和一定的技术能力。

Resilio Sync - 基于 BT 的高速同步

对于需要同步大文件的场景,Resilio Sync(原名 BT Sync)是个利器。它基于 BitTorrent 协议,同步速度非常快,特别适合视频、设计稿这类大文件。

我有个做视频剪辑的朋友就用 Resilio Sync 同步项目文件,几个 GB 的工程文件能在团队间快速分发。不过它是闭源软件,免费版功能有限,企业使用需要考虑授权成本。

如何选择?

说了这么多,到底该怎么选?我的建议是:

  • 个人用户,追求简单免费 → Syncthing
  • 小团队,需要协作功能 → Nextcloud
  • 大文件快速同步 → Resilio Sync
  • 临时需求,不想折腾 → Dropbox 等商业方案
  • 开发场景,需要精细控制 → Unison(手动同步反而更可控)

总结

Unison 是一个功能强大的文件同步工具,特别适合需要在本地和远程环境之间保持文件同步的开发场景。相比其他工具,它的双向同步和冲突处理机制使其在协作开发中表现出色。

不过如果你追求的是真正的实时同步,Syncthing 这类工具可能更适合你的需求。选择什么工具,关键还是要看你的具体使用场景和个人偏好。

通过合理配置和使用,这些同步工具都能大大提高工作效率,减少手动复制文件的时间和错误。希望这篇教程能帮助你找到最适合自己的文件同步方案!

参考资料