There are usually two files I creat when starting a new project: a file for organizing tasks, and a CHANGELOG file for keeping tabs on what I've done. I don't limit myself to only writing about direct file changes; I also use it to keep notes about overall changes I've made.

Here's a snippet from the CHANGELOG I use for this site:

An example CHANGELOG file

It's not exactly thrilling stuff, but it's handy when looking over traffic numbers to see if any changes I made worked. Or not.

change-log-mode works fine without additional configuration, but there are a few options to tweak. I also wrote some functions to add projectile integration.

Configuring your name and email address

Calling add-change-log-entry will insert a new date heading with your name and email address.

There are two variables to modify what is inserted:

  • add-log-full-name - The full name to use.
  • add-log-mailing-address - The email address to use.

Something like this will set both of variables:

(setq add-log-full-name       "My name"
      add-log-mailing-address "")

Emacs will attempt to figure your name or email if either of these are nil.

Configuring the default file name

change-log-mode looks for "ChangeLog" by default, but I use "CHANGELOG". Setting change-log-default-name will modify this behaviour:

(setq change-log-default-name "CHANGELOG")

Configuring indentation sizes

The default indentation width is a little large for my tastes, so I add this to my configuration file to narrow things:

(add-hook 'change-log-mode-hook
	  (lambda ()
	    (make-local-variable 'tab-width)
	    (make-local-variable 'left-margin)
	    (setq tab-width   2
		  left-margin 2)))

Alternatively these can be set inside a ".dir-locals.el" file if you don't want to change the global behaviour:

((change-log-mode . ((tab-width   . 2)
		     (left-margin . 2))))

Adding projectile integration

I use projectile a lot, so I wanted to make it easier to add log entries from within a project. I wrote two functions for this:

This opens the CHANGELOG file for the current projectile project.
This works the same way as add-change-log-entry, but it automatically selects the project CHANGELOG instead of prompting for a file name.

The full code is below:

(defun sodaware/project-changelog-path ()
  "Get the full path to the current project's changelog file, or NIL if not found."
  (let ((change-log-file (concat (projectile-project-root)
				 (file-name-nondirectory change-log-default-name))))
    (if (file-exists-p change-log-file)

(defun sodaware/projectile-goto-project-changelog ()
  "Open the CHANGELOG for the current project."
  (let ((change-log-file (sodaware/project-changelog-path)))
    (if change-log-file
	(find-file change-log-file)
	(message "Project does not contain a changelog file."))))

(defun sodaware/projectile-add-to-project-changelog ()
  "Add a new entry to the CHANGELOG for the current project."
  (let ((change-log-file (sodaware/project-changelog-path)))
    (if change-log-file
	  (find-file change-log-file)
	(message "Project does not contain a changelog file."))))

I added key bindings for both of these functions because I don't want to type that much:

(use-package projectile
  :diminish projectile-mode
  (:map projectile-mode-map
	("C-c p G" . sodaware/projectile-goto-project-changelog)
	("C-c p L" . sodaware/projectile-add-to-project-changelog))
  (projectile-keymap-prefix     (kbd "C-c p"))
  (projectile-enable-caching    t)
  (projectile-completion-system 'default))