▼ 本文更新于 [2026-05-18 一 14:25]

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 一样了:

  1. 可以指定需要的 commit 版本,比 melpa 更自由。
  2. 仅保留当前选定commit的快照,所有放在 .git 里的历史记录都归于虚无,和 melpa 仅保存快照的工作机制一致。
  3. 可以通过 use-pacakge 统一管理,而且可以通过同步整个 .emacs.d 保持多设备配置一致。

© Published by Emacs 31.0.50 (Org mode 10.0-pre) | RSS Comment