Git Notes as a Tool for Thought

Published See discussion on Twitter

While flying back out to the west coast for a week and a half "workation" - I stumbled across a brief tweet talking about git-notes. For those that don't know (and don't care to read through Git docs), git notes is a way to track additional free form content associated with commits, without editing/amending the underlying commit. From what I can tell - these are tracked separately from commits, but Git knows how to connect them behind the scenes.

While there's been other great blog posts about git notes (like this one that I recommend checking out), I wanted to write a bit about a failed idea to use this little used feature as a way to store a daily journal of sorts.

The rough idea was:

  • Create a single commit for each day (formatted nicely)
  • Append notes to that commit through out the day (as you see fit)
  • Each of the appended notes stashes the time at which the note was added, e.g. 9:15AM ET

And that's it! Plain and simple!

I was able to stub out a quick and very dirty Bun-flavored JavaScript snippet that could expose a simple CLI to manage these notes:

1// bun note.ts "something"
2// bun note.ts show
3
4import { readableStreamToText } from "bun";
5
6// git notes append --separator="\n---\n ### ${timestamp nicely formatted}"
7
8// commit each day
9// check if there is a commit for today or not
10// if not, create a commit
11
12// parse params
13let params = Bun.argv.slice(2);
14
15if (params.includes("show")) {
16 let {stdout} = Bun.spawn(["git", "notes", "show"],);
17 let text = await readableStreamToText(stdout);
18 console.log(text);
19 process.exit(0);
20}
21
22let message = params.join(" ");
23
24let dayFormatter = new Intl.DateTimeFormat("en-US", {
25 year: "numeric",
26 month: "2-digit",
27 day: "2-digit",
28}).format;
29
30let timeFormatter = new Intl.DateTimeFormat("en-US", {
31 hour: "2-digit",
32 minute: "2-digit",
33}).format;
34
35let day = dayFormatter(new Date());
36// check if current commit message matches the current date
37let res = Bun.spawnSync(["git", "log", "-1", "--pretty=%B"]);
38let commitMessage = res.stdout.toString();
39
40if (!commitMessage || !commitMessage.includes(day)) {
41 Bun.spawn(["git", "commit", "--allow-empty", "-m", day]);
42 Bun.spawn(["git", "notes", 'add', `\# ${day}`])
43}
44
45Bun.spawn([
46 "git",
47 "notes",
48 "append",
49 `--separator=\n\n---\n\n \#\#\# ${timeFormatter(new Date())}`,
50 "-m",
51 JSON.stringify(message),
52]);
1// bun note.ts "something"
2// bun note.ts show
3
4import { readableStreamToText } from "bun";
5
6// git notes append --separator="\n---\n ### ${timestamp nicely formatted}"
7
8// commit each day
9// check if there is a commit for today or not
10// if not, create a commit
11
12// parse params
13let params = Bun.argv.slice(2);
14
15if (params.includes("show")) {
16 let {stdout} = Bun.spawn(["git", "notes", "show"],);
17 let text = await readableStreamToText(stdout);
18 console.log(text);
19 process.exit(0);
20}
21
22let message = params.join(" ");
23
24let dayFormatter = new Intl.DateTimeFormat("en-US", {
25 year: "numeric",
26 month: "2-digit",
27 day: "2-digit",
28}).format;
29
30let timeFormatter = new Intl.DateTimeFormat("en-US", {
31 hour: "2-digit",
32 minute: "2-digit",
33}).format;
34
35let day = dayFormatter(new Date());
36// check if current commit message matches the current date
37let res = Bun.spawnSync(["git", "log", "-1", "--pretty=%B"]);
38let commitMessage = res.stdout.toString();
39
40if (!commitMessage || !commitMessage.includes(day)) {
41 Bun.spawn(["git", "commit", "--allow-empty", "-m", day]);
42 Bun.spawn(["git", "notes", 'add', `\# ${day}`])
43}
44
45Bun.spawn([
46 "git",
47 "notes",
48 "append",
49 `--separator=\n\n---\n\n \#\#\# ${timeFormatter(new Date())}`,
50 "-m",
51 JSON.stringify(message),
52]);

I've also pushed this script up to a repo here if you want to mess around with the concept more!

This is very naive - and probably has a number of issues - but seemed to work alright in some of my testing.

I called this a failed experiment because git notes feels incredibly "underbaked" compared to other git features. Maybe underbaked isn't the right phrase, but it's seen such low adoption that most tools don't support it, and it seems to break in some cases.

  • Notably - GitHub doesn't offer a way to see notes associated with commits in the web ui
  • You need to manually push and fetch these notes (kind of like tags) if you're sharing them with others
  • (probably a me problem) The version of Git by default on my mac (AppleGit) somehow didn't support most of the features - I had to brew install git to get the latest version with support for git notes append!
  • Amending a commit (even if not editing the message), will blow away all your notes!?

Anyway - it was an interesting little adventure to try out, but I think I'll be sticking with Obsidian for the time being, plus there have been quite a few useful git-backed note taking solutions out there that would work better.