Незаконное руководство по 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 johndoe@example.com
$ 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 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 <johndoe@example.com>
Date: Thu Mar 31 16:19:04 2022 +0300
add file3
Notes:
Hello Note HEAD!
commit d7ddbc3ac210ca0199ac6605b02e4b0c35e126ac
Author: John Doe <johndoe@example.com>
Date: Thu Mar 31 16:19:04 2022 +0300
add file2
commit bea58b9b945d27fad5d0779a4b86e5e33fbcc9e9
Author: John Doe <johndoe@example.com>
Date: Thu Mar 31 16:19:04 2022 +0300
add file1
Notes:
Hello Note Two!
commit 46794ca99c524be1bd300ba7e830bf2611229fcf
Author: John Doe <johndoe@example.com>
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:
Как мы видим это объекты коммитов, ну да кто бы сомневался, а это значит, что мы можем добавить 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 <johndoe@example.com>
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 <johndoe@example.com>
Date: Fri Apr 1 12:45:23 2022 +0300
Notes added by 'git notes add'
commit c958b65a4027b566a341903c27a6d020484a7666 (HEAD)
Author: John Doe <johndoe@example.com>
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 <johndoe@example.com>
Date: Fri Apr 1 12:12:58 2022 +0300
Notes added by 'git notes add'
commit a048c6403d67a71b4f0279a54f7c3bbbf904eee0
Author: John Doe <johndoe@example.com>
Date: Fri Apr 1 12:12:58 2022 +0300
Notes added by 'git notes add'
Граф при это поменялся не сильно, просто верхний коммит теперь указывает на дерево, которое в свою очередь указывает на четыре blob’a.
Если внимательно посмотреть на дерево первого коммита в 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 <johndoe@example.com> 1648732744 +0300
committer John Doe <johndoe@example.com> 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 <johndoe@example.com>
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 <johndoe@example.com>
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
Опять же нет.
Что осталось за кадром
- git notes append (смысл для неё тот же самый, что и для git add)
- любой blob в качестве note (пример есть в официальной документации)
- git notes copy (смысл и синтаксис вполне очевиден)
Визуализаторы для обучения
- https://github.com/hoduche/git-graph
- https://github.com/functicons/git-graph
- https://github.com/git-school/visualizing-git
- https://git-scm.com/docs/git-notes
- https://gist.github.com/dnclive/8399055
- https://alblue.bandlem.com/2011/11/git-tip-of-week-git-notes.html
- https://gerrit.googlesource.com/plugins/reviewnotes/%2B/master/src/main/resources/Documentation/refs-notes-review.md
- https://blog.adamspiers.org/2013/10/02/more-uses-for-git-notes/
- https://www.ibm.com/docs/en/elm/6.0?topic=git-associating-work-items-commits
- https://dev.to/leehambley/effortlessly-maintain-a-high-quality-change-log-with-git-notes-4bm5
- https://stackoverflow.com/questions/45672799/get-all-notes-for-a-commit-including-their-author-and-committer
- https://stackoverflow.com/questions/17018267/why-parent-is-stored-in-git-notes
- https://stackoverflow.com/questions/52202916/find-commit-with-specific-git-note
- https://stackoverflow.com/questions/18273879/git-get-the-commit-id-and-the-note-of-a-commit
- https://rubicotech.com/blog/advanced-git-features/
- https://github.com/functicons/git-graph
- https://stackoverflow.com/questions/14585613/is-there-a-way-to-automatically-merge-notes-if-commits-for-those-notes-get-squas
- https://github.com/aspiers/git-config/blob/master/bin/git-rnotes