Patch changelogs with git-notes

Git notes [1] is a neat function that has been around since v1.6.6. Notes is a kind of metadata that belongs to a certain commit but is stored separately (different git object) from the commit itself. The fact that it's a separate git object is important, it will therefor keep the commit hash intact, and as a bonus - it has its own diff log.

Basic usage

git-notes has support for add, append, copy edit, list, prune, remove and show subcommands. These subcommands is rather self-explanatory, so I will not describe them any further.

add and edit fits almost all my needs, so I will stick to them.

First, create a git repository

mkdir gitnotes
cd gitnotes/
git init
echo testfile > test
git add test
git commit --signoff -m "Initial commit"
echo add-more-stuff >> test
git commit --signoff -a -m "Feature X"

We now have two commits:

commit bce22657cb5fd8353d43537e6b64422a8ce1107d (HEAD -> master)
Author: Marcus Folkesson <marcus.folkesson@gmail.com>
Date:   Sun Feb 11 21:56:17 2018 +0100

    Feature X

    Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>

commit 93726c3f6bf5c95faf969f040966b15d58d6fd0b
Author: Marcus Folkesson <marcus.folkesson@gmail.com>
Date:   Sun Feb 11 21:55:21 2018 +0100

    Initial commit

    Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>

Add a note

Add a note is simple:

git notes add -m "v2: update locking handling for Feature X"

We now have a note appended to our git log HEAD -1

commit bce22657cb5fd8353d43537e6b64422a8ce1107d (HEAD -> master)
Author: Marcus Folkesson <marcus.folkesson@gmail.com>
Date:   Sun Feb 11 21:56:17 2018 +0100

    Feature X

    Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>

Notes:
    v2: update locking handling for Feature X

Note that the SHA, bce22657cb5fd8353d43537e6b64422a8ce1107d, hasn't changed.

Edit a note

Edit a note is as simple as adding one:

git notes edit HEAD

When to use notes?

The first field of application is obvious, keep notes about individual commits. The kind of notes I usually use is comments during log reviews.

For the last year I have been using notes for a more practical use; patch change log history, which is an incredible powerful but undocumented (try to google it yourself) area of use for notes.

Patch format and changelogs

When talking about patches, the --- marker line serves the essential purpose of marking for patch handling tools where the commit message ends. One good use for the additional comments after the --- marker is for patch changelogs, which describe what has changed between the v1 and v2 version of the patch.

Rebase and amend

When working with patches, it's not unusual that it will take a few iterations until the patch set is in a ready-to-merge state. The way to rework patches is with an interactive rebase and amending.

A note is linked to a certain git object and this will be a problem with rebase and amend since it will overwrite that git object. With that said; if you amend your commit, the notes will disappear... unless... you configure git to rewrite the note upon amend and rebase.

From git-notes(1):

notes.rewrite.<command>

When rewriting commits with <command> (currently amend or rebase) and this variable is set to true, Git automatically copies your notes from the original to the rewritten commit. Defaults to true, but see notes.rewriteRef below.

notes.rewriteRef

When copying notes during a rewrite, specifies the (fully qualified) ref whose notes should be copied. The ref may be a glob, in which case notes in all matching refs will be copied. You may also specify this configuration several times.

Does not have a default value; you must configure this variable to enable note rewriting. Set it to refs/notes/commits to enable rewriting for the default commit notes.

This setting can be overridden with the GIT_NOTES_REWRITE_REF environment variable, which must be a colon separated list of refs or globs.

The manpage simply tells you to add these lines to your ~/.gitconfig or .git/config

[notes "rewrite"]
    amend = true
    rebase = true
[notes]
    rewriteRef = refs/notes/commits

To make amend and rebase rewrite the notes.

Generate patches

The best part is that git format-patch --notes will generate patches with appended notes after the --- marker.

For example: git format-patch --notes -1 -v2 will generate v2-0001-Feature-X.patch:

From bce22657cb5fd8353d43537e6b64422a8ce1107d Mon Sep 17 00:00:00 2001
From: Marcus Folkesson <marcus.folkesson@gmail.com>
Date: Mon, 19 Feb 2018 21:42:45 +0100
Subject: [PATCH v2] Feature X

Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---

Notes:
    v2: update locking handling for Feature X

 test | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test b/test
index 2691857..066c37d 100644
--- a/test
+++ b/test
@@ -1 +1,2 @@
 testfile
+add-more-stuff
--
2.15.1

This makes the patch workflow real smooth instead of manually track and update your patch changelogs.

My typical workflow

/media/git-patch-workflow.png

Other tricks

Note logs

Even notes has a log (all objects in refs/XXX has), and it could be useful to see how your notes has evolved over time:

git log -p notes/commits

Push and fetch notes

The notes itself is stored as git object in .git/refs/notes. A thing to keep in mind is that refs/notes is not pushed by default, but that is not a problem - my opinion is that notes should be local only anyway.

If you really want to push your notes, you can to that with

git push <remote> refs/notes/*

and fetch them with

git fetch origin refs/notes/*:refs/notes/*