69

Like many people, I manage a lot of my dotfiles via a version control repository (Mercurial on Bitbucket, private, in my case). This is handy when setting up a new machine or propagating configurations among different machines.

So naturally I added my .emacs and .emacs.d to this setup.

Then I installed some packages, and ended up adding *.elc to my .hgignore, just like I omit *.pyc files from my Python repos.

Are there other things I shouldn't be tracking, e.g. generated files that are environment specific and won't be useful/correct when cloned to another platform? (I use Linux and OS X on the desktop, and FreeBSD on the server.)

Are there any setup tricks that are commonly used to make this kind of sharing more valuable? With my shell file setup I'm still looking for good ways to cherry-pick individual files across branches for example.

jch
  • 5,680
  • 22
  • 39
Paul Bissex
  • 833
  • 8
  • 9
  • Just FYI, Despite what is said below, if you use the same emacs version on all your computers, syncing the Elpa directory is perfectly fine. – Malabarba Sep 26 '14 at 06:33
  • Don't exclude `*.elc`. http://stackoverflow.com/a/24539894/324105 – phils Oct 05 '14 at 04:59

8 Answers8

40

I store my Emacs configuration in GitHub because I use two different computers, one at work, one at home.

Here is a list about things that I don't put into source control:

Environment specified setups.

For example, my Emacs open different org file on start-up at different machine. You don't want to commit these settings into source control.

I use (require 'local nil t) to load these settings, but never commit local.el.

Packages that managed by package manager

When packages are managed by package manager, I suggest not to put those packages into source control. Because :

  1. You have to commit after every update.
  2. You can miss important file that store somewhere else, which make you unable to synchronize across different computer properly.

Instead of commit packages, I suggest you commit the mechanism which recognized by your package manager.

For example, I use Cask to manage my 3rd packages, so I only commit the cask file, which contains specified packages I want.

When I use package.el before, my configuration will check whether package is installed/need to updated, so no package is committed.

However, there are some packages that does not exist in any package repository, in this case, I will commit it to the source control, such as in site-lisp.

All the files generated by packages

For example, all the autosave, backup files, tramp, eshell, recentf, even custom.el. I put these files into ~/.emacs/.gen, so I can just ignore this directory.

Files that change frequently but required to be synchronized

Such as personal dictionary file used by aspell, file database used by elfeed, In these case, I use Dropbox to synchronized it across different computers. So I won't forget to commit.

shynur
  • 4,065
  • 1
  • 3
  • 23
Rangi Lin
  • 987
  • 9
  • 15
  • 2
    The point about Cask is ok as long as you only work with machines which support Cask, most notably not Windows. – T. Verron Sep 26 '14 at 07:49
  • Some people may okay to commit packages after every update, if not I suggest don't store the whole package. Let package manager do the job. – Rangi Lin Sep 26 '14 at 07:59
  • @T.Verron I was able to make Cask work on Cygwin, but it gave me *some* trouble. BTW, I'm now using [Emacs Prelude](https://github.com/bbatsov/prelude), and I found oud the `prelude-require-packages` function works as a poor man's Cask (with the advantage of also working with Windows). – rsenna Oct 03 '14 at 17:48
  • Does cygwin cask work with w32 emacs? When it comes to macros emulating this behavior, the built-in `package-install` mentioned in http://emacs.stackexchange.com/a/410/184 may be helpful as well. – T. Verron Oct 03 '14 at 18:00
  • I change some of my answer about package manager, because I don't want to make an impression that I am suggesting use `Cask`, because it doesn't matter. – Rangi Lin Oct 04 '14 at 03:03
  • Why `custom.el` too? – shackra Oct 08 '14 at 20:19
  • 2
    @JorgeArayaNavarro It is perfectly fine to commit it if they will be the same across different machines. :) but it is not in my case. What's more, since it will be edited automatically, sometime I forget to commit, that's why I don't put `custom.el` into source control. – Rangi Lin Oct 09 '14 at 02:25
  • I disagree about not committing environment specific files. For instance if I have certain code that is specific to a OS, computer, or even user, I commit all of it and simply load them conditionally based on the values of `system-type`, `system-name`, and `user-login-name`. Of course some things, like functions that could expose information about my companies software are part of a separate repo that is only loaded if it exists on the current machine. – Jordon Biondo Jun 09 '15 at 20:49
  • Hi @JordonBiondo that's basically what I mean, things in `local.el` are mostly trivial stuff that override default value. – Rangi Lin Jun 10 '15 at 03:05
12

tl;dr

  • use .emacs.d/init.el instead of .emacs
  • make your .gitignore a white list
  • use a package manager

.emacs.d/init.el

I use .emacs.d/init.el instead of .emacs since this setup allows me to put .emacs.d under git. Having ~/.emacs makes you to create a symbolic link to git repository or to have git repo at your home directory. If you use .emacs.d, all is solved.

.gitignore

My .gitignore is white listing instead of the default black listing.

*

!.gitignore
!init.el

This configuration allows you to concentrate on what you really need instead of what you don't need. .emacs.d is not like source code repository, meaning that not only your code resides but also all other auto-generated or temporary files goes there. You don't really know what will go in. So, "ignore all by default and add files you care" is better strategy, IMO.

BTW, I keep most of configuration in the init.el, instead of using multi-file scheme. The reason is that a big file allows me to a) use standard tools like occur or isearch-forward to move to the configuration I want, b) use outshine which makes my init.el org-cycle-able, c) not change my .gitignore all the time.

Package Manager

Unless you have special needs to sync Emacs version and or Packages version on all your system, do not put packages under git. Package.el is fine. use-package is also fine. Cask is nice. Pick your package manager and commit only your configuration file but not the package itself.

ie. One of special needs I can think of would be to have two systems, a development and deployment and they must have exactly the same Emacs configuration.

Yasushi Shoji
  • 2,151
  • 15
  • 35
  • Keeping everything in one `init.el` file works as long as that file doesn't get too big. Emacs is not good at handling large files, and after a while it just starts to crawl when editing a large `init.el`. Another advantage of splitting your config in to multiple files is that they play better with git, which in certain situations can consider changes to a single file to be a merge conflict, but not so if the changes are in separate files. Finally, it's a lot easier to comment out just single requires than big chunks of your init file. – izkon Oct 06 '17 at 17:51
8

Just make sure no generated stuff (like @rangi-lin notes) is in the repo and, if you're sharing your dotfiles with others, no related security stuff (like passwords and API keys). For the later I've split my customizations into a separate file with:

(setq custom-file (concat dotfiles-dir "custom.el"))
(load custom-file 'noerror)

Occasionally I move "safe" customizations to a big setq statement before the snippet above.

My .gitignore file looks like:

/.org-id-locations
/ac-comphist.dat
/auto-save-list
/custom.el
/elpa/*
/image-dired/
/oauth2.plstore
/session.*
/tramp
/url/
/var/
*.elc
remvee
  • 561
  • 6
  • 13
6

I have the following things in my .hgignore

  • emacs server file
  • recentf file: File paths on one machine do not make sense on another
  • elpa/melpa directory: Use init file to automatically install required packages and save pull/push times.

If you want to share your init with others, you might consider removing any history files such as the one created by savehist mode. Apart from that I do not think there are any special tricks to this. Any guidelines you follow for versioning code projects work well here as well.

Vamsi
  • 3,916
  • 22
  • 35
3

Over the time packages add a lot of things to ~/.emacs and I end up adding them one by one to my .gitignore. I also have a private.el which contains passwords, machine specific code etc which I dont track.

This is what I have now.

# Gitignore file

# Remove backup files
*#
*.
*.elc
*~
.#*

# Emacs packages
elpa/
var/

#  Emacs tmp files & Misc
/.mc-lists.el
/.DS_Store
/.emacs.desktop
/.emacs.desktop.lock
/.watsonresults
/ac-comphist.dat
/auto-save-list
/eshell/history
/eshell/lastdir
/newsticker/feeds/
/snippets/
/tramp
/url/cookies
/.python-environments/
/ido.last
/places
/private.el
/games/
/bookmarks
/projectile-bookmarks.eld
/projectile.cache
Jaseem
  • 261
  • 1
  • 6
1

It depends on which packages/features you use, so it can get tricky. Beside the files mentioned by Vamsi, for example, if you use dired-immage, it creates a directory there to cache thumbnails. You probable want to ignore .elc files too.

rlazo
  • 983
  • 8
  • 13
1

I publish my .emacs.d, but use a subrepo with the private changes (passwords and such). To allow others to clone it, the default branch points to a placeholder subrepo, and every machine has its own named branch.

When merging between machines, I first graft the new changes into the default branch and then merge the default branch into the other workplace branches.

As example, you can find my .emacs.d on bitbucket, including a readme with a short usage guide.

You might want to add the org-mode merge driver to this setup.

1

After several iterations, I have determined that, while version control is great for sharing code and tracking changes, it's not a great solution for syncing a rapidly-changing configuration across computers. The reason is that there are many things that should be synced and should not be in version control. Some examples:

  1. .elc files (recompiling them when there's a configuration change is a major hassle, and bugs from outdated elc files are often a pain to debug).
  2. The entire elpa directory (and until version-pinning becomes standard, automatically rebuilding it just isn't reliable enough).
  3. Auto-generated files such as eshell history and gnus files.
  4. Private information such as passwords and API keys.

(Note that cross-platform issues aren't in the list--it should be perfectly fine to have one configuration that works across multiple operating systems.) Instead of using git as a syncing solution, I use it solely as a code tracking solution and sync using Dropbox. That way, all the annoying files that shouldn't be in version control are taken care of.

I do, however, have a goal of having my configuration be rebuildable from source if my Dropbox configuration disappears for whatever reason, so I keep track of all the installed packages and whatnot in the source. My private information is stored in a git submodule as well. But for day-to-day syncing, git just isn't a great solution.

shosti
  • 5,048
  • 26
  • 33