Fossil SCM 2.28 常用 CLI 命令详解
Fossil SCM 2.28 CLI 全谱实测:按建库/提交/同步/查询/维护分段跑通 init、new、clone、open、close、add、rm、mv、commit、changes、status、timeline、branch、tag、pull、push、sync、merge、bisect、settings/set/unset、configuration、user add/capabilities、wiki/technote、ticket、artifact/zip、rebuild/repack/backup/scrub/clean、server/ui/serve,含双机分叉冲突实测与 10 项真实坑位(2026-10-27)。
Fossil 与 Git 最大的使用差异在于:它把版本库、Web 界面与工单系统全部编进一个可执行文件,所有操作都从 fossil 子命令进入。本文按"建库 → 提交 → 同步 → 查询 → 维护"的顺序,把 2.28 版本真正会用到、也最容易踩坑的命令族逐条跑一遍,所有回显均来自 Ubuntu 22.04 上的实测(fossil version 2.28 [52445a27f1] 2026-03-11),示例账号 root / q1w2e3r4。概念与安装篇请先看《Fossil SCM 2.28 介绍与选型指南》与《Ubuntu 22.04 安装 Fossil SCM 2.28 指南》,配置项细节见《Fossil SCM 2.28 配置参数详解》,本篇不重复展开。
一、CLI 全景:先学会用 help 找命令
fossil help -a 一次性列出内置的全部 114 个命令名(输出为多列,wc 统计的是去重后的词数):
$ fossil help -a | tr -s ' ' '\n' | grep -c "[a-z]"
114
$ fossil help -a | head -12
3-way-merge clone help rebuild status
add close hook reconstruct sync
addremove commit http redo system
alerts configuration import remote tag
all dbstat info remote-url tarball
amend deconstruct init rename ticket
annotate delete interwiki repack timeline
artifact descendants leaves reparent tls-config
attachment describe login-group revert touch
backoffice detach ls rm tree
backup diff md5sum rss ui
bisect export merge scrub undo
help 本身有 5 种检索入口,比逐个点命令快得多:
$ fossil help help
Usage: fossil help TOPIC
Things to try:
fossil help help
fossil help -o # 全局选项
fossil help -a # 全部命令
fossil help -s # 全部设置项(等价于 settings 的文档)
fossil search -h TOPIC # 全文检索帮助文本
日常排查最常用的是 fossil help <子命令>,例如 fossil help mv、fossil help user、fossil help ticket,每个子命令的选项和边界条件都在里面写死,比翻网站快。注意 2.28 不接受 fossil server -h 这种写法,一律走 fossil help server。
二、仓库生命周期:init / new / clone / open / close
2.1 init:建一个空库
$ fossil init server.fossil
project-id: 18b4888788e778c67bee0cc937f1a290fd354ce3
server-id: b0e7ffd41196a9437d7cd2873cf6291bddba5f73
admin-user: root (initial remote-access password is "9ykuYGDc2F")
$ ls -l server.fossil
-rw-r--r-- 1 root root 217088 Oct 27 12:53 server.fossil
三行输出分别是项目 ID、服务端 ID 和随机生成的管理员初始 Web 密码。这个密码只在建库时出现一次,没记下来就要用 fossil user password root <新密码> 重置;初始库固定 217KB 左右(含默认工单/Wiki 模板与匿名用户记录)。
2.2 new:等价于 init,但不自动打开
$ fossil new single.fossil
project-id: f8a005162143e46b165fdabb5ecd9fa279b047af
server-id: 8b0eb3b8fd78731b366abe6b117c99ee2f87aa73
admin-user: root (initial remote-access password is "Y8HxDLGCsa")
$ ls -a
. .. single.fossil
只多出 single.fossil 一个文件,目录里没有检出标记。所以 new 并不能省掉 open,很多教程写成 "new 之后直接提交" 会导致 current directory is not within an open check-out。
2.3 clone + open:从已有库取一份工作副本
$ fossil clone server.fossil w1.fossil
Repository cloned into w1.fossil
Rebuilding repository meta-data...
0.0% complete... 100.0% complete...
Extra delta compression... none found
Vacuuming the database...
$ mkdir w1 && cd w1 && fossil open ../w1.fossil
project-name: <unnamed>
repository: /root/d1/w1.fossil
local-root: /root/d1/w1/
config-db: /root/.fossil
project-code: 023d17860944af3f81f63e741a503e4e2f283155
checkout: c3e489c5d3671a8806ce0aee99d6ec4b65418d19 2026-10-27 12:53:31 UTC
tags: trunk
comment: initial empty check-in (user: root)
check-ins: 1
两个细节:clone 只产生库文件,open 才在当前目录建检出(生成 .fslckout 或 _FOSSIL_);open 输出里的 Web 密码是克隆时重新随机生成的,与原库管理员密码不同,按需统一即可。
2.4 close:摘掉检出,不删库
$ fossil close
current directory is not within an open check-out
上面是在只有库文件、没有检出的目录执行的,属于误用回显。正确用法是在检出目录里执行 fossil close,它会删除 .fslckout 标记并解除绑定,库文件与本地修改原样保留;想彻底删掉工作副本直接 rm -rf 目录即可,Fossil 不依赖额外的 .git 式元数据目录。
三、日常提交:add / rm / mv / commit / changes / status
3.1 add 与 changes
$ printf 'line one\nline two\n' > README.md
$ mkdir src && printf 'void util(void){}\n' > src/util.c
$ fossil add README.md src/util.c
ADDED README.md
ADDED src/util.c
$ fossil changes
ADDED README.md
ADDED src/util.c
fossil add 会立即回显每个被加入的文件,changes 则汇总当前检出中相对于父版本的全部变更,前缀 ADDED / EDITED / DELETED / MISSING / RENAMED 一眼能看出状态。Fossil 不做暂存区,add 只是把文件纳入版本控制,真正成批入库靠 commit。
3.2 commit
$ fossil commit -m "初始提交"
Pull from file:///root/d2/server.fossil
Round-trips: 1 Artifacts sent: 0 received: 0
Pull done, wire bytes sent: 363 received: 348 remote:
New_Version: bc34f15b9743da527d2abe8435a3581b673af90059fe4993d9634b394d100947
Sync with file:///root/d2/server.fossil
Round-trips: 1 Artifacts sent: 3 received: 0
Sync done, wire bytes sent: 667 received: 302 remote:
只要克隆时记录了远端,commit 会先自动 pull 再自动 push(即 autosync 的默认行为),一次命令完成"提交+同步"。离线场景用 fossil commit --no-sync -m "..." 只落本地库,等网络恢复再手工 push。New_Version 后面就是新检入点的 artifact 哈希,后续 artifact、bisect、merge 都会用到它。
3.3 status 与 timeline
$ fossil status
repository: /root/d3/single.fossil
local-root: /root/d3/
config-db: /root/.fossil
checkout: 950c0043a146e42b2fe371720c3f63c39b71f9a2 2026-10-27 12:56:03 UTC
parent: 9871978d3f22c442174f6ba0ffb11dff87f2694f 2026-10-27 12:56:03 UTC
tags: trunk
comment: rename a->b (user: root)
工作区干净时 status 只打印检出元信息;有改动时会把 EDITED/MISSING 等清单接在后面。timeline 是查看历史的入口:
$ fossil timeline -n 5 -t ci
=== 2026-10-27 ===
12:55:03 [8b0f8c58f6] feature-login:README 追加 login 行 (user: root tags: feature-login)
12:55:03 [d8b569fb8a] Create new branch named "feature-login" (user: root tags: feature-login)
12:55:02 [bc34f15b97] *CURRENT* 初始提交 (user: root tags: trunk, v0.0)
12:55:02 [99de79671b] initial empty check-in (user: root tags: trunk)
+++ no more data (4) +++
-t ci 只过滤检入事件(不带则混入 Wiki/工单/标签修改),*CURRENT* 标记当前检出所在版本,*BRANCH* 标记分支起点。
3.4 mv:默认不落盘,这是最常见的坑
$ fossil help mv | sed -n '6,8p'
The 'mv' command does NOT normally rename or move the files on disk.
This command merely records the fact that file names have changed so
that appropriate notations can be made at the next commit.
$ fossil mv src/util.c src/helper.c
RENAME src/util.c src/helper.c
$ ls src/
util.c
$ fossil commit -m "重命名 util.c"
no such file: /root/d2/w1/src/helper.c
fossil mv 只登记改名,磁盘上仍是 util.c,紧接着 commit 会因找不到新路径而中止(退出码非 0,改动保留)。两种解法:加 --hard 让磁盘一起改名,或先设 fossil set mv-rm-files 1 改变默认行为。
$ fossil mv --hard a.txt b.txt
RENAME a.txt b.txt
MOVED_FILE /root/d3/a.txt
$ ls
b.txt single.fossil
$ fossil commit -m "rename a->b"
New_Version: 950c0043a146e42b2fe371720c3f63c39b71f9a226c9b559d7775161ac9efe76
3.5 rm:只标记删除,磁盘文件由 --hard 决定
$ fossil rm notes.txt
DELETED notes.txt
$ fossil changes
DELETED notes.txt
与 mv 同源,fossil rm 默认仅登记删除,下次 update 时才从工作区移除;要立刻删文件加 --hard。
四、分支与标签:branch / tag / tag cancel
4.1 建分支:参数是位置式,没有 -from
$ fossil branch new feature-login trunk
New branch: d8b569fb8a2e8b9265b7a06786b9dd9091bc9b4edb91dc55d3711251c095befc
$ fossil branch list
feature-login
* trunk
如果照 Git 习惯写 fossil branch new feature-login -from trunk,会直接报 unrecognized command-line option or missing argument: -from,第二个位置参数才是基线。建完分支只是产生一个指向基线的空提交,不会自动切换。
4.2 切换分支用 update,不是 checkout
$ fossil update feature-login
Pull from file:///root/d2/server.fossil
WARNING: 1 merge conflicts
WARNING: 1 unmanaged files were overwritten
CONFLICT src/helper.c - edited locally but deleted by update
ADD src/util.c - overwrites an unmanaged file, original copy backed up locally
-------------------------------------------------------------------------------
updated-from: bc34f15b9743da527d2abe8435a3581b673af900 2026-10-27 12:55:02 UTC
updated-to: d8b569fb8a2e8b9265b7a06786b9dd9091bc9b4e 2026-10-27 12:55:03 UTC
tags: feature-login
comment: Create new branch named "feature-login" (user: root)
changes: 2 files modified.
update 会带着未提交的本地改动切换版本,并在遇到未托管文件被覆盖时自动留一份 -original 备份(上文 src/util.c 就是上一节 mv 坑留下的残留文件被覆盖),这类 CONFLICT 需要人工确认后 fossil commit 或 fossil undo。
4.3 标签:add / cancel
$ fossil tag add v0.1 trunk
$ fossil tag list
feature-login
trunk
v0.0
v0.1
$ fossil tag cancel v0.1 trunk
$ fossil tag list
feature-login
trunk
v0.0
Fossil 标签是"附着在某个检入点上的可编辑签",打标签本身会生成一条 Edit 事件(timeline 中可见 Edit [accc13b06acdf888|accc13b06a]: Add tag "v0.1"),因此取消后历史记录仍在,只是当前不可见。
五、双机同步:clone / pull / push / sync、分叉与合并
5.1 两台机器的最小同步闭环
在机器 A 建库并提交,机器 B 克隆后修改,双方各自 push/pull:
# 机器 A
$ fossil push
Push to file:///root/d2/server.fossil
Round-trips: 2 Artifacts sent: 1 received: 0
Push done, wire bytes sent: 1122 received: 653 remote:
# 机器 B(克隆自同一库)
$ fossil clone ../server.fossil w2.fossil
Repository cloned into w2.fossil
$ fossil open w2.fossil
$ printf 'line one CHANGED-BY-W2\nline two\n' > README.md
$ fossil commit -m "w2:修改 README 第一行"
New_Version: ...
$ fossil push
Push to file:///root/d2/server.fossil
Round-trips: 1 Artifacts sent: 0 received: 0
Push done, wire bytes sent: 785 received: 302 remote:
sync 等价于 pull + push,不确定该用哪个时直接 fossil sync;fossil remote 查看当前远端 URL,fossil remote off 可临时断开。若只想拿一份不可推送的只读副本,用 fossil clone --once server.fossil ro.fossil,克隆时就不写入远端配置,后续 push 会因没有 remote 而失败——适合做一次性归档。
5.2 分叉(fork):pull 会先警告
两台机器都基于同一父提交改同一行,后 push 的一方先把对方的提交拉下来时:
$ fossil pull
Would fork. "update" first or use --branch or --allow-fork.
Round-trips: 2 Artifacts sent: 0 received: 4
Pull done, wire bytes sent: 853 received: 1814 remote:
Fossil 明确拒绝把分叉直接套到当前检出,必须先 fossil update 到某个叶子,或加 --allow-fork 强制。确认库内已经出现两个叶子后,fossil timeline 会同时显示两个 *CURRENT*/*BRANCH* 之外的叶子版本。
5.3 合并与冲突标记
在其中一个叶子上执行无参 fossil merge:
$ fossil merge
Pull from file:///root/d2/server.fossil
no unmerged forks of branch "trunk"
这次回显是"已经没有未合并分叉",因为上一步 pull 已经把对方提交合并进工作区并留下了冲突标记。真正的合并结果体现在工作区文件里:
$ cat README.md
<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<< (line 1)
line one CHANGED-BY-W2
####### SUGGESTED CONFLICT RESOLUTION follows ###################
line one MERGED
||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||| (line 1)
line one
======= MERGED IN content follows =============================== (line 1)
line one MERGED
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
line two
Fossil 的冲突块比 Git 多两段:SUGGESTED CONFLICT RESOLUTION 给出按行合并的建议结果,COMMON ANCESTOR 给出共同祖先原文,人工只需在"本地/建议/祖先/对方"四段里选一段留下。解决后:
$ printf 'line one MERGED\nline two\n' > README.md
$ fossil commit -m "合并 w1/w2 分叉,解决 README 冲突"
New_Version: 5019551e31e27de2bb2217055a414bb9f53ec1580dc815ba50248da7c62665dd
$ fossil push
合并提交会同时有两个父版本(fossil info 的 parent: 只显示第一父),另一台机器 fossil pull && fossil update trunk 即可拿到结果,实测输出 UPDATE README.md 后内容为 line one MERGED。
5.4 bisect:定位引入问题的检入点
$ fossil bisect good v0.0
$ fossil bisect bad
$ fossil bisect status
span: 2 steps-remaining: 1
2 BAD 2026-10-27 12:55:03 5019551e31e27de2
3 CURRENT 2026-10-27 12:55:03 0d09b40067a853aa
1 GOOD 2026-10-27 12:55:02 bc34f15b9743da52
$ fossil bisect log
2026-10-27 12:55:03 5019551e31 BAD
2026-10-27 12:55:03 0d09b40067 CURRENT
2026-10-27 12:55:02 bc34f15b97 GOOD
$ fossil bisect reset
good/bad 可省略版本表示"当前检出",标记后 Fossil 会自动 update 到区间中点并给出 CURRENT 标记;bisect chart 按提交顺序展示标记,reset 结束并回到原检出。标签名可以直接当版本号用,不必记哈希。
六、查询与追溯
6.1 文件历史三件套:finfo / annotate / cat
$ fossil finfo README.md
History for README.md
2026-10-27 [f3f5624f7d] 合并 w1/w2 分叉,解决 README 冲突 (user: root, artifact: [92240b8831], branch: trunk)
2026-10-27 [c05bb934e5] trunk:w1 修改 README 标题 (user: root, artifact: [5b817b00a0], branch: trunk)
2026-10-27 [710f0221d9] trunk:w2 修改 README 标题 (user: root, artifact: [6d2b9d8e12], branch: trunk)
2026-10-27 [accc13b06a] 初始提交:main.c、README.md、src/util.c (user: root, artifact: [f168d2ab42], branch: trunk)
$ fossil annotate README.md
c05bb934e5 2026-10-27 1: Fossil CLI demo (trunk from w1)
$ fossil cat README.md
Fossil CLI demo (trunk from w1)
finfo 给出文件级变更历史,annotate 逐行标注最后修改的检入点(排查"这行谁改的"最直接),cat 从库中取指定版本内容而不碰工作区。fossil ls 列出当前检出跟踪的文件清单,fossil diff 输出统一格式补丁:
$ printf 'b2\n' > b.txt
$ fossil changes
EDITED b.txt
$ fossil diff
Index: b.txt
==================================================================
--- b.txt
+++ b.txt
@@ -1,1 +1,1 @@
-a
+b2
6.2 grep 的边界
$ fossil grep "login"
Usage: fossil grep REGEXP FILENAME ...
2.28 的 grep 必须显式给文件名(支持多个),没有 Git 那种全库/全树检索;要在历史里找内容,得配合 fossil search(帮助文本检索)或 fossil sql 直接查 blob 表。
七、配置:settings / set / unset / configuration
$ fossil settings timeline-utc
timeline-utc
$ fossil set timeline-utc on
$ fossil settings timeline-utc
timeline-utc (local) on
$ fossil unset timeline-utc
$ fossil settings timeline-utc
timeline-utc
settings不带参数列出全部 113 项;带参数查询单项值。set/unset是settings的写入口,(local)表示这是本地覆盖值(存放在~/.fossil的配置库),未覆盖时显示为空但实际继承全局或默认值。- 坑位:
project-name不是 settings 项,执行fossil settings project-name会回no such setting: project-name;项目名在fossil init <文件名>时由文件名推导,或直接改fossil info中的project-name(本文所有库都显示<unnamed>正是没设置过的默认状态)。
配置的批量搬家用 fossil configuration,它按域导出/导入,适合在多个库之间同步工单字段、皮肤、别名:
$ fossil configuration export all /root/d2/cfg-export.txt
$ sed -n '1,4p' /root/d2/cfg-export.txt
# The "all" configuration exported from
# repository "/root/d2/w1.fossil"
# on 2026-10-27 12:55:04
config /user 87
支持的域为 all email interwiki project shun skin ticket user alias subscriber,子命令有 export / import / merge / pull / push / reset;merge 保留现有值优先,import 是整体覆盖,批量下发前先 export 备份。
八、用户与权限:user new / user password / user capabilities
user 系列要求当前目录是已打开的检出,或显式用 -R <库文件> 指定仓库。在只有库文件的目录直接执行会连报四次:
$ fossil user new dev dev@example.com devpass123
use --repository or -R to specify the repository database
进入检出后就能正常创建,并即时查看/授予权限:
$ fossil user password root q1w2e3r4
$ fossil user new dev dev@example.com devpass123
$ fossil user list
anonymous Anon
dev dev@example.com
developer Dev
nobody Nobody
reader Reader
root
$ fossil user capabilities dev
u
$ fossil user capabilities dev o
$ fossil user capabilities dev
ou
权限字符是累加的:u 读(reader),加 o 后变成 ou 即 developer(可写);s 是超级管理员(setup),a 匿名,h 隐藏,i 只读工单,j 读 Wiki,w 写 Wiki,x 私有。授予要一次性写全串,例如 fossil user capabilities dev "oujw";fossil user default -v 可以看命令行身份是按 FOSSIL_USER → USER → LOGNAME 的哪一级解析到的。用户永不能删除,只能降权(fossil user capabilities dev "")。
九、Wiki、技术备注与工单
9.1 Wiki 页:create / commit / export / list
$ printf '# 首页\n\nFossil CLI 演示。\n' | fossil wiki create Home
Created new wiki page Home.
$ printf '# 首页\n\nfossil help 查看全部子命令。\n' | fossil wiki commit Home
Updated wiki page Home.
$ fossil wiki list
Home
$ fossil wiki export Home
# 首页
fossil help 查看全部子命令。
create/commit 的第二个参数是文件名,不是内容;直接写 fossil wiki create Home "文本" 会被当成路径,回显 no such file: 文本...。没有文件时从标准输入读,所以运维脚本里用 printf ... | fossil wiki ... 最省事。内容默认 text/x-fossil-wiki,要 Markdown 加 -M markdown。
9.2 技术备注(technote):没有独立命令
2.28 没有 fossil technote 子命令:
$ fossil technote
fossil: unknown command: technote
fossil: use "help" for more information
技术备注由 wiki 命令族加 -t 时间戳创建,时间戳就是它的永久句柄:
$ printf 'v0.1 发布说明:新增 login 行。\n' | fossil wiki create "v0.1 发布说明" -t "2026-10-27T12:00:00" --technote-tags release
Created new tech note 2026-10-27 12:00:00.
$ fossil wiki list -t
2026-10-27 12:00:00
注意新建必须用 create;对不存在的技术备注执行 commit 会回 no such tech note: 2026-10-27T12:00:00。--technote-tags 决定它在时间线上显示的颜色分组标签。
9.3 工单:ticket add / show / set / history
$ fossil ticket add title "CLI 创建的工单" status Open type Code priority Medium severity Minor subsystem cli comment "ticket add 实测"
ticket add succeeded for 1105dd677079d9f0ce7306773b159b6f61384630
$ fossil ticket show 1
bgcolor # mtime type status subsystem title
#f2dcdc 1105dd6770 2026-10-27 12:55:04 Code Open cli CLI 创建的工单
$ fossil ticket set 1105dd677079d9f0ce7306773b159b6f61384630 status Fixed
ticket set succeeded for 1105dd677079d9f0ce7306773b159b6f61384630
$ fossil ticket history 1105dd6770
Ticket Change by root on 2026-10-27 12:55:04:
Change status: Fixed
两个易错点:ticket show 的参数是报表编号或标题(1 即 "All Tickets" 报表,0 是全部字段定义),不是工单号;set/change 才吃工单 UUID。fossil ticket list fields 能看到可写字段(title/status/type/priority/severity/subsystem/resolution/foundin/comment 等),自定义字段要先在 Web 端改 "Ticket Common Script"。
十、附件、导出与打包:artifact / zip / tarball
$ H=$(fossil info | awk '/checkout:/{print $2}')
$ echo $H
0d09b40067a853aa896be9c274190da89628e581
$ fossil artifact $H /root/d2/artifact-out.txt
$ sed -n '1,5p' /root/d2/artifact-out.txt
C w1:修改\sREADME\s第一行
D 2026-10-27T12:55:03.539
F README.md d5e2014deba50f32416abf7cbd2ddaf02638133db3735dcecbb51b2858553e6b
F src/util.c 30c06f42b3a5007753851ba6bc30b112139aabe70a885140805d23bc75c56611
P bc34f15b9743da527d2abe8435a3581b673af90059fe4993d9634b394d100947
artifact 按哈希导出任意对象:检入点是 manifest(C 注释、D 时间、F 文件+blob 哈希、P 父版本),文件是 blob 原文。这也是校验"某版本到底包含哪些文件"的最直接办法。
$ fossil zip trunk /root/d2/trunk.zip
$ fossil zip trunk /dev/null --list
unnamed-20261027125503-5019551e31/README.md
unnamed-20261027125503-5019551e31/src/util.c
fossil zip <version> <out> 直接导出该版本快照;输出路径给 /dev/null 配合 --list 就是"只看会打包哪些文件"。fossil tarball 用法相同,产出 tar 格式。导出目录结构时注意顶层目录名由项目名+时间+哈希拼成,上文 <unnamed> 项目名导致前缀全是 unnamed-...。另外命令表中没有 fossil extract(实测 unknown command: extract),从版本库取内容用 artifact 或 fossil cat,从归档包解压才用系统 unzip/tar。
十一、维护:rebuild / 完整性校验 / repack / backup / scrub / clean
$ fossil rebuild
0.0% complete... 26.3% complete... 52.6% complete... 78.9% complete... 100.0% complete...
$ fossil sql "PRAGMA integrity_check;"
ok
$ fossil repack
1 new delta saves 81 bytes
Vacuuming the database... done
$ fossil backup /root/d2/server-backup.fossil
$ ls -l /root/d2/server-backup.fossil
-rw-r--r-- 1 root root 225280 Oct 27 12:55 /root/d2/server-backup.fossil
$ echo y | fossil scrub
Scrubbing the repository will permanently delete information.
Changes cannot be undone. Continue (y/N)? Removed unmanaged file: src/util.c-original
$ fossil clean --dry-run
$ fossil clean
要点:
rebuild由 artifact 表重建派生表(timeline、文件名索引等),版本库升级、异常断电后必跑;2.28 已经没有fossil fsck,执行会得到fossil: unknown command: fsck,完整性检查改用fossil sql "PRAGMA integrity_check;",输出ok即通。repository does not exist or is in an unreadable directory: --noverbose这类报错通常是选项写在了仓库路径之后,或当前目录不在检出内;rebuild应在检出目录执行,跨库则fossil rebuild -R <库文件>。repack重新计算 delta 压缩并 vacuum,库越小效果越明显;backup生成一致快照(可直接用于恢复,比cp安全)。scrub会删除敏感信息并清理未托管文件,是交互式破坏操作:脚本里必须echo y |或加--force,否则提示会等待输入。clean --dry-run预览将被清掉的未版本控制文件,clean实际删除;两者都支持--dotfiles、--emptydirs。
十二、服务与内置 Web:server / ui / serve,以及 JSON 端点
$ fossil server --localhost --port 8099
Listening for HTTP requests on TCP port localhost:8099, IPv4 and IPv6
$ curl -s -o /dev/null -w 'GET / -> HTTP %{http_code}\n' http://127.0.0.1:8099/
GET / -> HTTP 302
访问根路径 302 跳转到 /home,用建库时的 admin-user/密码(或 root/q1w2e3r4)登录即可看到时间线、工单、Wiki、文件浏览。fossil ui 是同义入口,启动后自动拉起本机浏览器(无图形环境时会直接打印 URL 失败);fossil serve 是 server 的别名,在非检出目录执行会回 current directory is not within an open check-out,说明它和 server 一样需要仓库上下文或 -R。生产场景的 SCGI/Nginx 反代与 systemd 托管见安装篇,本节不重复。
关于 /json 端点:本环境实测四个路径全部 404,
GET /json -> 404
GET /json/version -> 404
GET /json/timeline?n=1 -> 404
GET /json/capabilities -> 404
$ curl -s http://127.0.0.1:8099/json/timeline?n=1
<h1>Not Found</h1>
<p>Page not found: json</p>
fossil settings json 也回 no such setting: json。结论:该 2.28 构建未暴露 JSON API,机器对接请直接用本文的 CLI(fossil sql、fossil timeline、fossil artifact 都可脚本化),不要按网上教程假定 /json/ 可用。
十三、高频坑位速查
| 现象/回显 | 根因 | 处理 |
|---|---|---|
current directory is not within an open check-out | 目录里只有库文件,没 fossil open | 先 fossil open <库>,或给命令加 -R <库> |
use --repository or -R to specify the repository database | user 系列在非检出目录执行 | 进检出或用 -R |
fossil mv 后 commit 报 no such file: <新路径> | mv 默认只登记不改磁盘 | 用 fossil mv --hard 或 fossil set mv-rm-files 1 |
unrecognized command-line option ... -from | branch new 不接受 -from | 改位置参数 fossil branch new <新分支> <基线> |
Would fork. "update" first or use --branch or --allow-fork. | 远端有另一叶子 | 先 fossil update,或确认后加 --allow-fork |
no such setting: project-name | 项目名不是 setting | 建库时命名或用 fossil info 核对 |
no such file: <中文文本>(wiki) | wiki create 第二参数是文件名 | 文本走标准输入或先落文件 |
unknown command: fsck | 2.28 已移除 | fossil sql "PRAGMA integrity_check;" |
unknown command: technote | 无独立命令 | fossil wiki create "注释" -t <时间戳> |
Usage: fossil grep REGEXP FILENAME ... | grep 不支持全库检索 | 显式给文件,或用 fossil sql |
掌握这一套命令后,Fossil 的日常操作可以完全脱离 Web 界面:建库、提交、双机同步、冲突合并、历史追溯、备份维护都有对应的单条命令,且全部指向同一个单文件 SQLite 版本库,备份与迁移只需复制或 fossil backup 一个文件。