Notational Velocity + Git = team note sharing

Introduction

I work in a small, but highly productive, agile software development team at Didit Search Engine Marketing. We are always looking for processes and tools that make collaboration and knowledge sharing more efficient for us.

Notational Velocity is a Mac application for creating and searching through notes. It features a very fast incremental search and it has no save button. When you start a new note or edit an existing note, your data is always saved automatically. The incremental search means that as you type anything in the search bar, the content and titles of all notes are searched for a match. It also has the ability to sync with Simple Note, which is a great, thin, online note service. This makes it easy to carry all your notes with you on your smartphone using the Simple Note app.

Combining the simple search and save capabilities of Notational Velocity with the decentralized source control of git makes a lightweight (fully open source) team note sharing system. Best of all, we can each still have private notes that are not shared. In fact, by default, notes are not shared. To share a note, you name it with a special prefix agreed on by the team. More on that below.

By the end of this tutorial, you will have shared note system viewable and searchable using Notational Velocity where new notes form team members appear automatically. Additionally, you will be notified right inside Notational Velocity when you have a shared note that needs to published for other team members to view.

Let’s jump right in with the configuration. In order to follow these instructions, you will need some understanding of git and of using the terminal on Mac.

Notational Velocity Setup

Download and install Notational Velocity here. When you first launch it, you will see a screen that looks like this:

The first thing you need to do is to change how notes are saved. In order to be used in conjunction with git, you want to have NV (Notational Velocity is just too long to type out every time) save your notes as individual plain text files. By default, NV stores data in a single file. This is beneficial in that you can encrypt this file, but does not work well for file sharing. Choose the “Notational Velocity -> Preferences” menu:

Click on the “Storage” tab and select “Plain Text Files” from the dropdown

We experimented with the different formats that NV provides and found the plain text was the best for our needs. This format has the added benefit of being readable on a webpage within github or of being cloned by authorized non-NV (Windows) users.

Git Setup

For the git setup, you will need to launch the terminal program on your Mac.

Switch to the directory that NV stores it’s notes and data files. By default, this will be:

cd ~/Library/Application Support/Notational Data

Note: The backslashes () are important as they are escaped spaces.

Initialize a git repository:

git init

The next step is critical in ensuring that the files you want to share make it up to your git repository. Create a .gitignore file and put the following into it:

1
2
*
!didit*

The purpose of .gitignore is to specify which files should not be included in your git repo. Git responds to regular expressions. The way to read the above code is:

1) Ignore all files
2) Don’t ignore files that start with the characters: didit

You can substitute your own identifier for “didit”. This means that any files that have the identifier (didit) at the beginning of the name will be included in the git repo.

As a test of the configuration, create a file that starts with the identifier you specified in the .gitignore file. Here’s a  file listing in the NV data folder. It includes the files that are setup with NV by default as well as the test file that I created.

total 32K
drwxr-xr-x  10 msilverman2 62075185  340 Jul 20 21:43 .
drwx------+ 76 msilverman2 62075185 2.6K Jul 12 11:53 ..
drwxr-xr-x   9 msilverman2 62075185  306 Jul 20 21:43 .git
-rw-r--r--   1 msilverman2 62075185   10 Jul 12 17:52 .gitignore
-rw-r--r--   1 msilverman2 62075185  138 Jul 12 11:53 Contact Information.txt
-rw-r--r--   1 msilverman2 62075185 1.1K Jul 12 11:53 Excruciatingly Useful Shortcuts.txt
-rw-r--r--   1 msilverman2 62075185  887 Jul 12 11:53 How does this thing work?.txt
-rw-r--r--   1 msilverman2 62075185 6.0K Jul 13 09:22 Notes & Settings
-rw-r--r--   1 msilverman2 62075185  630 Jul 12 11:53 This is the title of a note.txt
-rw-r--r--   1 msilverman2 62075185   16 Jul 20 21:43 didit - test note.txt

Running git status produces the following output:

# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#	didit - test note.txt
nothing added to commit but untracked files present (use "git add" to track)

Notice the one file that I created with the “didit” identifier in the file name. If you see any other files included in the output from git status, check your .gitconfig configuration.

Next, add the file and commit it using the standard git commands:

git add -A .
git commit -m "Initial Revision"

You can now publish your inited git project to a remote repository. This can be a dedicated server or a repo on github. NOTE: If you are using github you will most likely want a private repository so that the world can’t see your NV notes.

For the purposes of this configuration example, we will use github as the remote repository. We’ll briefly describe the setup below, but there are lots of good references on how to setup remote repositories both on github and on a private server.

Login to github.com and click on the “New Repository” button. Give your repo a name and optional description and url. Click the “Create Repository” button.

You can now register the remote repository in your NV data directory that you have initialized for git:

git remote add origin git@github.com:/.git

This is what it looks like for me:

git remote add origin git@github.com:dogeared/Notational-Velocity-Sync-Test.git

Finally, you can push up your changes – the initial commit of the one file in this case – to the remote repository.

git push -u origin master

Anyone on your team who wants to share notes can perform the same setup steps with one exception: after the git remote add origin command, new users will want to do a git pull to sync with the remote repository.

If you’ve followed everything up until this point, you now have git setup so that git pull will get any new notes that members of your team have shared and git push will push your new notes to the remote repository for other users. You can see both your private notes and the shared notes in Notational Velocity and can take advantage of all the features NV has to offer.

The last steps outlined below make it so that pulls and pushes are automatic and so that Notational Velocity itself gives you feedback on when you have new notes that need to be committed. We toyed with the idea of automatically committing new notes, but decided against it. This allows people to work on a note and share it when they are ready.

Auto pull/push and notifier script

First, here is the script. We will break it down below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash
 
#### CHANGE THE FOLLOWING 2 LINES TO MATCH YOUR ENVIRONMENT ###
NV_NOTES_PATH=~/Library/Application Support/Notational Data
GIT_PATH=/usr/local/bin
#### DO NOT CHANGE ANYTHING BELOW THIS LINE ####
 
STAT_FILE="YOU HAVE NEW FILES TO SYNC.txt"
cd "$NV_NOTES_PATH"
$GIT_PATH/git pull
$GIT_PATH/git push
 
GIT_STATUS=`$GIT_PATH/git status`
 
if [[ "$GIT_STATUS" =~ "nothing to commit" ]]
then
  if [ -e "$STAT_FILE" ]
  then
    rm "$STAT_FILE"
  fi
else
  echo "$GIT_STATUS" > "$STAT_FILE"
fi

The script performs three functions:

1) pull in the latest notes from the remote repository
2) push your latest committed notes to the remote repository
3) notify you via NV itself when you have new or edited uncommitted notes

Lines 4 and 5 specify the location of your NV data and the location of your git executable, respectively. These may be different on your machine, so this section of the script should be edited accordingly.

Line 8 specifies the file name that will be used to notify you when you have new or edited uncommitted notes.

Line 9 switches into the NV data directory.

Line 10 pulls in changes from the remote repository.

Line 11 pushes out committed changes to the remote repository.

Line 13 uses the git command to get the status of the NV data directory.

Here’s an example of the output after I made some changes:

# On branch master
# Changed but not updated:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#	modified:   didit - test note.txt
#
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#	didit - test note 2.txt
no changes added to commit (use "git add" and/or "git commit -a")

Line 15 tests to see if the output contains the text: “nothing to commit”.

If there is nothing new to commit, lines 17 – 20 ensures that the STAT_FILE is deleted from the system, if it exists.

If there are files that need to be committed, line 22 writes the status information to the file specified by STAT_FILE.

You may be asking, “What’s going on here?”. Here’s the beauty of it: The STAT_FILE is being created inside the NV data directory. Also, its name is NOT anything that would be included by git because of the .gitignore file. Any file in the NV data directory will be shown in the NV application. Also, NV arranges notes by descending date by default. This means that you will see this file at the top of your list of files in the NV application. This is a very lightweight notification system to let you know that you have notes that should be shared (because of their filename) that have not yet been committed to the repository.

Here’s a screenshot of what this looks like in Notational Velocity:

At this point, you would go to the NV data directory and commit your changes.

git add -A .
git commit -m "My latest changes"

git status now returns the following:

# On branch master
nothing to commit (working directory clean)

As per our script, lines 15 – 20 will ensure that the STAT_FILE is removed. Once that file is removed, it will also be removed from the NV application.

The first time the file is deleted by the script, you may see this alert from the NV application:

Click the checkbox and click the Delete button to ensure that the STAT_FILE file can be deleted without any further manual intervention from you in the NV application.

Here is a screenshot of the NV application after the changes have been committed to the repository:

The final step in automating the system is to get your Mac to automatically run the shell script at regular intervals. This ensures the least amount of manual intervention on your part and makes it much more likely that you and your team will make use of this system.

launchd is not cron

While Mac OSX supports the traditional UNIX cron, it is not the preferred method of running programs at intervals. An exhaustive discussion of the newer launchd system is outside the scope of this tutorial, but we will review the necessary steps to get the NV sync script to run at intervals.

Launchd works off of xml files called plist files. Here’s the plist file we will be using to run our shell script every 5 minutes. As before, we will break this down line by line.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>nv_sync</string>
  <key>UserName</key>
  <string>msilverman2</string>
  <key>Program</key>
  <string>/Users/msilverman2/sync_notational_velocity.sh</string>
  <key>StartInterval</key>
  <integer>300</integer>
  <key>Debug</key>
  <true/>
  <key>AbandonProcessGroup</key>
  <true/>
</dict>
</plist>

The core of the plist file is made up of keys and values where values can have different types. In our case, most of the values are string type, but we also have integer and true types.

The Label key on line 5 has a value of nv_sync on line 6. The Label is used in other commands to refer to this launchd definition.

The UserName key on line 7 should specify your local username for the string value on line 8.

The Program key on line 9 should refer to the full path of your shell script for the string value on line 10.

The StartInterval key on line 11 should specify a number of seconds for the integer value on Line 12. This is how long to wait before the program is run again. There are more complex calendar specifications that you can use with launchd, but we have a simple requirement here: just run every 5 minutes.

Setting Debug set to true on lines 13 and 14 gives us more logging output in /var/log/system.log when something goes wrong.

Setting AbandonProcessGroup to true on lines 15 and 16 tells launchd to leave any child processes running instead of killing them. This can be potentially dangerous if you have something that doesn’t exit properly, but this ensures that all of our calls to git will be run and not get clobbered by launchd.

You should save this plist file to the: /Library/LaunchDaemons folder. Let’s call it: sync_notational_velocity.plist

To tell launchd to install this plist file, you execute the following:

launchctl load /Library/LaunchDaemons/sync_notational_velocity.plist

Once this is done, if you look for nv_sync in /var/log/system.log, you should see the system attempting to run your script every 5 minutes. If anything has gone wrong, you should get some indication of what the problem is in the system log.

Summary

Using git, Notational Velocity and a small shell script along with the OS’s built in interval runner provides your team with a lightweight note sharing system. When setup properly, you will be able to view private and shared notes in Notational Velocity. Through Notational Velocity, you will see a notification note when you have uncommitted changes to shared notes. Synchronization of committed shared notes will happen automatically. As an added bonus, if there are members of your team or authorized people outside your team with access to your git repository, they can always clone the project and view or add notes of their own.



One Response to “ “Notational Velocity + Git = team note sharing”

  1. Jeff Borisch says:

    This is very slick. I was searching to see if anyone had done this already. You took it way further than I was planning on. Thanks for the ideas.

Leave a Reply