求教一个详细的git submodule管理插件的步骤说明

最近在编写自己的Emacs配置的过程当中,对于插件管理上,我曾经尝试过package.el、Elpaca,但是如论坛所指出的,有些在elpa的包会有版本低、安全性差的问题,有些甚至不提供elpa的安装方式,另外,我自己日常工作是在Linux和Windows下进行的,于是在近期也是看到论坛提到用git submodule的方式手动管理,也想做出尝试。

一开始我是按照这篇文章来做的: Managing packages in Emacs · Daniel Yaren

仿照这篇文章,我初步写出了这些配置: Mika-Lahtinen/kemacs (github.com)

但是加载的时候,后台还是直接开始扫描melpa仓库安装,而不是直接使用submodule加载的插件。

现在有问题:

  1. 我在论坛里看到的还只是分散在各个话题当中提到git submodule这种方式,可否以成文章的形式介绍一下更为详细的使用git submodule管理插件的步骤和方法?
  2. 我在配置AucTeX的时候,发现通过源码还要在不同平台下先单独在命令行编译,有没有什么方法在比如.gitmodule文件下提前写好配置或者预编译代码,这样尽量让配置开箱即用?

可以尝试使用 Borg 做包管理,很接近直接用 git submodule 手动管理。就算不喜欢 borg 也可以读一下源码或文档(因为很好懂),理解它的原理和做法以后自己模仿

1 个赞

说到这又一个新问题:这种手动管理插件的方法,会不会遇见不同插件有着同名的依赖但是不同版本的情况,这时候一般又会如何处理?

关于 submodule 的用法可以看我的博客介绍 我平常是怎么折腾Emacs插件的?

请先认真看我上面的内容, 然后看下面的回答:

  1. 添加插件: git submodule add 就好了, 插件更新就是切换到子目录 git pull 就好了, 配置仓库只保存每个插件的 commit id, 并不会保存任何插件内容, 这样你的配置仓库以后再次 clone 的时候会很小
  2. 删除插件: git submodole remove, 目前 git 没有针对 submodule remove 提供开箱即用的命令, eaf-git 可以帮助我们快速清理 submodule
  3. 插件更新: 去插件目录 git pull 就好了, submodule 最妙的是, 如果你觉得插件新版有bug, 可以直接 git reset 到稳定的 commit id 继续用老版的插件, 不会像 elpa 这种一股脑全部升级, 万一新版有问题, 只能硬着头皮折腾的尴尬情况
  4. 关于不同平台编译的情况: 我的方式是不同平台编译好放在目录下, 自己在配置文件中写 if else 来选择加载不同平台对应的编译目录
  5. 手动管理插件: 手动是麻烦, 遇到差依赖就继续手动下载就好了, 但是就是require的时候麻烦, 以后一点麻烦都没有, 因为你永远不会遇到你不知道升级了啥就挂了, 手动管理插件的出错路径非常清晰, 只有你今天手动升级才是挂的原因, 你很容易通过上面说的 git reset 命令来回滚到任意版本
  6. 不同插件有着同名的依赖但是不同版本的情况: 我手动管理插件十多年了, 很少遇到这种问题, 一般都是某个公共库太新导致了, 遇到这种情况, 给公共库提交一个issue后, 马上 git reset 回到稳定 commit 集合, 继续稳定的干活

手动管理插件, 如果用 eaf-git 这种插件, 你会发现一个命令都不用敲, 全傻瓜操作。

如果用git命令管理, 基本上就是安装的时候多费5分钟时间安装一下依赖, 但是好处就是你永远都可以稳定的工作。

最后分享一下我的经验: 手动插件管理 + 扁平化配置(不要追求所谓美观配置给自己带镣铐) + 没事别升级插件 + git是唯一能够让Emacs插件稳定工作的方式。

11 个赞

感谢您的回复,刚才去在Windows试着安装了一下EAF-git,用msys2编译的Emacs 30.0.50 会报错json-parse-buffer的Symbol’s function is void 错误, 换到Emacs 28.2就没有问题了,我回去先研究一下,装几个常用的插件试试看

看了一下Borg的文档,这个方案留待后面直接用git submodule用着不顺利的时候再试试

可以看看我目前的方法,把所有的包当作一个 submodule,绕开依赖管理。

项目地址更改为

这个方法看着是比较新颖,没这么尝试过

Borg 严重依赖 magit,在Liunx 上体验应该会很好。但在Windows 下 magit 太慢。楼主如果主力系统是 Linux的话,推荐用 Borg,否则不建议。

我是主力用 macOS,其次是 Windows,配置主要在 macOS上更新。

我是属于,Windows和Linux都用,五五开那种,magit在Windows下的性能不行这个我还是清楚的,之前还没开始重新组织配置的时候,也是听的陈斌先生的建议,用的vc

来个文不对题(不使用git submodule)的回复:

可以看看我写的一个包:新包:pie - package installer for Emacs

不依赖package.el,支持git clone仓库或者http下载单个文件,支持定制化构建包。不过我不用windows,不确定在win上会不会有啥问题。

依赖Magit吗?

不依赖magit,依赖vc(对于git仓库,一开始用的是vc,后来改成直接使用git这个命令行工具,对于hg之类的其他类型仓库,依赖vc,不过其他仓库我没测过。。。)

出现一个新问题:我按照use-package的说明,将use-apckage通过git submodule add到我设定的插件目录,在使用git submodule add另一个插件(如markdown-mode),用use-package加载的时候,我的插件路径:load-path是对的,但是还是在打开Emacs的时候,给我直接从elpa上查找markdown-mode,而不是直接使用我本地的文件,这样的问题怎么解决?

我使用的是 use-package+quelpa+git submodule 管理我自己写的一些package

首先所有的子模块我都放在 .emacs.d/site-lisp 目录下,所以需要添加 site-lisp 路径到 load-path https://github.com/honmaple/maple-emacs/blob/master/core/core.el#L126

然后是使用 use-package+quelpa, 其中的 quelpa 关键词是我自定义的 https://github.com/honmaple/maple-emacs/blob/master/core/core-use-package.el#L197

其中关键的地方就在于会优先查找本地的package,如果没有才会下载远程的包

(defun use-package-handler/:quelpa (name _keyword args rest state)
  "NAME KEYWORD ARGS REST STATE."
  (use-package-concat
   `((unless (or (locate-library ,(format "%s" name))
                 (package-installed-p ',(pcase (car args)
                                          ((pred listp)   (caar args))
                                          ((pred symbolp) (car args)))))
       (apply 'quelpa ',args)))
   (use-package-process-keywords name rest state)))

如果我在其它地方使用emacs(非我本机),可以选择是否克隆子模块,不克隆的话会使用quelpa下载package。

如果不想使用子模块,而是一个独立的本地包,和emacs配置一起管理,同样可以放到site-lisp目录下,只需要添加:ensure nil即可,具体这些都可以在我的配置里找到

https://github.com/honmaple/maple-emacs

我用magit加submodule,按提示就搞定了,什么都没学的

前不久换成了straight,现在是elpa+少量straight,straight相比submodule好处是原样给你目录,可以直接git/magit操作。不过默认只认elisp文件,找了好久怎么把lsp-bridge的py文件放进去。

昨天试了一天把use-package用上,失败了,还是暂时考虑直接require了

use-package没什么坑,只要注意 always-ensure always-defer 和 demand 应该就可以了。搞好之后已经require了的不用动,加新插件再用use-package就行

我是当时面对的问题是这样,use-package的load-path读取的路径,我按照插件的绝对路径写的,但是似乎它还是给我搞的是相对路径,这就是我不得不暂时放弃使用use-package的原因

use-package 里的 load-path 是配合和 user-emacs-directory 展开的,有什么理由一定要用绝对路径咧?

3.7 Setting a custom ‘load-path’
================================

If a package resides in some directory that is not in your ‘load-path’,
use the ‘:load-path’ keyword to add it.  It takes a symbol, a function,
a string or a list of strings.  If the path is relative, it is expanded
within ‘user-emacs-directory’.