I’m a backup nerd and like to back-up everything I do. Not just that, I like to version them too so I can go back in time to any point. git serves as a good tool for me for versioning wherever small data/text files etc are concerned and then I back this up with remote git servers like my own git server on a raspberry pi at home, a gitlab server and a github server. Prime targets for this are my dotfiles that I edit in spacemacs and my notes that I take in Joplin. The only issue though is that every time I change something, which is pretty often (since I’m a tinkering nerd too) I’ve to manually commit the changes and push them upstream. Apart from being all kinds of nerds, I’m an automation nerd too, which is a fancy way of saying that I am lazy, but I digress.

So, essentially I wanted to commit and push changes to my notes, dotfiles and few other things automatically whenever I make changes. I came across a tool called gitwatch, which can help do this. But I wanted to try out some more capabilities of Hammerspoon, so I chose that as my weapon of choice for this, especially because I already use it for few other automations so that’s one (or more) less things to install/maintain/update. Hammerspoon is an extremely powerful tool for macOS. In its own words:

At its core, Hammerspoon is just a bridge between the operating system and a Lua scripting engine. What gives Hammerspoon its power is a set of extensions that expose specific pieces of system functionality, to the user.

So, the things I had to do:

  • Setup the directories of my dotfiles (~/dotfiles/) and notes (~/.config/Joplin-desktop/) as git repositories (by running git init inside them)
  • Create repositories on GitHub (and other servers as needed) to backup them to. You can create them as private if you want to. In my case, my dotfiles are public but my notes are private.
  • Add the upstream repositories to your local git repositories as remotes (git remote add <somename> <remote_url>)
  • Add my ssh keys to the ssh-agent using the ssh-add command. You can read more about this here
  • Save the below lua script to ~/.hammerspoon/git-backup.lua
-- Paths to the directories we want to backup
local notes_path = "/Users/shantanugoel/.config/joplin-desktop"
local dotfiles_path = "/Users/shantanugoel/dotfiles"

-- The primary sync function
local function sync(path)
  if hs.fs.chdir(path) then
    output, status = hs.execute("git add . && git commit -am update", true)
    if status then
      output, status = hs.execute("git push -u origin master", true)
      if not status then
        -- Something went wrong! No internet? Didn't add ssh keys?
        hs.notify.show("Notes Sync", "Git Push Error", output)
      end
    end
  else
    -- Check if the path exists, just in case something goes wrong or you move to a new machine etc
    hs.notify.show("Notes Sync", "Cannot change Path", notes_path)
  end
end

local function notes_sync()
  sync(notes_path)
end

local function dotfiles_sync()
  sync(dotfiles_path)
end

-- Use pathwatcher to instantly sync whenever a change is made
notes_watcher = hs.pathwatcher.new(notes_path, notes_sync):start()
dotfiles_watcher = hs.pathwatcher.new(dotfiles_path, dotfiles_sync):start()

-- If you face perf issues with pathwatcher, comment out above 2 lines
-- and uncomment below lines to use a timed sync instead
-- Time interval is set to 5 minutes (300 seconds) here but can be changed
-- as per need
-- notes_timer = hs.timer.doEvery(300, notes_sync)
-- dotfiles_timer = hs.timer.doEvery(300, dotfiles_sync)
  • Update ~/.hammerspoon/init.lua to add this line: local gb = require('git-backup')
  • Reload hammerspoon config from its menu

I’ve commented the code as much as I could, so hopefully it makes sense. Now, this keeps me calm and focused on all the other procrastination that I’ve got to do :D