Unison 2.54.0 配置参数详解
Unison 2.54.0 profile 配置详解:配置目录与加载优先级、root 三种形态、ignore 四种模式语法、batch/auto/force/prefer 方向裁决、confirmbigdel 整副本删除保护、times/owner/perms 属性同步、fastcheck/repeat/socket 参数与两份生产配置模板,参数语义与默认值出自官方手册,行为全部实测。
Unison 2.54.0 配置参数详解
目标:讲清 Unison 2.54.0 的配置文件体系(profile)与核心参数的语义、默认值与实测行为,覆盖 root/path/ignore/batch/auto/force/confirmbigdel/属性同步/repeat/socket 等日常全部配置面,并给出可直接落地的生产配置模板。全部示例已在两台 Ubuntu 22.04 服务器(node1/node2,均为 2.54.0)实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04(x86_64)
- Unison 版本:2.54.0(官方二进制
/usr/local/bin/unison,unison version 2.54.0 (ocaml 4.14.3);apt 仓库版 2.51.5 仅用于版本对照实验,见安装篇) - 拓扑:node1(本地端)↔ node2(远端端),ssh 免密互通(
ssh root@node2直接登录) - 本地演示目录:
/srv/data-a、/srv/data-b(单机两目录形态)、/srv/data(ssh 形态本地侧)、/srv/prof-a(profile 形态本地侧) - 远端演示目录:node2 的
/srv/data、/srv/prof-b - 参数语义依据:v2.54.0 官方手册(随发布件分发的
doc/unison-manual.txt,或命令行unison -doc all阅读);行为结论为本文实测 - 安装与环境准备见同专栏 《Ubuntu 22.04 安装 Unison 2.54.0 指南》
二、前置条件
- 两端已安装同一版本的 Unison 2.54.0(
unison -version两端核对一致;版本不一致的报错与解决见安装篇常见问题)。 - ssh 模式需要远端 sshd 已运行且免密已配置(
unison /srv/data ssh://node2//srv/data -testserver返回Connected即就绪)。 - 已有任意一个可写的同步目录(本文用
/srv/data-a、/srv/data-b演示单机两目录,命令不依赖 node2 也能跑通)。
三、配置文件体系与加载顺序
3.1 配置目录与 profile 文件
Unison 的一切配置都放在 .unison 目录(手册 "Running Unison" 章节:若设置了环境变量 UNISON 则以它的值为目录名,否则为当前用户家目录下的 ~/.unison/)。目录里存放四类文件:
| 文件 | 作用 | 命名规则 |
|---|---|---|
<名字>.prf | profile 配置文件,一组同步参数的集合 | unison <名字> 即加载 <名字>.prf;不带名字运行时加载 default.prf |
ar<哈希> | archive 状态文件,记录「上次同步完成态」 | 按 root 路径哈希自动生成,不要手工编辑 |
lk<哈希> | 锁文件,防两个 unison 同时操作同一对 root | 异常退出会残留,报错会给出文件名,按提示删除 |
unison.log | 默认日志文件(log=true 时) | 位置可用 logfile 改 |
profile 是纯文本,一行一个参数,# 开头是注释,name=value 与 name value 两种写法等价。下面是本文实测使用的 ~/.unison/myrepo.prf(node1 上,cat /root/.unison/myrepo.prf 实测回显):
# myrepo 双向同步 profile
root = /srv/prof-a
root = ssh://node2//srv/prof-b
path = shared
ignore = Name *.tmp
ignore = Name .DS_Store
batch = true
times = true
owner = true
group = true
perms = 0
confirmbigdel = true
log = true
logfile = /var/log/unison-myrepo.log
maxerrors = 1
逐行语义在第五章逐项展开。调用方式就是 profile 名去掉 .prf 后缀:
unison myrepo
实测回显(首行):
Unison 2.54.0 (ocaml 4.14.3): Contacting server...
Connected [//node1//srv/prof-a -> //node2//srv/prof-b]
3.2 参数加载优先级
三类来源的优先级从高到低:命令行参数 > profile 中的参数 > 内置默认值(手册 "Running Unison" 章节)。这个设计有两个实用推论:
- profile 里可以写「日常默认」,临时需求用命令行覆盖。例如 profile 没写
batch,临时无人值守跑一次:
unison myrepo -batch
- 反过来,profile 里写了
batch = true而本次想人工审查冲突,命令行无法把布尔值改回 false(-batch是开关型参数),此时应维护一个不带batch的 profile,或用unison myrepo与unison mydata两份 profile 区分自动/人工场景。
⚠️ 注意:布尔参数的 profile 写法是
name = true/name = false;命令行写法是短横线开关-batch/-terse。testserver这类调试参数手册明确 "Should not be set in preference files"——只出现在命令行。
3.3 首跑自动生成的 default.prf
不带参数首次运行 unison 时,Unison 自动创建配置目录与默认 profile。实测(node1 首跑后 cat /root/.unison/default.prf):
# Unison preferences file
只有一个注释头,无任何参数——即所有参数都走内置默认值。日常建议不用 default.prf,而是按同步对建独立命名的 profile(如 mydata.prf、website.prf),避免多对同步互相污染。
四、参数总览
按用途分组的常用参数速查(默认值均出自官方手册,行为列含本文实测结论):
| 分组 | 参数 | 默认值 | 作用一句话 |
|---|---|---|---|
| 副本定义 | root | 无(必须恰好两个) | 定义一对副本,支持本地/ssh/socket 三种形态 |
| 路径选择 | path | 无(同步全部) | 只同步指定子路径,可重复多条 |
| 路径选择 | ignore/ignorenot | 无 | 排除/兜回匹配的路径,四种模式语法 |
| 路径选择 | follow | 无(符号链接不跟踪) | 跟踪指定的符号链接为普通文件/目录 |
| 运行方式 | batch | false | 不问任何问题:非冲突自动传播,冲突跳过 |
| 运行方式 | auto | false | 非冲突自动接受,冲突仍逐项问 |
| 方向裁决 | force | 无 | 全部差异按指定 root 方向裁决(镜像化) |
| 方向裁决 | prefer | 无 | 仅对冲突按指定 root 方向裁决 |
| 安全保护 | confirmbigdel | true | 整副本被删时额外确认(batch 下直接中止) |
| 属性同步 | times | false | 同步文件修改时间(不含目录) |
| 属性同步 | owner/group | false | 同步属主/属组(需 root 权限或同 uid 用户) |
| 属性同步 | perms | 0o1777 | 同步的权限位掩码(默认不含 set-uid/set-gid) |
| 属性同步 | xattrs/acl | false | 同步扩展属性/ACL(2.53.0 起支持) |
| 更新检测 | fastcheck | default(Unix 实际按 true) | 用 mtime+大小做快速变更检测 |
| 远端连接 | sshcmd | ssh | 指定 ssh 可执行文件路径 |
| 远端连接 | sshargs | 无 | 附加给 ssh 的参数(如 -p 2222 走 -sshargs) |
| 远端连接 | socket | 无 | 以 socket 服务端常驻(TCP 端口或 Unix domain socket) |
| 定时循环 | repeat | 无(跑一次即退) | N(每 N 秒)/watch(实时)/watch+3600(组合) |
| 日志输出 | log | true | 记录同步变更到日志 |
| 日志输出 | logfile | ~/.unison/unison.log | 日志文件位置,支持 SIGUSR1 轮转 |
| 日志输出 | silent/terse | false | 完全静默/只压掉状态消息 |
| 传输控制 | maxthreads | 0(等价 20 或 1000) | 传输并发线程数 |
| 传输控制 | maxerrors | 1 | 传输阶段容忍错误数,超出即中止 |
| 传输控制 | retry | 0 | 失败路径重试次数 |
| 备份 | backups/maxbackups | false/2 | 覆盖或删除前留备份副本 |
💡 说明:表里「方向裁决」三兄弟容易混——
force是连非冲突变更一起按指定方向摆平(等于把同步器降级成镜像器,手册原话 "effectively changes Unison from a synchronizer into a mirroring utility");prefer只影响冲突项的方向;两者都支持newer/older特殊值(按修改时间裁决,需times=true)。拿不准时优先prefer,force手册原文警告 "should be used only if you are sure you know what you are doing!"。
五、核心参数分类详解
5.1 root:副本定义与三种书写形态
root 决定「同步谁」。必须恰好两个(手册原文 "Exactly two roots are needed"),顺序无关——Unison 会对两个 root 做规范化排序(因此日志里显示的左右顺序可能与书写顺序相反)。三种书写形态(本文均实测):
# 形态一:本地目录(单机两目录)
root = /srv/data-a
root = /srv/data-b
# 形态二:ssh 远端(默认 22 端口;显式端口与用户的完整写法)
root = /srv/data
root = ssh://root@node2:22//srv/data
# 形态三:socket 远端(对端常驻 unison -socket 8143,见命令篇)
root = /srv/data
root = socket://node2:8143//srv/data
关键细节:远端绝对路径写在双斜杠之后(ssh://node2//srv/data,// 后即是绝对路径);若只写单斜杠(ssh://node2/srv/data)则是相对远端家目录的路径。端口的写法是 host:port 后跟 //路径(实测 ssh://root@node2:22//srv/data 的 -testserver 返回 Connected [//node1//srv/data -> //node2//srv/data])。
5.2 path:只同步子路径
不写 path 时同步 root 下全部内容;写了则只同步该子路径,且可以重复多条(多个 path = ... 即多路径白名单)。实测(node1,两目录下已有 sub1/、sub2-fake.txt 等文件,只同步 sub1):
unison /srv/data-a /srv/data-b -batch -path sub1
实测回显(节选):
Reconciling changes
new file ----> sub1/f1.txt
data-a : new file modified on 2026-11-01 at 7:15:46 size 9 rw-r--r--
data-b : absent
1 items will be synced, 0 skipped
验证只有子路径被同步(sub2-fake.txt 未出现在对侧):
ls /srv/data-b/sub1/ && ls /srv/data-b/sub2-fake.txt 2>/dev/null || echo "sub2-fake.txt 未同步 => -path 生效"
f1.txt
sub2-fake.txt 未同步 => -path 生效
💡 说明:archive 状态文件按 root 对生成、与 path 无关——同一对 root 用不同
path多次同步,状态都在同一份 archive 里,不存在「每个 path 一份 archive」的问题。
5.3 ignore / ignorenot:忽略规则与四种模式语法
ignore 让 Unison 完全无视匹配的路径(含其子孙),ignorenot 则从 ignore 规则里把匹配的路径「捞回来」(常用于「先排除一大类、再放行个别」)。四种模式语法(出自手册 Path Specification 章节):
| 模式 | 匹配语义 | 示例 |
|---|---|---|
Name | 路径最后一段匹配(glob 通配) | ignore = Name *.tmp(所有 .tmp 文件);ignore = Name {CVS,*.cmo}(大括号多选一) |
Path | 精确路径匹配(glob 通配,不以 . 开头规则不生效) | ignore = Path a/b;ignore = Path */tmp(能匹配到 .foo/tmp) |
BelowPath | 该路径自身及其整棵子树 | ignore = BelowPath cache(推荐用于「目录及其全部内容」) |
Regex | POSIX 扩展正则,锚定全路径(必须匹配整条路径,不是子串) | ignore = Regex a/b/.*\.ml |
glob 语法细则(手册原文归纳):* 匹配不含 / 的任意串(且位于段首时不匹配 . 开头的名字);? 单字符;[xyz] 字符集;{a,bb,ccc} 多选一(大括号逗号后不能有空格,空格会被当作字面量)。路径分隔符一律写 /(Windows 侧也一样,保证 profile 跨平台通用)。
实测(node1,造一个 .tmp 与一个普通文件,命令行加 ignore):
echo tmp > /srv/data-a/junk.tmp && echo keep > /srv/data-a/keep.txt
unison /srv/data-a /srv/data-b -batch -ignore 'Name *.tmp'
实测回显(节选——只有 keep.txt 进了同步清单):
Reconciling changes
new file ----> keep.txt
data-a : new file modified on 2026-11-01 at 7:08:19 size 5 rw-r--r--
data-b : absent
1 items will be synced, 0 skipped
ls /srv/data-b/
app.conf keep.txt notes.md readme.txt sub1 watch.txt
junk.tmp 未被同步,忽略生效。两个组合要点:
- ignore 目录则子孙全忽略(手册原文 "If a directory is ignored, all its descendants will be too")——忽略目录用
BelowPath最稳。 - 交互界面里按
I(ignore this path permanently)/E(按扩展名忽略)/N(按文件名后缀忽略)可以直接把当前项写入 profile 的 ignore 规则,不用手写模式串。
5.4 batch / auto:非交互的两个等级
两参数解决「cron 里跑 / 半自动跑」的问题,语义差异用一次实测看清。先造三份数据:一个非冲突新文件(A 侧 auto-a.txt)、一个非冲突新文件(B 侧 auto-b.txt)、一个冲突文件(两侧同改 conf.txt):
echo A1 > /srv/data-a/auto-a.txt
echo B1 > /srv/data-b/auto-b.txt
echo A-side > /srv/data-a/conf.txt
echo B-side > /srv/data-b/conf.txt
unison /srv/data-a /srv/data-b -auto
实测回显(节选;非冲突项被自动跳过不问,只剩冲突项等待人工):
data-a data-b
new file <-?-> new file conf.txt []
No default command [type '?' or F1 for help]
-auto 的语义:非冲突变更自动按推荐方向传播(auto-a.txt、auto-b.txt 直接互传),冲突项停在人机交互(<-?-> 且括号内无默认值,必须人工给方向)。而 -batch 更进一步——冲突也不问、直接跳过(手册原文 "Non-conflicting changes will be propagated; conflicts will be skipped")。前文冲突实测中 -batch 的输出:
changed <-?-> changed readme.txt
0 items will be synced, 1 skipped
...
Synchronization complete at 07:05:10 (0 items transferred, 1 skipped, 0 failed)
冲突文件两侧原样保留(数据无损),退出码 0。cron 场景务必 -batch:-auto 在冲突处会等输入,把 cron 任务挂死。
5.5 force / prefer / newer:冲突与方向裁决
这三个参数把「人工决策」换成「自动规则」。实测 force(冲突场景,指定以 /srv/data-a 为准):
echo 'edit from A' > /srv/data-a/readme.txt
echo 'edit from B' > /srv/data-b/readme.txt
unison /srv/data-a /srv/data-b -batch -force /srv/data-a
实测回显(节选;注意方向箭头从冲突的 <-?-> 变成了单向 ====>):
Reconciling changes
changed ====> changed readme.txt
data-a : changed file modified on 2026-11-01 at 7:05:10 size 12 rw-r--r--
data-b : changed file modified on 2026-11-01 at 7:05:10 size 12 rw-r--r--
1 items will be synced, 0 skipped
cat /srv/data-b/readme.txt
edit from A
B 侧被 A 侧内容覆盖——force 连「非冲突变更」也一并按指定 root 方向裁决,等价于镜像。三个参数的使用建议:
force <root>:明确要「单向镜像」时用(如发布场景 A→B),双向备份场景禁用。prefer <root>:只裁决冲突项方向,非冲突变更仍按各自方向互传——「以某侧为准解决冲突」的正确姿势。prefer newer/force newer:按修改时间取较新者(必须同时times = true,否则 Unison 不掌握可比对的 mtime;两端 mtime 相同时该参数失效,冲突照旧)。
5.6 confirmbigdel:整副本删除保护
默认 true(手册明确 "When this is set to true, Unison will request an extra confirmation if it appears that the entire replica has been deleted")。触发条件是「一侧的整个副本被删空」,此时若同时处于 batch 模式则直接中止同步。实测(node1 上把 profile 场景的 shared 目录整体删除后运行 unison myrepo,profile 内 batch = true):
rm -rf /srv/prof-a/shared
unison myrepo
实测回显(全文):
Reconciling changes
The following paths have been completely emptied in one replica:
'shared'
Unison may delete everything below these paths in the other replica.
(Set the 'confirmbigdel' preference to false to disable this check.)
Aborting...
对侧(node2)的数据原封不动,同步被拒绝——这正是该参数的价值:rm 手滑后 cron 自动同步不会把误删放大成两边的丢失。恢复方式就是把数据补回任一侧(或从备份恢复)后重跑。反过来说,确认要「删空并镜像删除」时,需显式 confirmbigdel = false(写进 profile)或交互模式下人工确认。
5.7 属性同步:times / owner / group / perms
四个属性参数决定了「同步的到底是文件内容的全部还是只是一部分」。实测 profile(见 3.1 的 myrepo.prf)中开启了 times/owner/group 并把 perms = 0(不同步权限位)。同步完成后在远端核对属性(node2 上 ls -l /srv/prof-b/shared/):
total 4
drwxr-xr-x 2 root root 4096 Nov 1 07:08 docs
参数语义与默认值(手册):
| 参数 | 默认 | 语义与实测要点 |
|---|---|---|
times | false | 同步文件修改时间(目录时间不同步)。用 prefer newer/force newer 的前提。两端时钟要准(NTP) |
owner/group | false | 同步 uid/gid。非 root 用户只能设置自己拥有的文件;两端 uid 语义需一致(都是本机账户体系) |
perms | 0o1777 | 同步的权限位掩码:默认同步除 set-uid/set-gid 外的位(安全考虑);perms = 0 关闭权限位同步 |
numericids | false | true 时按数字 uid/gid 而非名字匹配(两端账户名不同但 uid 相同时开启) |
xattrs/acl | false | 扩展属性/ACL 同步(2.53.0 起),配套 xattrignore 系列过滤 |
⚠️ 注意:
owner/group的一个实测细节——本例perms = 0时,对端展示的属性行会标注unknown permissions(权限位不比对),属正常现象,不是错误。
5.8 更新检测:fastcheck
fastcheck 决定每次同步「怎么判断文件变没变」(手册 "Fast Update Detection" 章节):
true:用 mtime + 文件大小当「伪 inode 号」比对 archive,不读文件内容——扫描近乎零开销。这是 Unix 上的实际默认(内置默认值default在 Unix 等价 true;yes/no/default是true/false/auto的向后兼容别名)。false:重算每个文件的内容指纹——慢,但能兜住「改了内容却不动 mtime」的异常程序。
手册同时写明两个细节:首次同步永远全量扫描(与 fastcheck 无关);对 .xls/.mpp 扩展名文件 fastcheck 自动关闭(防止 Excel 类程序改内容不改 mtime 造成漏检)。
选择建议:日常保持默认;只有怀疑「文件被改但 Unison 没发现」时,手动跑一次 unison myrepo -fastcheck false 做全量核对。
5.9 远端连接:sshcmd / sshargs 与 socket 模式
ssh 侧参数(profile 写法):
sshcmd = /usr/bin/ssh # ssh 可执行文件路径(默认 ssh)
sshargs = -p 2222 # 附加给 ssh 的参数(远端 sshd 非 22 端口时)
sshargs = -C # 也可叠加压缩等选项
sshargs 是把任意 ssh 参数透传给底层 ssh 的通道;sshcmd 用于 ssh 不是标准路径、或想换成特定 ssh 实现的场景。端口还有一个更直接的位置——写在 root URI 里(ssh://root@node2:2222//srv/data),两种写法选一即可。
socket 模式:profile 中无 socket 专属参数,socket 参数本身是「让 Unison 变成服务端」的命令行参数(手册原文 "Start unison as a server listening on a TCP socket (with TCP port number as argument) or a local socket (aka Unix domain socket)"):
unison -socket 8143 # 服务端:监听 TCP 8143
root = socket://node2:8143//srv/data # 客户端 root 写法
实测(node2 服务端监听 + node1 客户端同步,均通过,回显见命令篇 4.8 节)。socket 协议是明文的,仅限可信内网;跨公网一律走 ssh 形态。
5.10 定时循环:repeat
repeat 让命令行式同步变成前台常驻循环(手册明确三种取值),全部实测通过:
| 写法 | 语义 | 实测结论 |
|---|---|---|
repeat = 5 | 每轮结束后等 5 秒再来一轮 | 实测 12 秒内跑了 4 轮检测,中途写入的文件在第 2 轮被捕获传播 |
repeat = watch | 基于 inotify 的实时触发(Linux 依赖 unison-fsmonitor) | 实测写入文件后秒级触发同步 |
repeat = watch+3600 | 实时触发 + 每小时做一次全量兜底扫描 | 手册推荐的稳妥组合(防 inotify 漏事件) |
profile 写法 repeat = watch+3600,命令行写法 -repeat 5。实测命令形态:
unison /srv/data-a /srv/data-b -batch -repeat 5
实测日志节选(四轮循环):
Looking for changes
Looking for changes
Synchronization complete at 07:07:20 (1 item transferred, 0 skipped, 0 failed)
Looking for changes
⚠️ 注意:
repeat是前台循环——进程退出循环即停。长期无人值守要么配合 tmux/nohup 跑repeat,要么交给 cron/systemd timer 周期调用(见安装篇「配置说明」的两种托管形态)。
5.11 日志与输出:log / logfile / silent / terse
log(默认 true):把每条变更写入日志。实测logfile = /var/log/unison-myrepo.log的日志尾部(tail -4 /var/log/unison-myrepo.log):
[BGN] Copying shared from /srv/prof-a to //node2//srv/prof-b
[END] Copying shared
Unison 2.54.0 (ocaml 4.14.3) finished propagating changes at 07:08:31.93 on 01 Nov 2026, 0.003 s
Synchronization complete at 07:08:31 (1 item transferred, 0 skipped, 0 failed)
logfile:日志位置,默认~/.unison/unison.log;向进程发SIGUSR1会关闭并重开日志文件(手册说明该机制即日志轮转钩子)。terse = true:压掉状态消息(进度、Contacting server 等),保留变更清单与结果。实测输出从完整形态缩到三行变更清单 + 传播行。silent = true:除错误外什么都不打印(手册:设置 silent 会自动置 batch=true)。cron 任务里最安静的选择。
5.12 传输并发与容错:maxthreads / maxerrors / retry
| 参数 | 默认 | 语义 |
|---|---|---|
maxthreads | 0(特殊值:无流式传输时 20 线程,有流式时 1000) | 传输阶段并发度;低带宽链路建议调小(如 1),避免吃满带宽 |
maxerrors | 1 | 传输阶段容忍的错误数,超出即中止整轮;调大可让「个别坏文件不拖死整目录同步」,但手册提醒磁盘满这类持续性故障会拖很久才中止 |
retry | 0 | 同步失败的路径自动重试 N 次 |
六、生产配置模板
6.1 模板一:工作区双向同步(16GB 内存、SSD、个人工作目录)
场景:笔记本 ↔ 办公服务器,两目录双向,属性全同步,定时跑,安全网全开。
# ~/.unison/workspace.prf —— 工作区双向同步
root = /home/admin/workspace
root = ssh://admin@office.example.com//home/admin/workspace
times = true # 时间戳同步(冲突按新旧裁决的前提)
owner = true # 属主同步(两端为同一用户时)
group = true
perms = 0o1777 # 默认掩码,显式写出便于复查
ignore = Name {.git,*.swp,*.swo,*~} # VCS 元数据与编辑器临时文件
ignore = Name .DS_Store # macOS 桌面残留
auto = true # 交互跑时非冲突项自动过,冲突仍问
confirmbigdel = true # 整副本删除保护(默认开,显式写出)
fastcheck = default # Unix 实际按 true;怀疑漏检时命令行 -fastcheck false 核对
log = true
logfile = /var/log/unison-workspace.log
maxerrors = 3 # 容忍个别文件失败,不拖死整轮
配套调用:交互审查用 unison workspace;cron 用 unison workspace -batch -silent(自动 + 静默,冲突留到下次人工处理,日志可查)。
6.2 模板二:网站目录镜像发布(8GB 内存、NVMe、发布机 → 生产机单向)
场景:以发布机为权威单向镜像到生产机,冲突不可能(只有发布机改)。
# ~/.unison/websitedeploy.prf —— 单向镜像发布
root = /var/www/site
root = ssh://deploy@prod.example.com//var/www/site
force = /var/www/site # 全部差异按发布机方向裁决(镜像语义)
times = true
perms = 0o1777
owner = true # 生产机需 root 或同 uid 的 deploy 账户
group = true
ignore = BelowPath cache # 运行时缓存目录整棵不同步
ignore = Name *.log
batch = true
confirmbigdel = true # 发布机误删整目录时,生产端拒绝跟随删除
repeat = watch+3600 # 实时触发 + 每小时全量兜底
maxthreads = 20
log = true
logfile = /var/log/unison-deploy.log
⚠️ 注意:模板二的
force使 Unison 退化为镜像器(手册原话),这正是发布场景想要的;但它同时意味着生产机上的任何手工改动都会被发布机覆盖——生产机上应当只读。若生产机存在合法的本地变更,改用prefer并保留人工冲突处理。
6.3 模板选型要点
两份模板的关键差异就三处:auto/batch(是否无人值守)、force(是否镜像化)、repeat(是否常驻循环)。同步方向明确选模板二,双向协同选模板一;两份模板都以 confirmbigdel = true 兜底,这是 profile 里最便宜也最值钱的一行。
七、常见问题
Q1:ignore 写了却不生效?
先确认匹配的是「路径形态」而不是「文件名本身」:ignore = Name *.tmp 只匹配路径最后一段(文件/目录名),若想匹配子目录下的特定路径要用 Path a/b 或 BelowPath。再确认没有用 Name 匹配点开头文件的段首场景(Name .* 匹配不到 .git 这类隐藏名——Name 模式段首 * 不匹配 . 开头,写 ignore = Name .git 字面量或 ignore = BelowPath .git 即可)。最后用交互界面按 l(list all changes)核对哪些路径被排除。
Q2:profile 里写了 batch = true,想临时人工审查冲突怎么办?
布尔开关型参数无法在命令行「反向关闭」(-batch 只能打开)。两个办法:临时跑 unison root1 root2(不带 profile 的直连形态);或维护两份 profile(如 myrepo 自动、myrepo-review 不带 batch),按场景选用。
Q3:两份 profile 同步同一对 root 会冲突吗?
archive 按 root 对(规范化路径哈希)生成,与 profile 名无关——两份 profile 指向同一对 root 时共享同一份 archive,只要参数(尤其 ignore)一致就没问题;参数不一致时会出现「A profile 忽略的文件 B profile 又想同步」的抖动,规范做法是一对 root 一份 profile。
Q4:repeat watch 在低版本 Unison 上报找不到 fsmonitor?
-repeat watch 依赖 unison-fsmonitor 辅助程序,官方二进制包自带(bin/unison-fsmonitor),需与主程序放在同一 PATH 可见目录(如都装到 /usr/local/bin);apt 装的 2.51.5 不附带该程序(发行版打包为独立包或无),这也是推荐官方二进制的理由之一。
Q5:times = true 后两端文件时间还是不一致?
times 只同步文件的时间(手册原文 "file modification times (but not directory modtimes) are propagated"),目录时间不同步是设计行为。另外若同步方向是「较新覆盖较旧」,mtime 本身就是裁决依据,同步完成后两侧应一致;个别不一致的文件可在下次同步中被 prefer newer 收敛。
八、参考链接
- Unison v2.54.0 官方手册(随发布件
doc/unison-manual.txt/.pdf,或unison -doc all在线阅读)——本文参数语义与默认值的权威出处 - 官方手册 "Path Specification" / "Ignoring Paths" 章节——ignore 四种模式语法与示例
- GitHub 仓库:https://github.com/bcpierce00/unison (v2.54.0,查询日期 2026-11-01)
- 同专栏前置阅读:《Ubuntu 22.04 安装 Unison 2.54.0 指南》(安装与 ssh 免密)