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.

2
  • 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, 2014 at 6:33
  • Don't exclude *.elc. stackoverflow.com/a/24539894/324105
    – phils
    Oct 5, 2014 at 4:59

8 Answers 8

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.

9
  • 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, 2014 at 7: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, 2014 at 7: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, 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 3, 2014 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 emacs.stackexchange.com/a/410/184 may be helpful as well.
    – T. Verron
    Oct 3, 2014 at 18:00
  • 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 9, 2014 at 2:25
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.

1
  • 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 6, 2017 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
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.

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
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.

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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