nvrmnd-png/undo
GitHub: nvrmnd-png/undo
一款通过 shell 集成拦截常见文件系统命令并将所有操作记录到 SQLite 的命令行撤销工具,让 mv、rm、cp 等操作均可恢复。
Stars: 42 | Forks: 1
# 撤销
  
Shell 的文件系统命令是不可逆的:一旦你用 `mv` 覆盖了文件,或者用 `rm` 删除了目录,就没有内置的方法可以恢复。**undo** 会记录所有支持的操作,并可以根据需要撤销它们,而且它从不直接删除任何内容,因此即使是 `rm` 也是可以恢复的。

它通过*拦截*命令而不是监视命令来工作:一个小的 shell 集成会将 `mv`、`cp`、`rm`、… 路由到 undo,由后者在 Rust 中自行执行操作,并准确记录如何撤销它。删除的文件会进入 freedesktop.org 回收站,被覆盖的文件会先在那里备份,并且每次回滚在修改任何内容之前都会验证文件的完整性。
## 支持的命令
`mv` · `cp` · `rm` · `mkdir` · `rmdir` · `chmod` · `chown` · `ln` · `rename`
`rm` 和 `rmdir` 会移动到回收站而不是直接删除。覆盖操作(`mv`、`cp`、`ln -f`)会将替换掉的文件存放在回收站中,因此它们是完全可逆的。
`rename` 使用 Perl 的 `s/old/new/` 语法。
## 安装
```
git clone https://github.com/nvrmnd-png/undo
cd undo
./manager.sh # interactive: build from source or fetch a prebuilt binary
```
`manager.sh install --source` 会使用 `cargo` 构建并安装到 `~/.local/bin`;`--prebuilt` 会下载发布版本的二进制文件并验证其 SHA-256。可以使用 `UNDO_PREFIX` 覆盖安装位置。或者直接使用 cargo:
```
cargo install --path .
```
### 启用 shell 集成
undo 只会记录通过其包装器执行的命令。在你的 shell 启动文件中添加一行:
```
# ~/.zshrc
eval "$(undo init zsh)"
# ~/.bashrc
eval "$(undo init bash)"
# ~/.config/fish/config.fish
undo init fish | source
```
打开一个新的 shell,你日常使用的 `mv`/`cp`/`rm`/… 就变得可撤销了。对于单次调用,可以使用 `command mv …` 或 `\mv …` 来绕过包装器。
## 用法
| 命令 | 作用 |
|---|---|
| `undo` | 撤销最近的一次操作 |
| `undo redo` | 重新应用最近撤销的操作 |
| `undo list` | 显示 undo 和 redo 栈 |
| `undo history` | 显示完整日志(`-n N`,`--all`) |
| `undo show ` | 详细显示某一条目 |
| `undo clear` | 清除日志(绝不触碰回收站) |
| `undo tui` | 交互式浏览并执行 undo/redo |
| `undo init ` | 打印 shell 集成代码片段 |
全局标志:`--force`(覆盖完整性拒绝;被替换的文件会进入回收站)、`--dry-run`(报告会发生什么)和 `--json` / `--yaml`(稳定的机器输出,`schema: 1`)。
```
$ undo list
Undo stack (newest first):
#8 2026-07-14 09:14 applied rm -r build/
#7 2026-07-14 09:12 applied mv report.txt archive/
$ undo history --json | jq '.entries[0].command'
"rm"
```
### 交互式 TUI
`undo tui` 会打开一个彩色的浏览器:包含日志条目列表、详细信息面板以及实时完整性徽章。
| 按键 | 操作 |
|---|---|
| `j` / `k` | 向下 / 向上移动 |
| `Tab` | 切换过滤器 |
| `v` | 验证所选条目 |
| `u` | 撤销所选条目 |
| `r` | 重做所选条目 |
| `f` | 切换 `--force` |
| `?` | 帮助 |
| `q` | 退出 |
## 安全性
- **绝不删除任何内容。** `rm`/`rmdir` 使用 freedesktop 回收站;每个破坏性的逆向操作(删除副本、替换覆盖的文件)也都会通过回收站进行。跨设备移动在任何删除之前都会进行经验证的复制。
- **每次回滚前都会检查完整性。** 内容使用 BLAKE3 进行指纹识别(在 64 MiB 以上时为大小 + mtime);自操作以来被修改过的文件将拒绝回滚,除非你传递 `--force`。
- **仅限你的数据。** 日志是私有的(`0600`,已检查所有权),并且会拒绝来自其他用户的条目。
- **在检查期间绝不跟踪符号链接**,并且操作会被锁序列化,在每次变更前立即重新检查。
### 限制
undo 只能撤销通过其包装器执行的操作。`sudo`、脚本、cron 和 GUI 文件管理器会绕过它们(过期的日志会被验证机制捕获,而不是盲目地重放)。复制目录树内的 ACL、xattrs 和硬链接拓扑不会被保留。非 UTF-8 路径会回退到真实命令。清除日志不会清空回收站。完整列表请参见 `man undo`。
## 工作原理
每个操作都存储在特定用户的 SQLite 日志中(`$XDG_DATA_HOME/undo`),包含其命令行、工作目录、每个受影响节点的操作前/后状态,以及确切的逆向操作。`undo`/`redo` 会将其作为栈来处理;新的操作会像编辑器一样清除 redo 栈。回滚过程中的部分失败会补偿回一致的状态,并且因为所有被替换的内容都存在于回收站中,即使在最坏的情况下也不会丢失任何内容。
## 开发
```
cargo test # 150+ unit and integration tests
cargo clippy --all-targets
cargo fmt --check
```
## 支持
如果 undo 帮你避免了一次糟糕的 `rm`,可以考虑赞助一下:
| 资产 | 地址 |
|---|---|
| BTC | `bc1qmgnz54x4epaeuvz558z4d7n3a3dqk3vldsgcnt` |
| XMR | `43eLK3JjmkDiWAuP9b5N8sahtzQQByaVSEPbZvVTctXAYJ1cHGXbVL3f8PSREnmnSsY4rMkhx14UA8vxc5sfz4ZhDfxKkg5` |
| ETH | `0x8CF98DeF5d716E10697E5905caff34b405dcd4fF` |
| SOL | `DFwWy5EMB5QRd1FTV81ft5WYyH6uHecRvPsXkLNRyh1s` |
## 许可证
GPLv3 © 2026 nvrmnd。请参见 [LICENSE](LICENSE)。
标签:Rust, Shell扩展, 可视化界面, 数据恢复, 文件管理, 系统运维, 网络流量审计, 通知系统