16

I'm a beginner in Emacs (using it for about 2 weeks now and loving it). As I update and expand my ~/.emacs.d/init.el file, the things that I write in there depend on certain packages that I installed from MELPA using M-x package-install, on .el files that I've written myself, etc.

My question is, should I in the future switch computers for example, what is the best way to seamlessly get the same exact Emacs environment on the new computer as I have now?

  • 3
    As long as you can move your init.el around (using git for example), this approach also works (based on use-package): lunaryorn.com/posts/… – VanLaser Oct 17 '16 at 17:01
  • One approach is to put your .emacs.d directory in Dropbox. I've only used it across computers with the same OS. Different flavors o f*nix should be ok, but you might have problems if you try to share across machines running OSes that are too different. – Qudit Oct 18 '16 at 22:29
  • This question is very close to emacs.stackexchange.com/q/408/2710 . Can you highlight the differences? – Andrew Swann Oct 21 '16 at 17:43
  • For the non-programmer such as myself, synchronizing emacs configuration and packages across three machines (two windows, one OSX) using Google Drive has been effective and reliable. This works because emacs and most of its packages are largely platform agnostic. Cross platform reproduction of an identical emacs experience requires only a few lines in the init.el file to resolve OS specific paths to the synchronized emacs package directory. – Snelephant Jul 18 '17 at 19:18
  • Your config is your entire ~/.emacs.d directory, so use whatever method you prefer to synchronise that between machines. (e.g. a Github repository, or a Dropbox folder, or whatever works best for you). – phils Jun 20 '18 at 1:26
9

The correct solution is to use straight.el, a package manager that I wrote to solve this problem. You can find more details about this in another answer to this question.

This answer, which was written months before I started work on straight.el, previously described a strictly inferior way of achieving a partial solution. This approach is described briefly below; I no longer recommend it.

Even if you don't want to use straight.el, you should at least adopt use-package. (Not that the two are mutually exclusive—I believe the cleanest setup comes from using both.)


Start by defining a list of packages in your init-file:

(defvar my-packages
        '(
          aggressive-indent
          avy
           .
           .
           .
          projectile
          undo-tree
          )
  "List of packages to be installed at Emacs startup.")

Then install them automatically:

(require 'cl-lib)
(package-initialize)
(unless (cl-every #'package-installed-p my-packages)
  (dolist (package my-packages)
    (unless (package-installed-p package)
      (package-install package))))

If you keep your init.el file under version control, then syncing it to another machine will result in your packages being installed automatically. Of course, the versions that are installed will be completely different, and your configuration can't be expected to work out of the box as a result. This is a fundamental flaw of package.el, and is one of the reasons why this approach is bad. See again straight.el. Note also that the code outlined above separates your package list from your configuration for those packages, making it harder to keep track of things in your init-file. This is another major disadvantage. See again use-package.

  • Thanks for the write-up! If I choose to host everything on Github, including the packages I downloaded from MELPA, will this retain MELPA's capability of auto-updating the packages on the new computer? – space_voyager Oct 17 '16 at 19:04
  • 1
    @space_voyager Yes, everything will still happen the same way. However: (1) when you clone to a new computer, Emacs won't need to download packages from MELPA, because they are already in the repository you just cloned; and (2) whenever you use package.el to update packages, you will have unstaged changes in your repository, and you will have to make a commit to include the package updates. – Radon Rosborough Oct 17 '16 at 19:36
  • Great, thanks. One more thing: I thought MELPA does package updates automatically. Is this not the case? – space_voyager Oct 17 '16 at 19:49
  • 1
    @space_voyager: Well, of course the remote package repository will be updated, but the updated versions of the packages are not downloaded and installed on your local machine automatically. For that you need to M-x list-packages RET U. – Radon Rosborough Oct 17 '16 at 20:06
  • 1
    @Lassi Short answer: use whatever you want to install Emacs; use straight.el only to install Emacs packages. Nix is a great idea, but it's not well-optimized for Emacs package development, as far as I know (please correct me if I'm wrong). If you use a system package manager to install Emacs packages, you won't be able to just edit their source code and then commit and push your changes upstream. Last time I looked at a Nix configuration for Emacs packages, it seemed overly complex and generally inferior to the straight.el development experience. But, whatever floats your boat. – Radon Rosborough Jun 17 at 3:55
11

If you use use-package, you can move that file around from computer to computer, and when Emacs starts up, as long as you have internet access, it will pull in the packages and configure them.

First, set up the package library:

(require 'package)
(add-to-list 'package-archives
             '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)

And then bootstrap use-package:

(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

(eval-when-compile (require 'use-package))

Now, instead of configuring Emacs and assuming packages are installed, use use-package to both install and configure them. For example, for some of my helm settings:

(use-package helm
  :ensure t
  :bind (("M-x" . helm-M-x)
         ("M-y" . helm-show-kill-ring)
         ("C-x C-f" . helm-find-files)
         ("M-s o" . helm-occur))

  :config
  (helm-mode 1)
  (setq helm-echo-input-in-header-line t))
  • Mind you, that gets the configuration (in init.el) across, but there's lots more to it. For example, this wont' port the dabbrev files, or your custom snippets or any of a ton of other thing. – Omair Majid Oct 17 '16 at 18:18
  • Yes. If you have other files that are part of your configuration, you'll have to move them too, alongside your init file. – zck Oct 17 '16 at 19:35
  • at that point, it again becomes a game of "which file is actually part of my configuration and how do I keep it in sync across my machines" :( – Omair Majid Oct 17 '16 at 20:24
  • you should add :ensure t to the use-package declaration or set use-package-always-ensure to t. Otherwise it wouldnt automatically install on another system when copied the config over. – Chakravarthy Raghunandan Oct 19 '16 at 20:11
5

Next-generation package management with straight.el

After a long and frustrating struggle to use package.el + Quelpa to manage my packages, I bit the bullet and wrote my own package manager. It is intended to completely replace package.el by providing a package management experience that is superior in almost every way.

You can read the very extensive documentation to learn about all of its features, but the most relevant one to this question is that straight.el focuses on perfect reproducibility. This means it should not matter whether you are starting Emacs normally, or starting it on a new machine, and that any local changes are version-controlled and can be reverted to a canonical state. Practically speaking, this is achieved by (1) cloning packages as Git repositories, and providing automated tools for managing their state; (2) using the init-file as the sole source of truth for package management state, with no mutable data stored elsewhere; and (3) using optional version lockfiles to specify exact Git revisions of every package, plus any recipe repositories and straight.el itself.

To get started, insert the bootstrap snippet, which will install and activate straight.el. Then, to ensure that a package is installed, simply place a call to straight-use-package in your init-file:

(straight-use-package 'projectile)

Yes, it's that simple. No dealing with package-refresh-contents or any of that garbage. If you remove this form from your init-file and restart Emacs, Projectile will no longer be loaded (unlike in package.el). This means you do not have to worry about your configuration somehow not working on a new machine because you accidentally depended on undeclared packages.

You can install packages whereever and whenever you would like, throughout your init-file (no need to declare a list of them at a single point). Of course you can also just do

(dolist (package '(ace-jump-mode ... zzz-to-char)) (straight-use-package package))

if you prefer the list. I however recommend that you use use-package to manage your package configuration. First you have to install it:

(straight-use-package 'use-package)

Then, since straight.el has built-in integration with use-package, the following "just works":

(use-package projectile
  :straight t
  :init (projectile-mode 1))

Once you've written your init-file to install the packages it needs, run M-x straight-freeze-versions to save a version lockfile to ~/.emacs.d/straight/versions/default.el. You should keep this file under version control, since it will allow straight.el to check out the correct versions of all your packages, when you first launch Emacs on a new machine. (You can manually revert to the versions specified in the lockfile using M-x straight-thaw-versions.)

To support the idea of machine-local dotfiles that I mentioned in my other answer, straight.el offers a profile system. I still recommend using symlinks for your dotfiles (in this case, init.el, your local init-file if applicable, and the version lockfile if you want to use one).

If you're wondering how straight.el compares with other package managers, check out the extensive comparisons section. But there is lots more documentation on everything else, too.

4

You can use cask to manage your packages. Use git/github to source control and sync your emacs dotfiles.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.