Подпись коммитов
Как подписывать коммиты и теги Git с помощью GPG или SSH для подтверждения авторства и получения значка Verified.
Подпись коммита прикрепляет криптографическую подпись, которая доказывает кто его создал и что содержимое не было изменено. В этой главе объясняется, почему подписи важны, как сгенерировать ключ, как подписывать коммиты и теги с помощью GPG или SSH, как проверять подписи и как исправлять ошибки, с которыми вы, скорее всего, столкнётесь в первый раз.
Что именно доказывает подпись
По умолчанию имя автора и email в коммите — это просто текст. Git никогда не проверяет их — кто угодно может задать user.name и user.email любое значение (см. git config) и создать коммит, который претендует быть от чужого имени. Подпись меняет это: она создаётся с помощью закрытого ключа, который есть только у вас, и любой, кто имеет ваш соответствующий открытый ключ, может подтвердить два факта:
- Авторство — коммит действительно создан владельцем данного закрытого ключа.
- Целостность — если изменится даже один байт коммита (сообщение, дерево, родитель, автор), проверка завершится неудачей.
Для проектов, где происхождение важно — чувствительный к безопасности код, релизы с открытым исходным кодом, регулируемые среды — подписанная история позволяет рецензентам доверять тому, кто что написал. На GitHub и GitLab проверенная подпись даёт зелёный значок Verified рядом с коммитом.
Выбор GPG или SSH
Git поддерживает два формата подписи. Выберите один:
- GPG (OpenPGP) — традиционный вариант. Зрелый, широко поддерживаемый, но управление ключами (связки ключей, истечение срока действия, агент
gpg) требует привыкания. - SSH — доступен начиная с Git 2.34. Если вы уже используете SSH-ключ для push, можно повторно использовать его для подписи практически без дополнительной настройки. Проще в управлении, и теперь является рекомендуемой отправной точкой для большинства людей.
Сначала проверьте вашу версию:
git --versionПодпись с помощью GPG
Создание или поиск ключа
Если у вас ещё нет GPG-ключа, создайте его (оставьте настройки по умолчанию, выбрав 4096-битный RSA или ECC-ключ):
gpg --full-generate-keyВыведите список ключей и скопируйте длинный идентификатор ключа — значение после алгоритма в строке sec:
gpg --list-secret-keys --keyid-format=longsec ed25519/3AA5C34371567BD2 2024-01-08 [SC]
AB1C2D3E...
uid Jane Dev <[email protected]>Здесь идентификатор ключа — 3AA5C34371567BD2.
Настройка Git
git config --global user.signingkey 3AA5C34371567BD2
git config --global commit.gpgsign trueПодпись коммита или тега
При включённом commit.gpgsign каждый коммит подписывается автоматически. Чтобы явно подписать один коммит, используйте флаг -S в верхнем регистре:
git commit -S -m "Add audited payment handler"Чтобы подписать аннотированный тег, используйте -s в нижнем регистре:
git tag -s v2.0.0 -m "Signed release 2.0.0"-S (верхний регистр) подписывает коммит, а -s (нижний регистр) подписывает тег. В команде git commit строчный флаг -s добавляет строку Signed-off-by — это текстовый Developer Certificate of Origin, а не криптографическая подпись.Подпись с помощью SSH
Если у вас есть ключ id_ed25519 (или любой другой SSH-ключ), укажите Git путь к открытому ключу и переключите формат подписи:
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign trueКоммиты и теги теперь подписываются теми же флагами -S / -s, что и раньше — никаких других изменений не требуется.
Включение локальной проверки для SSH
В отличие от GPG, у Git нет встроенного хранилища доверия для SSH-ключей, поэтому git log --show-signature сообщает No principal matched, пока вы не создадите файл allowed signers. Сопоставьте каждый email с его открытым ключом:
mkdir -p ~/.config/git
echo "[email protected] $(cat ~/.ssh/id_ed25519.pub)" >> ~/.config/git/allowed_signers
git config --global gpg.ssh.allowedSignersFile ~/.config/git/allowed_signersЗагрузка открытого ключа на хостинг
Значок Verified появляется только после того, как хостинг получит ваш открытый ключ.
- GPG: скопируйте открытый ключ в формате ASCII Armor из
gpg --armor --export <key-id>и вставьте его в Settings → SSH and GPG keys → New GPG key. - SSH: добавьте содержимое
~/.ssh/id_ed25519.pubкак ключ типа Signing key (отдельно от ключа аутентификации) в той же области настроек.
Email в вашем ключе должен совпадать с email автора коммита, иначе хостинг покажет Unverified.
Проверка подписей
Проверяйте подписи локально любым из этих способов:
git log --show-signature # show signature status in the log
git verify-commit HEAD # verify one commit
git verify-tag v2.0.0 # verify a tagДля компактного вывода заполнитель %G? в git log выводит один код статуса на коммит:
git log --pretty="%h %G? %s"a1b2c3d G Add audited payment handler
d4e5f6g N Quick typo fixG означает хорошую (действительную) подпись, B — плохую, U — хорошую с неизвестной действительностью, N — отсутствие подписи.
Распространённые ошибки и их устранение
error: gpg failed to sign the data— обычно агент GPG не может запросить вашу парольную фразу. Экспортируйте терминал, который он должен использовать:export GPG_TTY=$(tty)(добавьте в~/.bashrcили~/.zshrc). На macOS установитеpinentry-mac, чтобы агент мог открыть диалог ввода пароля.gpg: signing failed: No secret key—user.signingkeyуказывает на неверный идентификатор. Проверьте повторно с помощьюgpg --list-secret-keys --keyid-format=long.- GitHub показывает Unverified — email автора коммита не совпадает с email, привязанным к загруженному ключу, или ключ не был добавлен на хостинг.
No principal matched(SSH) — вы не настроилиgpg.ssh.allowedSignersFile(см. выше).
Часто используемые параметры
| Команда | Описание |
|---|---|
git commit -S | Подписывает один коммит. |
git tag -s <name> | Создаёт подписанный аннотированный тег. |
git config commit.gpgsign true | Подписывает каждый коммит автоматически. |
git config gpg.format ssh | Подписывает с помощью SSH-ключа вместо GPG. |
git log --show-signature | Отображает статус подписи в логе. |
git log --pretty="%G?" | Выводит код статуса подписи для каждого коммита. |
git verify-commit <commit> | Проверяет подпись коммита. |
git verify-tag <tag> | Проверяет подпись тега. |