Skip to main content
Since people keep upvoting this outdated answer full of bad practices, I have removed its main text and replaced it with a much stronger advisory to use straight.el instead.
Source Link

WARNING: COMPLETELY WRONG/OBSOLETE, SEE THIS ANSWER!

The correct solution is to use straight.el, a package manager that I wrote to solve this problem. You can get as elaborate as you want with ensuring the portability of your setup.find more details about this in (I, personally, go for the "complete overkill" solutionanother answer to this question.)

Install packages automatically on Emacs startup

(Note: while I quite like my current setup, use-package looks extremely nice, and I'll probably be switching to it someday. See the other answers 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 whatdescribed briefly below; I do in myno longer recommend it.

Even if you don't want to use initstraight.el, you should at least adopt (full versionuse-package. here(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:

;;; Here we are using the defvar-nil-setq pattern described in [1],
;;; which makes it so that changes to this list will be picked up by a
;;; reload of init.el (M-RET r).
;;;
;;; [1]: http://ergoemacs.org/emacs/elisp_defvar_problem.html
(defvar radianmy-packages nil "The packages required by Radian.")
(setq radian-packages
       '(
        ace-jump-mode ; quickly jump to words, characters, or lines onscreen
        aggressive-indent ; keep code correctly indented at all times
         .
         .
         .
        projectile ; quickly jump to files organized by projectavy
        undo-tree ; more intuitive and powerful undo/redo
        ))
.
;; The cl-lib library provides `cl-every', which is used in the code
;; for determining if any packages need to be installed.
(require 'cl-lib)

;;; The following code will install any packages specified in
;;; `radian-packages' that are not already installed. It will only
;;; call `package-refresh-contents' if it is necessary to install a
;;; new package. The mainprojectile
 logic is based on [1].
;;;
;;; [1]: http://batsov.com/articles/2012/02/19/package-management-in-emacs-the-good-the-bad-and-the-ugly/

;; Since `package-archives', `package-pinnedundo-packages', andtree
;; `package-installed-p' are not autoloaded, we must explicitly load
;; package.el before using any of them.
(require 'package)

;; Add package repositories. GNU is the default repository; MELPA is
;; necessary to get most"List of the packages we are interested in.
(setq package-archives
   to be installed '(("gnu"at .Emacs "http://elpa.gnustartup.org/packages/")
        ("melpa" . "https://melpa.org/packages/")))

;; Initialize package.el. This is necessary to use
;;

Then install them automatically:

(require `package-installed'cl-p'.lib)
(package-initialize)
 
;; If any of the packages in `radian-packages' are not installed...
(unless (cl-every 'package#'package-installed-p radianmy-packages)
  ;; ... then make sure that we know about the latest versions of all
  ;;     the packages...
  (package-refresh-contents)
  ;; ... and install any packages that aren't already installed.
  (dolist (package radianmy-packages)
    (unless (package-installed-p package)
      (package-install package))))
      

KeepIf you keep your init.el file under version control and publish it to Github (or Dropbox, or ...). For example, you can see my repository here. When you switch to a new machine, clone the repository and link ~/.emacs.d/init.el to the file in the repository. This is what I do (except that the linking part is automated, more on that later).

Alternatively, you can clone the repository directly to your ~/.emacs.d folder. The disadvantage of this is that you have to make surethen syncing it to put everything Emacs might create in your .gitignore.

Either way, with this code installed, you can just drop your init.el file on another machine and start Emacs. All ofwill result in your packages will bebeing installed automatically. Instead of using M-x package-installOf course, you simply add the package name to the list defined in init.el and reload the file. Then the package is not onlyversions that are installed, but is guaranteed to always will be installed on any machine where you are using that init.el file.

Alternativelycompletely different, you can simply keep your entire ~/.emacs.d folder under version control (or at least most of it). This way you can have 100% control overand your setup, instead of relying on the MELPA servers to be able to download packages when they need toconfiguration can't be installed. The disadvantage of this is that you needexpected to manually update allwork out of your packages and createthe box as a commit every time you update anything.

You mention you have other .el files you've written yourselfresult. Personally, I prefer to keep everything inThis is a single file (namely,fundamental flaw of initpackage.el). I think this makes things simpler. But if you have other files, then you can just keep these under version control as well, and you will get them when you clone from another machine.

Automate deployment on another machine

This is one of the overkill partreasons why this approach is bad. You can see my scriptSee again herestraight.el. Given an arbitrary OS X machine, it will installNote also that the correct versions of all dependencies, back up any existing dotfiles, and make sure everything is symlinked correctly.

I actually go a step farther, and separate my dotfiles into two groups: public and private. My public dotfiles are published on Github as Radian, and they are meant to be usage by a wide range of people with different preferencescode outlined above separates your package list from me. I host my private dotfiles in Dropbox: these areyour configuration for settings specific to me and my filesystem, weird hacksthose packages, and other randommaking it harder to keep track of things.

To get started on a new machine, then, I install Dropbox, clone Radian, and run the setup script in your init-file. I'll be prompted for the location of my private dotfiles folder, and everything else will be set up automaticallyThis is another major disadvantage. I can then hit the ground running immediatelySee again use-package.

WARNING: COMPLETELY WRONG/OBSOLETE, SEE THIS ANSWER!

You can get as elaborate as you want with ensuring the portability of your setup. (I, personally, go for the "complete overkill" solution.)

Install packages automatically on Emacs startup

(Note: while I quite like my current setup, use-package looks extremely nice, and I'll probably be switching to it someday. See the other answers to this question.)

This is what I do in my init.el (full version here):

;;; Here we are using the defvar-nil-setq pattern described in [1],
;;; which makes it so that changes to this list will be picked up by a
;;; reload of init.el (M-RET r).
;;;
;;; [1]: http://ergoemacs.org/emacs/elisp_defvar_problem.html
(defvar radian-packages nil "The packages required by Radian.")
(setq radian-packages
      '(
        ace-jump-mode ; quickly jump to words, characters, or lines onscreen
        aggressive-indent ; keep code correctly indented at all times
         .
         .
         .
        projectile ; quickly jump to files organized by project
        undo-tree ; more intuitive and powerful undo/redo
        ))

;; The cl-lib library provides `cl-every', which is used in the code
;; for determining if any packages need to be installed.
(require 'cl-lib)

;;; The following code will install any packages specified in
;;; `radian-packages' that are not already installed. It will only
;;; call `package-refresh-contents' if it is necessary to install a
;;; new package. The main logic is based on [1].
;;;
;;; [1]: http://batsov.com/articles/2012/02/19/package-management-in-emacs-the-good-the-bad-and-the-ugly/

;; Since `package-archives', `package-pinned-packages', and
;; `package-installed-p' are not autoloaded, we must explicitly load
;; package.el before using any of them.
(require 'package)

;; Add package repositories. GNU is the default repository; MELPA is
;; necessary to get most of the packages we are interested in.
(setq package-archives
      '(("gnu" . "http://elpa.gnu.org/packages/")
        ("melpa" . "https://melpa.org/packages/")))

;; Initialize package.el. This is necessary to use
;; `package-installed-p'.
(package-initialize)
 
;; If any of the packages in `radian-packages' are not installed...
(unless (cl-every 'package-installed-p radian-packages)
  ;; ... then make sure that we know about the latest versions of all
  ;;     the packages...
  (package-refresh-contents)
  ;; ... and install any packages that aren't already installed.
  (dolist (package radian-packages)
    (unless (package-installed-p package)
      (package-install package))))

Keep your init.el file under version control and publish it to Github (or Dropbox, or ...). For example, you can see my repository here. When you switch to a new machine, clone the repository and link ~/.emacs.d/init.el to the file in the repository. This is what I do (except that the linking part is automated, more on that later).

Alternatively, you can clone the repository directly to your ~/.emacs.d folder. The disadvantage of this is that you have to make sure to put everything Emacs might create in your .gitignore.

Either way, with this code installed, you can just drop your init.el file on another machine and start Emacs. All of your packages will be installed automatically. Instead of using M-x package-install, you simply add the package name to the list defined in init.el and reload the file. Then the package is not only installed, but is guaranteed to always be installed on any machine where you are using that init.el file.

Alternatively, you can simply keep your entire ~/.emacs.d folder under version control (or at least most of it). This way you can have 100% control over your setup, instead of relying on the MELPA servers to be able to download packages when they need to be installed. The disadvantage of this is that you need to manually update all of your packages and create a commit every time you update anything.

You mention you have other .el files you've written yourself. Personally, I prefer to keep everything in a single file (namely, init.el). I think this makes things simpler. But if you have other files, then you can just keep these under version control as well, and you will get them when you clone from another machine.

Automate deployment on another machine

This is the overkill part. You can see my script here. Given an arbitrary OS X machine, it will install the correct versions of all dependencies, back up any existing dotfiles, and make sure everything is symlinked correctly.

I actually go a step farther, and separate my dotfiles into two groups: public and private. My public dotfiles are published on Github as Radian, and they are meant to be usage by a wide range of people with different preferences from me. I host my private dotfiles in Dropbox: these are for settings specific to me and my filesystem, weird hacks, and other random things.

To get started on a new machine, then, I install Dropbox, clone Radian, and run the setup script. I'll be prompted for the location of my private dotfiles folder, and everything else will be set up automatically. I can then hit the ground running immediately.

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.

Strengthen language
Source Link

WARNING: HEAVILY DEPRECATED IN FAVOR OFCOMPLETELY WRONG/OBSOLETE, SEE THIS ANSWER!

WARNING: HEAVILY DEPRECATED IN FAVOR OF THIS ANSWER!

WARNING: COMPLETELY WRONG/OBSOLETE, SEE THIS ANSWER!

deprecate
Source Link

WARNING: HEAVILY DEPRECATED IN FAVOR OF THIS ANSWER!

Install packages automatically on Emacs startup

Install packages automatically on Emacs startup

Automate deployment on another machine

Automate deployment on another machine

Install packages automatically on Emacs startup

Automate deployment on another machine

WARNING: HEAVILY DEPRECATED IN FAVOR OF THIS ANSWER!

Install packages automatically on Emacs startup

Automate deployment on another machine

add note about use-package
Source Link
Loading
Source Link
Loading