emacs-使用use-package的:vc像melpa一样安装package快照
MELPA (Milkypostman’s Emacs Lisp Package Archive) 是 Emacs 社区中一个广泛使用的第三方包托管网站。根据我个人的观察,和手动调用 package-vc-install / straight / borg 这种基于 Git 的包管理方式相比,主要优点是与 package.el 的集成不错,可以方便快捷地在一个页面搜索 package 、更新删除,还可以通过其中自动安装其他 package 的依赖。
也正因为 melpa 上托管了不少第三方包,导致其更新周期有一点长,基本是2-3小时才能完成一次更新。更雪上加霜的是,由于国内网络环境,直连 melpa 的速度令人忍俊不禁,第三方源的同步频率更是底到一天两次。
针对我的使用场景,还有一点特殊:我将整个 .emacs.d 文件夹放进了 git 中同步。如果使用普通的 git 相关包管理工具,由于它们都会在本地 clone 一个 git repo ,导致其下载到本地的代码文件夹会被 .emacs.d 的 git 给当成 submodule 忽略掉。
对 Git 而言,如果工作树中出现另一个仓库的 .git 目录,它就会将其视为“子仓库”(nested repository)。此时上层 Git 只会记录一个所谓的 gitlink(一个表示子仓库提交哈希的条目),而不会跟踪该目录内的具体文件。
有没有办法将安装好的包也纳入同步呢?我们可以利用 use-package 新增的 :vc 关键字,并为其增加一些自定义 advice 。
(with-eval-after-load 'package-vc
(defun my/package-vc--clone-remove-dotgit (pkg-desc _pkg-spec pkg-dir &rest _)
"Remove .git right after cloning."
(let ((git-path (expand-file-name ".git" pkg-dir)))
(when (file-exists-p git-path)
(if (file-directory-p git-path)
(delete-directory git-path t)
(delete-file git-path))
(message "Removed .git from %s" pkg-dir))))
(advice-add 'package-vc--clone :after #'my/package-vc--clone-remove-dotgit))
通过上面这个函数以及 advice ,我们可以为 package-vc--clone 添加一个后续的操作函数,将 clone 路径里的 .git 文件删除。这样一来,这些 repo 也会被上层 git 给发现并纳入同步了。
现在,我们在使用 use-package + :vc 的时候,也能像 melpa 一样了:
- 可以指定需要的
commit版本,比 melpa 更自由。 - 仅保留当前选定commit的快照,所有放在 .git 里的历史记录都归于虚无,和 melpa 仅保存快照的工作机制一致。
- 可以通过
use-pacakge统一管理,而且可以通过同步整个.emacs.d保持多设备配置一致。