Урок курса
Исправить последний собственный коммит
Git и GitHub с нуля: бесплатный курс с практикойgit log --oneline и git show читают историю, а git restore восстанавливает рабочий файл из текущего индекса, не меняя коммиты. git commit --amend заменяет последний собственный неопубликованный коммит снимком индекса и выбранным сообщением.
Механизм git commit --amend: замена коммита новым объектом
Когда вы выполняете git commit --amend, Git не редактирует существующий коммит на месте. Вместо этого он формирует замещающий коммит: берёт снимок из текущего индекса, прикрепляет к нему родителей прежнего последнего коммита, и записывает его как новую вершину истории. Прежний коммит при этом перестаёт быть последним в текущей ветке, но сам объект в хранилище Git никуда не исчезает — он просто больше не виден в обычном git log.
Из этого вытекает ключевое следствие: в рассматриваемых исправлениях меняется сообщение или снимок, поэтому ID замещающего коммита отличается от прежнего. Хеш вычисляется по всему содержимому коммита — снимку файлов, сообщению, временной метке, данным об авторе, ссылке на родителей. Даже если вы поменяли только одну букву в сообщении и индекс остался прежним, хеш будет другим.
Визуально в git log --oneline вы увидите ту же одну строку на месте последнего коммита — но с другим идентификатором. Количество коммитов в истории не изменится: amend заменяет последний, а не добавляет новый поверх него.
Граница безопасного применения amend
Смена хеша при amend — не просто техническая деталь. Если коммит уже опубликован (отправлен в удалённый репозиторий), его хеш известен другим участникам проекта: они могут работать поверх него, ссылаться на него в ветках или задачах. Когда вы заменяете такой коммит через amend, ваша локальная история расходится с общей. При следующей попытке отправить изменения Git откажет, потому что истории больше не совпадают. Коллеги, уже скачавшие прежний коммит, окажутся в ситуации, когда их история и ваша описывают одно место в репозитории по-разному.
Поэтому правило простое: amend применяют только к последнему собственному коммиту, который ещё не был отправлен ни в один удалённый репозиторий. В учебном репозитории этого урока именно такая ситуация — коммиты ещё никуда не уходили, и amend безопасен.
Важно не попасться на интуитивно привлекательное исключение: «я исправил только опечатку в сообщении, снимок файлов не тронул — хеш же останется тем же?» Нет. Сообщение коммита входит в данные, по которым вычисляется хеш. Если сообщение фактически изменилось, хеш изменится тоже, независимо от того, совпадают ли снимки файлов. Это означает, что даже косметическая правка в сообщении уже опубликованного коммита создаёт расхождение истории.
Исправление сообщения и добавление забытого файла через amend
Есть две типичные ситуации, когда нужен amend: неточное сообщение или забытый файл.
Создайте новую отдельную учебную папку и откройте в ней терминал. Выполните команды по одной:
git init -b main
git config user.name "Учебный автор"
git config user.email "learner@example.invalid"
В обычном текстовом редакторе создайте README.md со строкой «# Проект», сохраните файл. Затем выполните:
git add README.md
git commit -m "Добавить данные"
git status
В этой папке main содержит один коммит, файл отслеживается, рабочая папка и индекс чисты. Это первый и единственный собственный коммит опыта; его ещё никуда не отправляли. До исправления выполните git log --oneline и запишите его фактический ID и сообщение. Оба дальнейших исправления относятся к этому одному коммиту.
Исправить только сообщение
Перед тем как менять сообщение, убедитесь, что в индексе нет посторонних изменений:
git diff --staged
Вывод должен быть пустым. Если он не пуст, в заменяющий коммит войдут не только правки сообщения, но и всё, что сейчас в индексе — это может быть нежелательно.
Когда diff пуст, выполните:
git commit --amend -m "docs: добавить README"
Флаг --amend сообщает Git, что нужно создать замещающий коммит вместо последнего. Флаг -m передаёт новое сообщение напрямую, без открытия редактора. Git берёт снимок из текущего индекса — а поскольку индекс чистый, снимок файлов останется таким же, каким был в исходном коммите.
Добавить забытый файл
Допустим, вы уже сделали amend с новым сообщением, но вспомнили, что забыли добавить CHANGELOG.md. Создайте в текстовом редакторе CHANGELOG.md со строкой «история изменений», сохраните его, затем:
git add CHANGELOG.md
Проверьте, что в индексе именно то, что нужно:
git diff --staged
Вы должны увидеть только добавление CHANGELOG.md. Если в вывод попало что-то лишнее — разберитесь с этим до amend, иначе лишнее тоже войдёт в коммит.
Теперь выполните:
git commit --amend --no-edit
Флаг --no-edit говорит Git сохранить сообщение последнего коммита без изменений и не открывать редактор. Git создаст замещающий коммит с полным снимком текущего индекса — то есть со всеми ранее отслеживаемыми файлами плюс новым CHANGELOG.md. Хеш снова изменится, сообщение "docs: добавить README" останется.
Что показывает git log --oneline и git show после amend
Чтобы убедиться, что amend сработал правильно, достаточно двух команд, которые вы уже знаете: git log --oneline и git show.
git log --oneline выводит по одной строке на каждый коммит: сначала короткий хеш, затем сообщение. Сравните вывод до и после amend. Ниже условные допустимые шестнадцатеричные ID; ваши фактические значения будут другими:
# до amend a1b2c3d Добавить данные # после amend -m e4f5a6b docs: добавить README # после amend --no-edit с добавлением CHANGELOG.md c7d8e9f docs: добавить README
Три наблюдаемых признака корректной работы:
- Количество строк в
git log --onelineне изменилось — коммитов столько же, сколько было. - Хеш в первой строке отличается от предыдущего после каждого amend.
- Сообщение соответствует тому, что вы передали в
-mили оставили через--no-edit.
git log --oneline не показывает, какие файлы вошли в коммит. Для этого нужен git show — он выведет метаданные коммита и diff по каждому изменённому файлу:
git show
В подготовленном опыте заменяется первый и единственный коммит, поэтому после amend с добавлением CHANGELOG.md вы увидите в его diff оба файла — и README.md (добавленный изначально), и CHANGELOG.md (добавленный через amend). Если CHANGELOG.md в выводе git show есть — amend включил его в снимок корректно.
В этих двух исправлениях новое сообщение и добавленный файл дают другой ID. При попытке amend без изменения сообщения и снимка одного сравнения ID недостаточно: на него влияют также метаданные коммитера, включая время. При изменении этих данных ID может смениться; при совпадении всех данных может остаться тем же. Неизменный ID сам по себе не доказывает отказ команды или пропуск amend. Проверяйте нужное сообщение и снимок по log и show.
Задача 1
Последний собственный коммит учебного репозитория ещё не публиковался. Автор изменил и подготовил notes.md, но теперь выполняет git commit --amend -m "Исправленное описание". Сообщение отличается от прежнего. Что попадёт в заменяющий коммит?
Задача 2
Нужно исправить сообщение одного коммита через amend по правилу этого курса. Какой кандидат соответствует разрешённому учебному случаю?
Задача 3
Практика: создайте отдельный учебный репозиторий известным циклом init -b main, обе локальные настройки автора, README через редактор, add и commit. Индекс чист, коммит ваш и нигде не публиковался. Исправьте его сообщение на «docs: добавить README», предварительно проверив staged diff. Затем создайте CHANGELOG.md через редактор, подготовьте файл и включите его в последний коммит без редактирования сообщения. Проверьте историю и diff через show. Запишите ID и сообщения до и после каждого amend, количество коммитов и файлы, показанные diff итогового коммита. Письменно объясните коллеге, почему новый текст сообщения меняет ID даже при прежнем снимке файлов.
Платформа проверяет только ответ ниже; действия в своём репозитории и письменные ответы вы проверяете самостоятельно.
В отдельном контрольном случае до amend было три коммита. Через add подготовили новый забытый файл и выполнили amend --no-edit. Как проверить смысл получившегося результата?
Продолжить с сохранением прогресса
Перейдите к уроку в учебном кабинете.
