Незаконное руководство по git notes и показания к применению

Nikita Shubin <[email protected]>

Незаконное руководство по git notes и показания к применению

Команда git notes позволяет манипулировать заметками к коммиту, не меняя при этом его хэш.

Simply because notes namespaces are not something special in git, they are just ordinary branches with complete history. You can do

git notes, фактически это отдельные отдельные “ветки”, расположенные в .git/refs/notes, они не отображаются командой git branch. Их можно сравнить с orphan branches - немного похоже, но коммиты в refs/notes/*, содержат ссылки на деревья, которые в свою очередь содержат блобы с именами коммитов (любых - как из регулярных деревьев, так и из refs/notes/*).

$ git init
$ git config user.name "John Doe"
$ git config user.email [email protected]
$ git add README.md
$ git commit -m "root commit"
$ git add file1
$ git commit -m "add file1"
$ git add file2
$ git commit -m "add file2"
$ git add file3
$ git commit -m "add file3"

Предположим у нас есть такой проект (специально положил все файлы в корень проекта, чтобы избежать лишних деревьев в графе):

git-initial

Добавим к нему git notes:

git notes add HEAD~3 -m "Hello Note One!"
git notes add HEAD~2 -m "Hello Note Two!"
git notes add HEAD -m "Hello Note HEAD!"

git log по умолчание выводит notes из refs/notes/commits, это поведение контролируется переменной окружения GIT_NOTES_REF или ключом конфигурации core.notesRef:

$ git --no-pager log
commit 54eb62cfb827810077391650c5434a4082db4276 (HEAD -> master)
Author: John Doe <[email protected]>
Date:   Thu Mar 31 16:19:04 2022 +0300

    add file3

Notes:
    Hello Note HEAD!

commit d7ddbc3ac210ca0199ac6605b02e4b0c35e126ac
Author: John Doe <[email protected]>
Date:   Thu Mar 31 16:19:04 2022 +0300

    add file2

commit bea58b9b945d27fad5d0779a4b86e5e33fbcc9e9
Author: John Doe <[email protected]>
Date:   Thu Mar 31 16:19:04 2022 +0300

    add file1

Notes:
    Hello Note Two!

commit 46794ca99c524be1bd300ba7e830bf2611229fcf
Author: John Doe <[email protected]>
Date:   Thu Mar 31 16:19:04 2022 +0300

    root commit

Notes:
    Hello Note One!

Для начала убедимся, что это ветка:

$ git checkout notes/commits
$ git --no-pager log --oneline
c958b65 (HEAD, refs/notes/commits) Notes added by 'git notes add'
14967b4 Notes added by 'git notes add'
a048c64 Notes added by 'git notes add'

И построим граф, теперь уже для ветки notes/commits:

git-initial-notes-tree

Как мы видим это объекты коммитов, ну да кто бы сомневался, а это значит, что мы можем добавить note к уже существующему note !

$ git notes add c958b65 -m "I Am A Note To A Note!"
$ git --no-pager show c958b65
commit c958b65a4027b566a341903c27a6d020484a7666 (HEAD)
Author: John Doe <[email protected]>
Date:   Fri Apr 1 12:12:58 2022 +0300

    Notes added by 'git notes add'

Notes:
    I Am A Note To A Note!

diff --git a/54eb62cfb827810077391650c5434a4082db4276 b/54eb62cfb827810077391650c5434a4082db4276
new file mode 100644
index 0000000..c7aa303
--- /dev/null
+++ b/54eb62cfb827810077391650c5434a4082db4276
@@ -0,0 +1 @@
+Hello Note HEAD!

$ git --no-pager log notes/commits
commit 36438c1388cad56e020327a11918cc96d5c567dd (refs/notes/commits)
Author: John Doe <[email protected]>
Date:   Fri Apr 1 12:45:23 2022 +0300

    Notes added by 'git notes add'

commit c958b65a4027b566a341903c27a6d020484a7666 (HEAD)
Author: John Doe <[email protected]>
Date:   Fri Apr 1 12:12:58 2022 +0300

    Notes added by 'git notes add'

Notes:
    I Am A Note To A Note!

commit 14967b4531613477caad3d45d5c639b952218fc4
Author: John Doe <[email protected]>
Date:   Fri Apr 1 12:12:58 2022 +0300

    Notes added by 'git notes add'

commit a048c6403d67a71b4f0279a54f7c3bbbf904eee0
Author: John Doe <[email protected]>
Date:   Fri Apr 1 12:12:58 2022 +0300

    Notes added by 'git notes add'

Граф при это поменялся не сильно, просто верхний коммит теперь указывает на дерево, которое в свою очередь указывает на четыре blob’a.

git-add-note-to-note

Если внимательно посмотреть на дерево первого коммита в notes/commits, то мы увидим следующее:

$ git cat-file -p 5c0584bf4fe93ca289827ba9d2d5557f7356c207
100644 blob 58589bd2a9c6361fe31740a7f4c6e73fb7663e9c    46794ca99c524be1bd300ba7e830bf2611229fcf

При этом содержимым блоба будет являться текст самой записки:

$ git cat-file -p 58589bd2a9c6361fe31740a7f4c6e73fb7663e9c
Hello Note One!

А имя файла 46794ca это ничто иное как коммит к которому относится записка.

$ git cat-file -p 46794ca99c524be1bd300ba7e830bf2611229fcf
tree 9bd9e28a95ee603c5e584689c84d6b9c4acee7cd
author John Doe <[email protected]> 1648732744 +0300
committer John Doe <[email protected]> 1648732744 +0300

root commit

Бесконечное число refs/notes/*

По умолчанию используется refs/notes/commits

Число записок никак не ограничено, можно создать refs/notes/

Default git notes namespace

merge git-notes

$ git notes --ref commits-new add -m "Merge me note"
$ git --no-pager log --show-notes="*" HEAD^..HEAD
commit 56fb198260e598ec762be8ed7b158c0ded4a3585 (HEAD -> master)
Author: John Doe <[email protected]>
Date:   Mon Apr 4 10:05:06 2022 +0300

    add file3

Notes:
    Hello Note HEAD!

Notes (commits-new):
    Merge me note

Попытка смержить два дерева notes, приведет к конфликту:

$ git notes merge commits-new
Auto-merging notes for 56fb198260e598ec762be8ed7b158c0ded4a3585
CONFLICT (add/add): Merge conflict in notes for object 56fb198260e598ec762be8ed7b158c0ded4a3585
Automatic notes merge failed. Fix conflicts in .git/NOTES_MERGE_WORKTREE and commit the result with 'git notes merge --commit', or abort the merge with 'git notes merge --abort'.
$ cat .git/NOTES_MERGE_WORKTREE/56fb198260e598ec762be8ed7b158c0ded4a3585
<<<<<<< refs/notes/commits
Hello Note HEAD!
=======
Merge me note
>>>>>>> refs/notes/commits-new
$ git notes merge --abort

Конфликт легко разрешим руками (поддержки mergetool в git notes отсутствует), либо можно задать стратегию для merge (по умолчанию manual):

$ git notes merge --strategy=union commits-new
$ git --no-pager log --show-notes="*" HEAD^..HEAD
commit 56fb198260e598ec762be8ed7b158c0ded4a3585 (HEAD -> master)
Author: John Doe <[email protected]>
Date:   Mon Apr 4 10:05:06 2022 +0300

    add file3

Notes:
    Hello Note HEAD!

    Merge me note

Notes (commits-new):
    Merge me note

git notes и cherry-pick

Показания к применению

Мета информация

Сюда может входить информация о сборках, включая путь к артефакту. Можно убрать сюда привязку к тикету, чтобы убрать из текста коммита отвратительные номера Jira, Gitlab, чего угодно.

Некоторые инструменты сохраняют здесь данные, например дополнительную информацию о конвертации из subversion в git.

Комментарии и обсуждения

Поскольку к коммиту из notes можно привязывать опять же коммит из notes, это позволяет создавать, хоть целые ветки форумов или хранить в таком формате архив mail-lists.

Поддержка в git веб-мордах

Bitbucket

Нет и не предвидится: https://jira.atlassian.com/browse/BSERV-5450

Есть подтухший плагин: https://github.com/daveychu/git-notes-plugin

Gitlab

Нет и не предвидится: https://gitlab.com/gitlab-org/gitlab/-/issues/15029

Gogs, Gitee

Опять же нет.

Что осталось за кадром

Визуализаторы для обучения