2.2 Bootstrapping

(As mentioned in the next section you can use a location other than ~/.config/emacs (or ~/.emacs.d). Nevertheless most of the subsequent examples just talk about ~/.config/emacs and if you use something else, then obviously have to substitute that. The same applies to the string lib and the variables user-init-file and user-emacs-directory, which also might not be appropriate depending on your choices.)

2.2.1 Bootstrapping using a seed

To get started clone the repository of the emacs.g collective. A "collective" is a starter-kit and/or configuration seed that relies on Borg as the package manager. Most users end up using emacs.g merely as a bootstrapping seed and do not merge upstream changes after that.

This collective already assimilates a few drones in addition to borg itself, namely magit, epkg, use-package, auto-compile, git-modes and diff-hl, as well as their dependencies. These drones are not required by borg but their use is highly recommended.

Clone the emacs.g repository to either ~/.config/emacs, or for testing purposes to any other location. This repository contains a Makefile that imports lib/borg/borg.mk and defines an additional target whose purpose is to make that file and lib/borg/borg.sh available. Run make bootstrap-borg to clone the borg repository. That does not completely setup borg but it makes the latest version of the mentioned files available.

Now that these files are available you can run make bootstrap to get and configure all submodules (including the borg submodule) and to build all drones.

git clone git@github.com:emacscollective/emacs.g.git ~/.config/emacs
cd ~/.config/emacs
make bootstrap-borg
make bootstrap

If you have assimilated many packages, you might want to use make bootstrap | tee bootstrap.log.

The last command run during bootstrap is git submodule status, which prints one line per module. If a line is prefixed with ‘+’, that means that it was not possible to checkout the recorded commit, and - means that the module could not be cloned. Even if some module could not be cloned, that usually does not render a configuration unusable, so just run emacs now, and then investigate any issues from the comfort of Magit.

If you cloned to somewhere other than ~/.config/emacs, then you can use that configuration using emacs --init-directory /path/to/emacs.g/, provided you are using Emacs 29 or later. Otherwise you have to resort to emacs -Q -l /path/to/emacs.g/early-init.el -l /path/to/emacs.g/init.el.

For drones whose upstream repositories are located on Github or Gitlab the emacs.g collective uses the ssh protocol by default, which is a problem if you don’t have accounts there and have not properly setup your keys. See Using https URLs.

During package compilation you may notice the submodules relating to those packages become dirty due to the compilation outputs not being ignored in those submodules. For this reason it is useful to ignore these outputs globally, for example in your ~/.config/git/ignore file:

*.elc
*-autoloads.el
dir

You may discover more things that you’ll want to ignore this way as you use borg.

2.2.2 Bootstrapping from scratch

If you don’t want to base your configuration on the emacs.g starter-kit described in the previous section, then you have to do a few things manually.

git init ~/.config/emacs
cd ~/.config/emacs

By default Borg installs packages inside the lib/ subdirectory, but since you are starting from scratch, you may choose something else by setting the Git variable borg.drones-directory locally for this repository.

Then you should add a Makefile containing at least:

DRONES_DIR = $(shell git config "borg.drones-directory" || echo "lib")

-include $(DRONES_DIR)/borg/borg.mk

bootstrap-borg:
        @git submodule--helper clone --name borg --path $(DRONES_DIR)/borg \
        --url git@github.com:emacscollective/borg.git
        @cd $(DRONES_DIR)/borg; git symbolic-ref HEAD refs/heads/main
        @cd $(DRONES_DIR)/borg; git reset --hard HEAD

Now you are probably tempted to run make bootstrap-borg, but that is for bootstrapping from a seed, and what we are doing right now is to bootstrap from scratch. In the process we are creating a seed but we are not there yet. Instead run this:

git submodule add --name borg git@github.com:emacscollective/borg.git lib/borg

Now that borg is available we can build all the assimilated packages (currently just borg itself) using make bootstrap.

Now it is time to tell Emacs to initialize Borg instead of Package by adding a simple init.el file containing at least:

(when (< emacs-major-version 27)
  (setq package-enable-at-startup nil))
(add-to-list 'load-path (expand-file-name "lib/borg" user-emacs-directory))
(require 'borg)
(borg-initialize)

Beginning with Emacs 27.1, package-enable-at-startup has to be disabled earlier, in early-init.el:

(setq package-enable-at-startup nil)

Now you could create the initial commit but you could also delay that.

git commit -m "Assimilate borg"

Now it is time to assimilate some other essential packages. You could do so using M-x borg-assimilate, but you would quickly notice that doing so without the help of the epkg package is quite cumbersome, so lets manually install that and its dependency first:

git submodule add --name closql git@github.com:emacscollective/closql.git lib/closql
git submodule add --name emacsql git@github.com:magit/emacsql.git lib/emacsql
git submodule add --name compat git@github.com:emacs-compat/compat.git lib/compat
git submodule add --name llama https://git.sr.ht/~tarsius/llama lib/llama
git submodule add --name epkg git@github.com:emacscollective/epkg.git lib/epkg
git config -f .gitmodules submodule.emacsql.no-byte-compile emacsql-pg.el
echo /epkgs/ >> .gitignore
git add .gitignore .gitmodules
make build
git commit -m "Assimilate epkg and dependencies"

Once you have done that and have restarted Emacs, you can install Magit using Borg, as described in Assimilation. You should also configure Magit status buffers to display submodules:

(with-eval-after-load 'magit
  (magit-add-section-hook 'magit-status-sections-hook
                          'magit-insert-modules
                          'magit-insert-stashes
                          'append))

Finally (look, nobody forced you to do this from scratch ;-) I strongly suggest that you make yourself familiar with my auto-compile package.

2.2.3 Migrating a legacy configuration

If you are currently using Package and want to gently ease into using Borg alongside that, then you can proceed as described in Use as secondary package manager.

If on the other hand you are already manually using Git modules, then you should proceed as described in Bootstrapping from scratch. Obviously "from scratch" does not apply this time around, so just skip steps like git init.

2.2.4 Using your configuration on another machine

Getting started using your existing configuration on another machine works the same way as described in Bootstrapping using a seed. The only difference is that instead of starting by cloning someone else’s repository you start by cloning your own repository.

2.2.5 Using https URLs

For drones whose upstream repositories are located on Github or Gitlab the emacs.g collective uses the ssh protocol by default, which is a problem if you don’t have accounts there and have not properly setup your keys.

Luckily this can easily be fixed using the following global rules.

git config --global url.https://github.com/.insteadOf git@github.com:
git config --global url.https://gitlab.com/.insteadOf git@gitlab.com:

If you don’t want to configure this globally, then you can also configure Borg itself to prefer the https URLS.

(setq borg-rewrite-urls-alist
      '(("git@github.com:" . "https://github.com/")
        ("git@gitlab.com:" . "https://gitlab.com/")))

This does not affect packages that have already been assimilated. During bootstrapping you have to change the URLs for packages that are assimilated by default.

cd ~/.config/emacs
sed -i "s|git@github.com:|https://github.com/|g" .gitmodules
sed -i "s|git@gitlab.com:|https://gitlab.com/|g" .gitmodules
git commit -m "Use https URLs for Github and Gitlab"

If you have already run make bootstrap, then you also have to edit .git/config.

cd ~/.config/emacs
sed -i "s|git@github.com:|https://github.com/|g" .git/config
sed -i "s|git@gitlab.com:|https://gitlab.com/|g" .git/config