#snapshot #zfs #backup #restore #search-file #command-line-tool #walk-dir

无std app httm

一个用于查看ZFS和btrfs数据集上快照文件版本的CLI工具

190个版本 (26个破坏性更新)

0.42.2 2024年8月24日
0.41.5 2024年8月13日
0.40.5 2024年7月28日
0.37.9 2024年3月29日
0.14.7 2022年7月30日

#20 in 操作系统

Download history 5/week @ 2024-05-17 157/week @ 2024-05-24 11/week @ 2024-05-31 5/week @ 2024-06-07 2/week @ 2024-06-14 175/week @ 2024-06-21 261/week @ 2024-06-28 256/week @ 2024-07-05 537/week @ 2024-07-19 910/week @ 2024-07-26 422/week @ 2024-08-02 790/week @ 2024-08-09 243/week @ 2024-08-16

2,535 每月下载量

MPL-2.0 许可证

450KB
9K SLoC

Rust 7.5K SLoC // 0.1% comments BASH 1K SLoC // 0.1% comments Handlebars 67 SLoC Zsh 51 SLoC // 0.3% comments Pacman's makepkg 34 SLoC // 0.2% comments

asciicast

httm

使用httm,CLI时光机的梦想依然存在。

httm打印出驻留在快照上的可用唯一版本(通过修改时间和大小进行去重)的大小、日期和对应位置,但也可以用于交互式选择和恢复文件,甚至可以通过文件恢复快照挂载!httm可能会改变您使用快照(因为ZFS/BTRFS/NILFS2不是为查找唯一文件版本而设计的)或时光机概念的方式(因为httm非常快!)。

httm拥有许多诱人的功能,如

  • 同时搜索不同数据集上多个文件的版本
  • 搜索和递归列出已删除文件。 甚至可以浏览删除目录背后的文件
  • 列出所有本地池的文件快照(检测本地快照版本以及本地复制的快照版本)!
  • 列出远程备份池的文件快照(甚至可以将远程快照目录覆盖到活动目录上)。
  • 适用于rsync的本地非ZFS/BTRFS/NILFS2/APFS数据集(如ext4、XFS或NTFS),而不仅仅是ZFS/BTRFS/NILFS2快照和TM备份。
  • 可选地使用自定义命令预览快照文件版本(默认是diff与活动版本比较)
  • 直接列出或快照文件的挂载点
  • 向前滚动到以前的快照,而不是回滚(避免删除中间快照)
  • 使用预防性快照来保护任何恢复操作
  • 列出快照名称,甚至可以删除包含文件名的快照
  • 快捷功能:仅显示最后一个快照,省略活动文件的重复项等。
  • 验证级别:与rsync一样,httm可以根据仅基于元数据或使用校验和来确定文件是否唯一
  • 4种原生交互模式:浏览、选择、修剪和恢复
  • 环境中的ANSI ls颜色
  • 检测并显示可用的独特文件版本类别(multiplesinglesingle-with-snap、...等)
  • 从多种格式化样式中选择(换行符、空、制表符分隔、JSON等)。可解析的...或不...哦,我的天啊!
  • 包装的脚本可以帮助您,并展示如何使用 httmouncebowieequinenicotine
  • 支持 ZFS/BTRFS/NILFS2 快照,以及 Restic 和 Time Machine 备份!

与您喜欢的 shell 的热键结合使用,让乐趣倍增。

受到 findoid 脚本、fzfskim 和许多 zsh 键绑定的启发。

通过原生包安装

对于基于 Debian 的发行版(如 Ubuntu),我维护了一个(不受支持的)个人软件包存档,或 PPA。请参阅链接的仓库

对于基于 Debian 和 Redhat 的 Linux 发行版(如 Ubuntu 或 Fedora 等),还可以查看针对您的发行版的标记的版本。对于基于 Redhat 的 Linux 发行版,您可能需要在通过 rpm -i 安装时使用 --replacefiles 选项,请参阅链接的 问题

您还可以从最新源创建并安装自己的原生包,适用于基于 Debian 和 Redhat 的 Linux 发行版,如下所示

#!/bin/bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo install cargo-deb 
git clone https://github.com/kimono-koans/httm.git
cd ./httm/; cargo deb
# to install on a Debian/Ubuntu-based system
dpkg -i ./target/debian/httm_*.deb
# or convert to RPM 
alien -r ./target/debian/httm_*.deb
# and install on a Redhat-based system
rpm -i --replacefiles ./httm_*.rpm

对于基于 Arch 的 Linux 发行版,您可以从最新源创建并安装自己的原生包,如下所示

#!/bin/bash
# warning: this is only an example PKGBUILD
# you may need to edit the example, as needed, to conform to the latest release
wget https://raw.githubusercontent.com/kimono-koans/httm/master/packaging/arch/example/PKGBUILD
makepkg -si

对于 MacOS 用户,社区中的一个用户(非常令人兴奋)已经发布了公式,用于Homebrew

通过源安装

建议通过包安装以支持目的,但那些 野孩子,也许无法停止(或不想停止),他们可以通过将脚本通过管道传递到 bash 来安装

bash -c "$(curl -fsSL https://raw.githubusercontent.com/kimono-koans/httm/master/packaging/install-from-source.bash)"

对于那些只想自己逐步构建 httm 的人来说,该项目只包含几个组件

  1. httm 可执行文件。要构建和安装

    #!/bin/bash
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    latest="(wget -nv -O - "https://api.github.com/repos/kimono-koans/httm/releases/latest" 2>/dev/null | grep tag_name | cut -d: -f2 | cut -d'"' -f2)"
    # cargo-install places a release binary in your $HOME/.cargo/bin, however, 
    # you may wish to: cp $HOME/.cargo/bin/httm /usr/local/bin/httm; cargo uninstall httm
    cargo install --locked --git https://github.com/kimono-koans/httm.git --tag "$latest"
    
  2. 可选的 zsh 热键绑定:使用 ESC+s 选择要删除到命令行中的快照文件名(例如在 cat 命令之后),或使用 ESC+m 浏览文件的所有快照。在安装 httm 二进制文件后,将热键脚本复制到您的家目录,并在您的 .zshrc 中源该脚本

     httm --install-zsh-hot-keys
    
  3. 可选的 man 页面:cargo 没有原生设施用于安装 man 页面(尽管将来可能会有)。您可以使用 manpath 查看系统使用的各种目录并决定哪个目录最适合您。要安装,只需将其复制到您的 man 路径中的一个目录,如下所示

     cp ./httm/httm.1 /usr/local/share/man/man1/
    
  4. 可选脚本。请参阅以下示例用法部分中的脚本使用说明,或点击链接获取更多信息(ouncebowieequinenicotine)。要安装,只需将其复制到您的路径中的某个目录,如下所示

    #!/bin/bash
    cp ./httm/scripts/ounce.bash /usr/local/bin/ounce
    # bowie is "required" for the default/best "--preview" behavior
    cp ./httm/scripts/bowie.bash /usr/local/bin/bowie
    # equine is "required" for Time Machine support on MacOS
    cp ./httm/scripts/equine.bash /usr/local/bin/equine
    cp ./httm/scripts/nicotine.bash /usr/local/bin/nicotine
    chmod +x /usr/local/bin/bowie /usr/local/bin/ounce /usr/local/bin/equine /usr/local/bin/nicotine
    

注意事项

目前,您可能需要使用支持 Rust 的 Unix-like 平台来构建和安装(即:只有 Linux、FreeBSD 和 MacOS 才已知可以工作)。请注意,您的平台无需支持 ZFS/BTRFS/NILFS2 快照或 TM 备份即可使用 httm。而且,没有基本理由不能构建非交互式 Windows 版本的 httm,因为它曾经可以构建,但现在 Windows 平台支持不是我的首要任务。用户的贡献当然是受欢迎的。

在 FreeBSD 上,在全新最小化安装后,交互模式可能无法正确渲染,请参阅修复链接 问题

在某些 Linux 发行版中,包括旧的 libc 版本,可能需要使用 musl 构建 cargo,请参阅链接 问题

示例用法

注意:用户可能需要使用 sudo(或等效)来查看 BTRFS 或 NILFS2 数据集或 Restic 存储库的版本,因为 BTRFS 或 NILFS2 快照或 Restic 存储库可能需要 root 权限才能可见。Restic 和 Time Machine 备份还需要一个额外的标志,请参阅以下关于 Restic --alt-store 的进一步讨论。

与其他 UNIX 工具(如 catuniqsort)一样,如果您不提供路径/作为参数,则 httm 将暂停等待从 stdin 输入。

# Press CTRL+C to send a SIGINT and quit the program
➜ httm 
# Pipe output of find command to httm
➜ find . -maxdepth 1 | httm

打印历史文件中所有唯一的版本

 httm ~/.histfile

以格式化的 JSON 打印历史文件中所有唯一的版本

 httm --json ~/.histfile

递归地浏览您的主目录中的所有文件,并查看本地快照上的唯一版本

 httm -b -R ~

递归地打印已从您的主目录中删除的快照上的所有文件

 httm -d -R ~

递归地浏览从您的主目录中删除的所有文件,并查看所有本地和替代复制的数据集快照上的唯一版本

 httm -d=only -b -a -R ~

递归地打印已从您的主目录中删除的快照上的所有文件,以换行符分隔,管道到文本文件

# pseudo live file versions
➜ httm -d -n -R --no-snap ~ > pseudo-live-versions.txt
# unique snapshot versions
➜ httm -d -n -R --no-live ~ > deleted-unique-versions.txt

递归地浏览您的主目录中的所有文件,并查看本地快照上的唯一版本,以选择并最终以覆盖模式恢复到其原始位置

 httm -r=overwrite -R ~

递归地浏览您的主目录中的所有文件,并查看本地快照上的唯一版本,以选择并最终以“保护”模式恢复到您的工作目录,该模式通过预先恢复的 ZFS 快照覆盖和保护任何恢复操作

 printf "
# export a default httm restore mode
export HTTM_RESTORE_MODE=\"guard\"" >> ~/.zshenv
➜ httm -r -R ~

查看文件的唯一版本以进行恢复(快捷方式,无需浏览目录)

 httm -r /var/log/samba/log.smbd

httm 也是一名优秀的 UNIX 公民,这意味着——您应该使用其他 UNIX 工具以您喜欢的方式组织您的查询。findawk 特别有用。

# search for the text "pattern" among snapshots of httm manpage
➜ httm -n --omit-ditto /usr/share/man/man1/httm.1.gz | xargs rg "pattern" -z

# print all unique versions of your `/var/log/syslog` file, 
# newline delimited piped to `find` to print only versions 
# with modify times of less than 1 day from right now.
➜ httm -n --omit-ditto /var/log/syslog | xargs -I{} find '{}' -mtime -1

# httm usually sorts snapshot versions in chronological order, 
# oldest to newest, but since these are just paths/strings 
# you may choose to sort them differently.
#
# here, print all unique versions of your `/var/log/syslog` file, 
# then print each snapshot version's size in bytes first, 
# then reverse sort by its size, then remove the number of bytes, 
# leaving only the paths in their new sorted order
➜ httm -n --omit-ditto /var/log/syslog | xargs -I{} find '{}' -printf '%s\t%p\n' | \
sort -rn | awk 'BEGIN {FS="\t"}; {print $2}'

查看 ~/.zshrc 的每个唯一快照与实时文件版本之间的 diff(需要安装 bowie 脚本)

 httm --preview -s ~/.zshrc

查看 ~/.zshrc 的每个唯一快照的 cat 输出

 httm --preview="cat {snap_file}" -s ~/.zshrc

恢复最新的唯一文件版本(快捷方式,无需浏览目录或从其他唯一版本中选择)

 httm -l -r /var/log/samba/log.smbd

快照位于 /etc/samba/smb.conf 的数据集

 sudo httm -S /etc/samba/smb.conf

递归浏览通过 rsync 备份到远程共享的文件夹中的所有文件,并直接查看远程快照上的唯一版本(仅适用于 BTRFS Snapper 和 ZFS 数据集)。(注意:记得在您的 smb.conf 中将 ZFS 快照设置为可见,使用 zfsacl:expose_snapdir=True)。

# mount the share
➜ open smb://<your name>@<your remote share>.local/Home
# execute httm
➜ httm -b -R /Volumes/Home

递归浏览您的 MacOS 家目录中通过 rsync 备份到 ZFS 或 BTRFS Snapper 远程共享的所有文件,通过 smbd 共享,并查看远程快照上的唯一版本。注意:与上述不同之处在于,这里您正在浏览“实时”目录中的文件。

# mount the share
➜ open smb://<your name>@<your remote share>.local/Home
# execute httm
➜ httm -b -R --map-aliases /Users/<your name>:/Volumes/Home ~

打印 .zshrc 文件的全部唯一版本。注意:与上述不同之处在于,httm 现在甚至直接支持您的 Time Machine 备份。使用 equine 将我的个人 Time Machine ZFS 网络共享挂载后。

➜ sudo equine --mount-local
Discovering backup locations (this can take a few seconds)...
Mounting snapshots...
...
➜ sudo equine --mount-remote
Connecting to remote Time Machine: smb://timemachine@montrose._smb._tcp.local./TM%20Volume ...
Mounting sparse bundle (this may include an fsck): Backups of kiev ...
/dev/disk4
/dev/disk5           EF57347C-0000-11AA-AA11-0030654
/dev/disk5s1         41504653-0000-11AA-AA11-0030654 /Volumes/Backups of kiev
Discovering backup locations (this can take a few seconds)...
Mounting snapshots...
...
# restic users can do something similar by:
# 1. mounting their repositories: restic -r /path/to/repo mount /path/to/mountpoint
# 2. invoking httm with --alt-store: httm --alt-store=restic .zshrc
➜ httm --alt-store=timemachine .zshrc
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Tue May 09 22:57:09 2023  6.7 KiB  "/Volumes/.timemachine/842A693F-CB54-4C5A-9AB1-C73681D4DFCD/2023-11-08-212757.backup/2023-11-08-212757.backup/Data/Users/kimono/.zshrc"
Sun Nov 12 20:29:57 2023  6.7 KiB  "/Volumes/.timemachine/842A693F-CB54-4C5A-9AB1-C73681D4DFCD/2023-11-18-011056.backup/2023-11-18-011056.backup/Data/Users/kimono/.zshrc"
Sun Nov 26 02:14:56 2023  6.7 KiB  "/Volumes/.timemachine/842A693F-CB54-4C5A-9AB1-C73681D4DFCD/2023-12-13-054342.backup/2023-12-13-054342.backup/Data/Users/kimono/.zshrc"
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Sun Nov 26 02:14:56 2023  6.7 KiB  "/Users/kimono/.zshrc"
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

查看 httm man 页面上每个唯一快照版本与每个先前版本之间的差异(这个简单的脚本是 bowie 的基础)。

#!/bin/bash
filename="./httm/httm.1"
# previous version is unset
previous_version=""
for current_version in $(httm -n --omit-ditto $filename); do
    # check if initial "previous_version" needs to be set
    if [[ -z "$previous_version" ]]; then
        previous_version="$current_version"
        continue
    fi

    # print that current version and previous version differ
    diff -q "$previous_version" "$current_version"
    # print the difference between that current version and previous_version
    diff "$previous_version" "$current_version"

    # set current_version to previous_version
    previous_version="$current_version"
done

创建所有唯一版本的 /var/log/syslog 的简单 tar 归档。

 httm -n --omit-ditto /var/log/syslog | tar -zcvf all-versions-syslog.tar.gz -T -

创建所有唯一版本的 /var/log/syslog有点花哨tar 归档。

#!/bin/bash
file="/var/log/syslog"
dir_name="${$(dirname $file)/\//}"
base_dir="$(basename $file)_all_versions"
# squash extra directories by "transforming" them to simply snapshot names 
httm -n --omit-ditto "$file" | \
tar \
--transform="flags=r;s|$dir_name|$base_dir|" \
--transform="flags=r;s|.zfs/snapshot/||" \
--show-transformed-names \
-zcvf "all-versions-$(basename $file).tar.gz" -T  -

创建所有唯一版本的 /var/log/syslog超级花哨git 归档(这个简单的脚本是 nicotine 的基础)。

#!/bin/bash
# create variable for file name
file="/var/log/syslog"
# create git repo
mkdir ./archive-git; cd ./archive-git; git init
# copy each version to repo and commit after each copy
for version in $(httm -n --omit-ditto $file); do
    cp "$version" ./
    git add "./$(basename $version)"
    # modify commit date to match snapshot modify date-time
    git commit -m "httm commit from ZFS snapshot" \
    --date "$(date -d "$(stat -c %y $version)")"
done
# create git tar.gz archive
tar -zcvf "../all-versions-$(basename $file).tar.gz" "./"
# and to view
git log --stat

使用 ounce(代号:“dimebag”),一个 httm 的包装脚本,进行无心理负担、非周期性的动态快照。

# request ZFS snapshot privileges
➜ ounce --give-priv
# here you create a "dummyfile", ounce will add a snapshot of "dummyfile" 
# before you remove it, and httm will allow you to view the snapshot created
➜ touch ~/dummyfile; ounce rm ~/dummyfile; httm ~/dummyfile
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Wed Feb 15 12:59:42 2023  0 bytes  "/home/kimono/.zfs/snapshot/snap_2023-02-15-12:59:42_ounceSnapFileMount/dummyfile"
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                                   "/home/kimono/dummyfile"
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
# use as an alias around programs which modify files/dirs
➜ printf "
# ounce aliases 
alias vim=\"ounce --trace vim\"
alias emacs=\"ounce --trace emacs\"
alias nano=\"ounce --trace nano\"
alias rm=\"ounce rm\"" >> ~/.zsh_aliases

使用 bowie,一个 httm 的包装脚本,显示唯一快照版本与实时文件之间的差异。

 bowie ~/.zshrc
/home/kimono/.zshrc
__
Files /home/kimono/.zfs/snapshot/snap_2023-02-14-13:42:11_ounceSnapFileMount/.zshrc and /home/kimono/.zshrc differ
1c1
< ### If you come from bash you might have to change your $PATH.
---
> # If you come from bash you might have to change your $PATH.

使用 nicotine,一个 httm 的包装脚本,将唯一快照文件版本转换为 git 归档。

 nicotine .zshrc
nicotine git archive created successfully: /home/kimono/zshrc-git.tar.gz

向前滚动到以前的 ZFS 快照,而不是回滚(这避免了破坏中间快照)。

 sudo httm --roll-forward=rpool/scratch@snap_2023-04-01-15:26:06_httmSnapFileMount
[sudo] password for kimono:
httm took a pre-execution snapshot named: rpool/scratch@snap_pre_2023-04-01-15:27:38_httmSnapRollForward
...
httm roll forward completed successfully.
httm took a post-execution snapshot named: rpool/scratch@snap_post_2023-04-01-15:28:40_:snap_2023-04-01-15:26:06_httmSnapFileMount:_httmSnapRollForward

嘿,@kimono-koans,你的快照是从哪里来的?

如果您想了解有关其他人/我如何创建快照的更多信息,您可能想尝试我的 《关于有效 ZFS 快照的有些意见的指南》

我知道你在想什么,但慢点。

To be clear, httm is not...

许可证

httm 根据 MPL 2.0 许可证授权 - 有关更多详细信息,请参阅 LICENSE 文件。

依赖项

~14–26MB
~408K SLoC