От SHA-1 к SHA-256: переход на новый хеш

Рейтинг: 67.2% · 18 голосов
Самый подробный курс по Git - от первого коммита до объектной базы и packfiles. Терминал и первый репозиторий, ветки и слияние, конфликты, удалённая работа и форджи (GitHub, GitLab), rebase и переписывание истории, спасение кода через reflog и fsck, stash и worktree, bisect и blame, подмодули и монорепо, хуки и подпись коммитов, внутреннее устройство и масштаб. Для новичков и профи. Актуально на 2026 (Git 2.54, дорожная карта 3.0).
Ответить
Аватара пользователя
Pavel_Git
Сообщения: 52
Зарегистрирован: 11 май 2026, 05:31

От SHA-1 к SHA-256: переход на новый хеш

Сообщение Pavel_Git »

Оглавление курса (52)
  1. Что такое контроль версий и почему победил Git
  2. Установка Git на Windows, macOS и Linux и первая настройка
  3. Терминал и как спрашивать у Git: выживание в командной строке
  4. Ментальная модель Git: три состояния, коммит-снимок и граф
  5. Первый репозиторий: init, add, commit, status
  6. Просмотр изменений: status, diff и индексация по частям
  7. История проекта: git log, диапазоны и поиск
  8. .gitignore: что не должно попасть в репозиторий
  9. .gitattributes: окончания строк, бинарники и атрибуты
  10. Ветки как указатели: branch, switch и detached HEAD
  11. Слияние веток: fast-forward против трёхстороннего merge
  12. Конфликты слияния: анатомия и уверенное разрешение
  13. Практикум: твой первый день с Git от нуля до push
  14. Удалённые репозитории: remote, fetch, базовый pull и refspec
  15. git push: безопасная отправка и защита от перезаписи
  16. Клонирование: shallow, partial clone, bundle и backfill
  17. GitHub, GitLab и форки: pull request, rulesets и защита веток
  18. Рабочие процессы команды: GitFlow, GitHub Flow, trunk-based
  19. Merge queue и merge trains: безопасное вливание в trunk
  20. Культура code review и Conventional Commits
  21. git reset: три дерева и отмена индексации и коммитов
  22. git revert: безопасная отмена в общей истории
  23. Правка последнего коммита: git commit --amend
  24. git rebase: пересадка истории и золотое правило
  25. Интерактивный rebase: переписать серию коммитов
  26. git cherry-pick: перенос отдельных коммитов
  27. Stacked diffs: цепочка зависимых PR
  28. Массовое переписывание истории: git filter-repo и git replace
  29. git reflog: журнал, который помнит всё
  30. Восстановление утерянных коммитов, веток и файлов
  31. Откат опасных операций: reset --hard, сломанный rebase, плохой merge
  32. git stash: тайник для незавершённой работы
  33. git worktree: несколько рабочих деревьев одного репозитория
  34. git bisect: бинарный поиск регрессии
  35. git blame, mailmap и археология кода
  36. Теги, релизы, archive и bundle
  37. Подмодули: внешние репозитории внутри проекта
  38. Subtree, монорепозитории и sparse-checkout
  39. Git LFS и большие файлы
  40. Вспомогательные команды: clean, mv, rm, restore
  41. Псевдонимы и кастомизация .gitconfig
  42. Хуки Git: автоматизация на клиенте и сервере
  43. Подпись коммитов и тегов: SSH, GPG и Sigstore
  44. Внутреннее устройство I: объектная база Git
  45. Внутреннее устройство II: ссылки, HEAD, notes и reftable
  46. Внутреннее устройство III: индекс, packfiles, gc и обслуживание
  47. От SHA-1 к SHA-256: переход на новый хеш (вы здесь)
  48. Огромные репозитории: partial clone, FSMonitor, Scalar
  49. Git в CI/CD: shallow, кеш, merge_group и безопасность
  50. Куда движется Git: дорожная карта 3.0 и экосистема
  51. Профессиональный setup: собираем рабочее окружение Git
  52. 30+ типичных ошибок Git и как из них выбираться
Если ты дошёл до этого урока, то уже знаешь: внутри Git каждый объект - коммит, дерево, блоб, тег - адресуется хешем. Ты сотни раз видел эти 40-символьные строки в git log, git show, в выводе любой команды. Это не просто "айдишник" - это содержимое объекта, прогнанное через криптографическую хеш-функцию. И до недавнего времени этой функцией был SHA-1.

Проблема в том, что SHA-1 сломан. Не "теоретически устарел", а реально сломан: в 2017 году исследователи показали практическую коллизию. А раз вся модель Git построена на предположении "разный контент - разный хеш", это бьёт в самый фундамент. Поэтому Git мигрирует на SHA-256, и в 2026 году это перестало быть экзотикой для параноиков - это мейнстрим, который вот-вот станет дефолтом. В этом уроке разберём, что именно хранит git хеш, почему shattered git так напугал сообщество, как устроена безопасность git хеш и что конкретно тебе делать на практике.

Что вообще хранит хеш и почему это про целостность, а не шифрование

Сразу убьём частое заблуждение. Хеш в Git - это не шифрование. Ничего не шифруется, ключей нет, расшифровать обратно нельзя в принципе. Хеш - это отпечаток содержимого: берём байты объекта, прогоняем через функцию, получаем строку фиксированной длины. Поменялся хоть один байт - отпечаток меняется полностью.

Давай посмотрим руками, что именно хешируется. Возьмём блоб (содержимое файла):

Код: Выделить всё

$ printf 'hello\n' | git hash-object --stdin
ce013625030ba8dba906f756967f9e9ca394464a
Откуда взялась именно эта строка? Git не хеширует голые байты файла. Он добавляет заголовок вида "тип пробел размер нольбайт", и только потом контент. Проверим вручную через системный sha1sum:

Код: Выделить всё

$ printf 'blob 6\0hello\n' | sha1sum
ce013625030ba8dba906f756967f9e9ca394464a  -
Совпало. Вот она, вся "магия": , пробел, длина (это "hello" плюс перевод строки), нулевой байт-разделитель, потом сам контент. Для коммита туда попадает дерево, родители, автор, дата и сообщение - поэтому хеш коммита зависит вообще от всего, включая историю предков. Поменяй одну букву в сообщении коммита месячной давности - и хеши всех коммитов после него поедут, потому что каждый ссылается на хеш родителя. Это и есть знаменитая неизменяемость истории.

Зачем всё это? Целостность. Хеш гарантирует, что объект не побился на диске, при передаче по сети, при сбое RAM. Git при каждом обращении может пересчитать хеш и сверить с именем - команда

Код: Выделить всё

git fsck
так и делает по всему репозиторию. Если бит перевернулся, хеш не сойдётся, и Git закричит. Это контрольная сумма уровня всей структуры данных, а не отдельного файла.

Изображение

Почему SHA-1 пришлось менять: shattered git и коллизии

Криптографическая хеш-функция обязана обладать стойкостью к коллизиям: должно быть вычислительно невозможно найти два разных входа с одинаковым хешем. На этом держится всё. Если я могу сделать два разных коммита с одинаковым SHA-1, я могу показать тебе один контент при проверке, а подсунуть другой при клонировании - и Git не заметит подмены, потому что для него это "тот же объект".

В феврале 2017 команда из Google и CWI выкатила атаку SHAttered: они предъявили два разных PDF с одинаковым SHA-1. Это была первая практическая коллизия, и стоила она огромных вычислений, но "дорого" в криптографии означает "сломано" - дальше только дешевле. Отсюда и название: shattered git - это про то, как землю выбили из-под ног у хеша, на котором стоял Git.

Линус Торвальдс тогда справедливо заметил, что архитектура Git смягчает удар: объекты подписаны контекстом, есть распределённость, есть подписи коммитов. Но смягчает - не значит "не проблема". Поэтому сделали две вещи. Короткую и длинную.

Короткая: в Git вшили collision detection. Современный Git использует не голый SHA-1, а sha1dc (sha1collisiondetection) - реализацию, которая на лету ловит признаки именно той математики, что используется в атаках на SHA-1, и аварийно завершается. Эта защита включена по умолчанию. Проверить можно так:

Код: Выделить всё

$ git version --build-options
git version 2.54.0
...
sizeof-size_t: 8
shell-path: /bin/sh
...
Если скормить Git один из shattered-файлов, ты получишь не тихую подмену, а громкую ошибку вида "collision attack detected". Тихо подсунуть второй файл из известной пары уже не выйдет.

Длинная история - это и есть переход на SHA-256, потому что детектор конкретной атаки лечит симптом, а не причину. SHA-1 как фундамент надо менять целиком.

Статус 2026: object-format sha256 становится мейнстримом

Давай по фактам, без мифов, потому что вокруг git sha-256 много путаницы и устаревших статей.

Экспериментальная поддержка SHA-256 появилась ещё в Git 2.29 (2020). С тех пор её довели до боевого состояния. Ключевые вехи к середине 2026:
  • Git 2.45 (2024) - заложен фундамент интеропа SHA-1 и SHA-256, чтобы старые репозитории и новые могли сосуществовать.
  • Git 2.51 (2025) - SHA-256 объявлен дефолтным форматом, который Git 3.0 будет использовать для новых репозиториев. Тонкий момент: сам по себе 2.51 при

    Код: Выделить всё

    git init
    всё ещё создаёт SHA-1-репозиторий по умолчанию, но вся внутренняя машинерия уже готова, а курс задан официально.
  • Git 2.52 (конец 2025) - стартовала большая работа над живым интеропом SHA-1 и SHA-256. Это сотни патчей, часть сделана, часть в работе.
  • Git 3.0 (ожидается к концу 2026) - SHA-256 закрепляется как встроенный дефолт для новых репозиториев. Тогда

    Код: Выделить всё

    git init
    без флагов начнёт создавать SHA-256-репо.
Вывод простой: на 2026 переход - это не "поиграться на выходных", а заданное направление развития. Но и не "уже всё по умолчанию" - в ванильном Git новые репозитории пока ещё SHA-1, SHA-256 включаешь руками. Не верь статьям, которые пишут, что 2.51 уже флипнул дефолт - он только назначил дефолт для будущей 3.0.

Главный сдерживающий фактор - экосистема. На 2026 крупные форджи ещё не все умеют SHA-256. В частности GitHub на момент написания не поддерживает SHA-256-репозитории. Поэтому: для своих внутренних, локальных, security-критичных проектов SHA-256 уже отличный выбор, а вот для зеркалирования на публичный GitHub сперва проверь, что хостинг это принимает.

Практика: как создать и опознать SHA-256-репозиторий

Создаём новый репозиторий на SHA-256 явным флагом:

Код: Выделить всё

$ git init --object-format=sha256 demo256
Initialized empty Git repository in /tmp/demo256/.git/

$ cd demo256
$ git config extensions.objectformat
sha256
Формат записан в конфиг как расширение

Код: Выделить всё

extensions.objectformat=sha256
. Это значит: репозиторий помечен, и старый Git, не понимающий SHA-256, откажется с ним работать вместо того чтобы тихо всё испортить. Это сознательная защита.

Сделаем коммит и посмотрим на хеш:

Код: Выделить всё

$ printf 'hello\n' > file.txt
$ git add file.txt
$ git -c user.name=dev -c user.email=dev@local commit -m "first"
[main (root-commit) 1b2c3d...] first

$ git rev-parse HEAD
9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
Сразу видно разницу: SHA-256-хеш - это 64 шестнадцатеричных символа против 40 у SHA-1. Это первый признак, по которому ты на глаз отличишь репозиторий. А тот же блоб "hello", что в начале урока имел SHA-1

Код: Выделить всё

ce013625...
, теперь имеет совсем другой отпечаток:

Код: Выделить всё

$ printf 'hello\n' | git hash-object --stdin
bc02d6d38c44fc0bd1c5f57d36ec06b5e5680a76db3a3a4a76845b96ac9d65b2
Заголовок объекта остался прежним (

Код: Выделить всё

blob 6\0hello\n
), сменилась только функция, которой его прогоняют. Хочешь не плодить флаги в каждом init - задай дефолт глобально, и все новые репозитории будут на SHA-256:

Код: Выделить всё

$ git config --global init.defaultObjectFormat sha256
Теперь про важное ограничение. Формат хеша выбирается один раз при создании репозитория и не меняется. Нельзя взять существующий SHA-1-репо и сказать "теперь ты SHA-256" одной командой конфига - это переписывание абсолютно всех объектов и хешей. По-настоящему мигрировать историю можно только пересозданием через интероп-механизмы, которые как раз дозревают к 3.0. Так что для существующих проектов на GitHub сегодня честный ответ - подожди, пока экосистема и интероп стабилизируются. Для новых внутренних - стартуй сразу на SHA-256.

Типичные грабли
  • Старый Git и чужой инструмент не понимают репо. Если CI, IDE-плагин, ред-тул или хостинг падают с ошибкой "object-format sha256 not supported" - это не баг твоего репозитория, это они ещё не доросли. Прежде чем переводить команду, проверь весь тулчейн, а не только локальный git.
  • ] Нельзя смешивать в одном fetch. SHA-1-репозиторий и SHA-256-репозиторий - это два разных мира адресации. Пока интероп не стабилизирован, не жди, что просто добавишь SHA-256-репо как remote к SHA-1 и всё срастётся. Это и есть та работа, что пилится в 2.52+.
  • Сокращённые хеши стали длиннее. Привычка копировать "7 символов короткого хеша" работает и тут, но на больших SHA-256-репозиториях Git может показывать больше символов, чтобы избежать неоднозначности. Не удивляйся.
  • "Я включу sha256 в конфиге существующего репо". Не сработает и не должно.

    Код: Выделить всё

    extensions.objectformat
    - это метка того, как репо был создан, а не переключатель. Руками туда лезть нельзя - сломаешь репозиторий.
  • Путаница "хеш = защита от злоумышленника". Сам по себе хеш защищает целостность от случайных повреждений и от подмены при условии стойкости функции. От целенаправленной злонамеренной подмену объектов тебя защищают связка стойкого хеша (SHA-256) плюс подписи коммитов и тегов. Одно без другого - полумера.
Мини-лаба: пощупать оба мира руками

Сделай по шагам, это 10 минут и снимает всю абстракцию.
  • Шаг 1. Создай SHA-1-репо по старинке:

    Код: Выделить всё

    git init demo1
    , зайди внутрь, сделай коммит с любым файлом.
  • Шаг 2. Посмотри

    Код: Выделить всё

    git rev-parse HEAD
    - посчитай символы, их 40.
  • Шаг 3. Воспроизведи хеш блоба вручную:

    Код: Выделить всё

    printf 'blob 6\0hello\n' | sha1sum
    и сравни с

    Код: Выделить всё

    printf 'hello\n' | git hash-object --stdin
    . Должны совпасть - ты понял, что хешируется заголовок плюс контент.
  • Шаг 4. Рядом создай SHA-256-репо:

    Код: Выделить всё

    git init --object-format=sha256 demo256
    . Сделай такой же коммит.
  • Шаг 5. Сравни

    Код: Выделить всё

    git rev-parse HEAD
    в обоих. 40 против 64 символов - вот вся разница на глаз.
  • Шаг 6. Проверь метку:

    Код: Выделить всё

    git config extensions.objectformat
    - в первом репо пусто, во втором .
  • Шаг 7. Запусти

    Код: Выделить всё

    git fsck
    в обоих - убедись, что целостность проверяется одинаково, независимо от функции хеша.
После этой лабы у тебя в голове щёлкнет: формат хеша - это свойство репозитория, заданное при рождении, а не настройка на лету.

Контрольные вопросы
  • Почему хеш в Git - это про целостность, а не про шифрование? Что конкретно подаётся на вход функции при хешировании блоба?
  • Что такое атака SHAttered и почему она опасна именно для модели Git, где имя объекта равно его хешу?
  • Чем отличается "SHA-256 - дефолт для будущей Git 3.0" (статус 2.51) от "git init по умолчанию создаёт SHA-256-репо"? На 2026 это одно и то же?
  • Можно ли командой git config превратить существующий SHA-1-репозиторий в SHA-256? Почему да или почему нет?
Итог

Хеш - это фундамент адресации и целостности в Git, а не шифрование. SHA-1 был скомпрометирован атакой SHAttered в 2017, и Git ответил двумя путями: немедленной защитой через collision detection (включена по умолчанию) и стратегическим переходом на SHA-256. К 2026 SHA-256 - уже не экзотика: с Git 2.51 он назначен дефолтом для грядущей Git 3.0, интероп активно пилится с 2.45 и 2.52, а в самой 3.0 (ожидается к концу 2026) SHA-256 станет дефолтом для новых репозиториев. Создаёшь новый внутренний проект - можешь стартовать на

Код: Выделить всё

git init --object-format=sha256
уже сейчас. Тащишь на публичный форж - сперва проверь поддержку, потому что экосистема пока догоняет.
👍5 ❤️2 🔥 😄 🤔1
Аватара пользователя
vereinte
Сообщения: 1
Зарегистрирован: 11 май 2026, 04:10

Re: От SHA-1 к SHA-256: переход на новый хеш

Сообщение vereinte »

А я думал хеш это типа шифрование пароля, спасибо что разжевали - оказывается просто отпечаток контента. Сразу понятнее стало зачем заголовок blob 6 туда лепится.
👍 ❤️ 🔥1 😄 🤔1
Аватара пользователя
slamarc32
Сообщения: 1
Зарегистрирован: 30 май 2026, 07:58

Re: От SHA-1 к SHA-256: переход на новый хеш

Сообщение slamarc32 »

Проверил git config extensions.objectformat у себя на рабочем репо - пусто, значит sha1. А на гитхабе sha256 реально не заводится, словил not supported. Подожду 3.0 получается.
👍3 ❤️1 🔥 😄 🤔
Ответить
← Предыдущая глава
Внутреннее устройство III: индекс, packfiles, gc и обслуживание
Следующая глава →
Огромные репозитории: partial clone, FSMonitor, Scalar

Все главы курса «Git профессионально: от первого коммита до внутреннего устройства»

Поделиться темой: ✈ Telegram VK

Вернуться в «Git профессионально: от первого коммита до внутреннего устройства»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость