Подпись коммитов подтверждает, что изменения внесли именно вы, а не кто-то с вашим именем в git config. В open source это давно норма: ядро Linux и Debian требуют подписанные теги, а многие компании включают проверку в защищённых ветках. Настроить GPG-подпись в Linux — задача на полчаса, но только если сразу разобраться с агентом, TTY и форматом ключа. Ниже — рабочий порядок для Linux Mint, Ubuntu и любой системы с GnuPG 2.2 и новее.
Зачем это нужно
git по умолчанию доверяет полю author. Любой может поставить ваше имя и почту и отправить коммит. Подпись GPG привязывает коммит к ключу, а значит, к человеку, который контролирует приватную часть. Проверка помогает в трёх сценариях: аудит истории, защита релизных тегов и требование репозитория.
Подпись не шифрует код и не заменяет code review. Она отвечает только на вопрос, кто автор и не менялись ли байты после подписи.
Создание ключа
Для подписи достаточно ключа с возможностью sign, отдельный encrypt не нужен. Ed25519 короче и быстрее RSA, но старые системы могут его не понимать; для максимальной совместимости берите RSA 4096.
gpg --quick-generate-key "Ivan Petrov <ivan@example.com>" ed25519 sign 2y
gpg --list-secret-keys --keyid-format=long
gpg --fingerprint ivan@example.com
gpg --armor --export-secret-keys ivan@example.com > secret.asc
Вторая команда покажет строку вида sec ed25519/ABCD1234EF567890. Это короткий ID, но для настройки лучше взять полный отпечаток из вывода gpg —fingerprint. Срок 2y означает два года: после истечения подпись перестанет считаться валидной, поэтому напоминание в календаре обязательно. Файл secret.asc нужен только для офлайн-бэкапа, его нельзя коммитить, класть в облако без шифрования или отправлять в чат.
Настройка git
Четыре параметра связывают git с ключом. Первый выбирает ключ, второй включает подпись по умолчанию, третий задаёт программу, четвёртый распространяет правило на теги.
git config --global user.signingkey ABCD1234EF567890
git config --global commit.gpgsign true
git config --global tag.gpgSign true
git config --global gpg.program gpg
Если в системе только gpg2, подставьте его. Проверьте, что почта в user.email совпадает с адресом в ключе: GitHub и GitLab сопоставляют подпись с аккаунтом именно по нему, и при несовпадении коммит получит статус Unverified.
git config --global user.name
git config --global user.email
gpg --list-keys --keyid-format=long ivan@example.com
Подпись коммитов и тегов
При включённом commit.gpgsign флаг -S не нужен, но его полезно знать: он подписывает один коммит, не меняя глобальные настройки. Тег подписывается отдельно: флагом -s или автоматически при включённом tag.gpgSign.
git commit -m "Fix network config"
git commit -S -m "Hotfix for dhcp pool"
git tag -s v1.4.0 -m "Release 1.4.0"
git log --show-signature -1
Вывод содержит строку Good signature и отпечаток ключа. Если вместо неё написано No signature, подпись не создалась или вы смотрите на коммит, сделанный до настройки. Старые коммиты автоматически не подписываются: при необходимости их переписывают интерактивным rebase, но это меняет хеши и требует согласования с командой.
Публикация ключа
Локальной подписи мало: получателю нужен ваш публичный ключ. Его добавляют в GitHub, GitLab или на keyserver. Для сайта и репозитория достаточно armored-файла.
gpg --armor --export ABCD1234EF567890 > public.asc
gpg --keyserver keyserver.ubuntu.com --send-keys ABCD1234EF567890
git verify-commit HEAD
git verify-tag v1.4.0
В GitHub ключ вставляют в Settings → SSH and GPG keys → New GPG key. Экспортируйте по отпечатку, а не по короткому ID, чтобы не перепутать ключи с похожими окончаниями. Публичный ключ можно смело публиковать, приватный — никогда.
Срок жизни ключа — не формальность. Продление делается командой gpg —edit-key, затем expire: старые подписи остаются валидными, если ключ не отозван. Отзыв — отдельный сценарий. Revocation-сертификат создаётся при генерации и лежит в ~/.gnupg/openpgp-revocs.d; если ключ скомпрометирован, сертификат импортируют и публикуют, после чего проверки помечают подпись как revoked. Храните его отдельно от секретного ключа.
В команде достаточно, чтобы каждый подписывал свои коммиты, а CI проверял сам факт подписи; строить паутину доверия внутри компании обычно не требуется.
Проверка на стороне получателя
Коллега или CI может проверить каждый коммит в диапазоне. Для этого импортируют публичный ключ и доверяют ему.
gpg --import public.asc
git verify-commit HEAD
git log --show-signature --pretty="%h %G? %s" -5
git log --format="%h %G? %s" origin/main..HEAD
Символ G означает хорошую подпись, B — плохую, U — неизвестный ключ, N — отсутствие подписи, E — ошибку проверки. В CI удобно проверять всю ветку перед слиянием и падать, если найден N или B. Для защищённой ветки включите Require signed commits в GitHub или push rule в GitLab.
Если подпись не создаётся
Самая частая ошибка — «gpg failed to sign the data» на сервере или в tmux. Причина в pinentry: агенту негде спросить пароль. Решение — выставить GPG_TTY и перезапустить агент.
export GPG_TTY=$(tty)
echo "test" | gpg --clearsign
gpgconf --kill gpg-agent
git config --global gpg.program "$(command -v gpg)"
Строку с GPG_TTY добавляют в конец ~/.bashrc, иначе она не подхватится в новых сессиях. В контейнерах и CI используйте batch-импорт и loopback-pinentry, а пароль передавайте через секрет переменной окружения, не через аргумент командной строки: аргументы видны в списке процессов.
Альтернатива: SSH-подписи
Git 2.34 и новее умеет подписывать коммиты тем же SSH-ключом, что и доступ к серверу. Это проще, если GPG вы не используете, но проверка требует файла allowed_signers.
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers
git log --show-signature -1
В allowed_signers добавляют строку вида ivan@example.com ssh-ed25519 AAAA… — почта, пробел, тип ключа и сам ключ. GitHub принимает SSH-подписи, но не все старые клиенты их понимают, поэтому в смешанной команде лучше договориться об одном формате и записать это правило в README.
Чек-лист
- Ключ с возможностью sign, срок и напоминание о продлении.
- user.email совпадает с адресом в ключе.
- commit.gpgsign и tag.gpgSign включены глобально.
- Публичный ключ добавлен в GitHub или GitLab.
- Резервная копия секретного ключа и revocation-сертификата лежит офлайн.
- CI проверяет подписи в защищённых ветках.
Итог
Подпись коммитов — это несколько команд и одна привычка: проверять git log —show-signature после настройки. Начните с ed25519 или RSA 4096, добавьте ключ в Git-хостинг и включите обязательную проверку в защищённой ветке. Тогда история перестанет быть набором анонимных строк и станет проверяемой.