| git commit: правила хорошего тона |
|
| Добавил(а) microsin | ||||||||||||||||||||||||||||||||||||||||||||
|
В этой статье рассмотрены некоторые общепринятые правила управления фиксациями (фиксация == git commit). Сначала небольшая памятка по командам, связанным с фиксациями:
Примечания: 1. Важный момент: поскольку --hard перезаписывает файлы, вы можете потерять свою работу. Если вы случайно выполнили эту команду, но коммит существовал, его ещё можно попытаться восстановить с помощью git reflog (журнала ссылок), но незакоммиченые изменения восстановить практически невозможно. Никогда не используйте --hard для коммитов, которые уже были отправлены (push) в удалённый репозиторий, так как это перепишет общую историю и создаст проблемы для других. HEAD~1 — это синтаксис, который указывает Git на коммит, являющийся родителем текущего коммита (то есть на один коммит назад в истории фиксаций). Разбор по частям: HEAD — это специальный указатель (ссылка) на текущий коммит, на котором вы сейчас находитесь (вершина текущей ветки). Итого: HEAD~1 = «текущий коммит минус один шаг назад по истории» = родитель текущего коммита. Как это можно представить наглядно? Представьте историю коммитов: A ← B ← C ← D - HEAD — это коммит D. [Важные нюансы] 1. Только по первой линии родителей. Если коммит является результатом слияния (merge) и имеет двух родителей, `~` всегда идёт по первому родителю. Для обращения ко второму родителю используется `^2` (например, `HEAD^2`). 2. Синоним `HEAD^`. Запись `HEAD^` эквивалентна `HEAD~1` (один шаг назад), `HEAD^^` эквивалентна `HEAD~2` (два шага назад). Но `HEAD~2` и `HEAD^2` — это разные вещи: `~2` — два шага по первой линии, `^2` — второй родитель текущего коммита. 3. Работает не только с HEAD. Вместо `HEAD` можно указать любую ссылку: `main~1`, `feature~2`, хеш коммита и т.д. Именно поэтому: - `git reset HEAD~1` — сбрасывает ветку на родителя текущего коммита, то есть «отменяет последний коммит». `ORIG_HEAD` — это специальная ссылка (псевдо-ссылка) в Git, которая автоматически создаётся некоторыми командами перед выполнением «опасных» операций. Она служит «закладкой» или «точкой восстановления», запоминая, где находился указатель `HEAD` до того, как команда начала менять историю. [Назначение и принцип работы ORIG_HEAD] Основная идея: если после выполнения команды что-то пошло не так (например, слияние оказалось неудачным, или вы поняли, что перебазирование испортило историю), вы можете легко вернуться к исходному состоянию, используя `ORIG_HEAD`. Согласно документации Git, `ORIG_HEAD` создаётся командами, которые «резко» перемещают `HEAD` (такими как `git am`, `git merge`, `git rebase`, `git reset`), чтобы записать позицию `HEAD` до начала операции. Важное предостережение: ненадёжность при `rebase`. Хотя `ORIG_HEAD` кажется надёжным инструментом, у него есть важная особенность, о которой стоит знать. В официальной документации к `git rebase` прямо указано, что `ORIG_HEAD` не гарантированно указывает на исходную вершину ветки после завершения перебазирования, если во время этого процесса вы использовали другие команды, которые также перезаписывают `ORIG_HEAD` (например, `git reset`). Это может сбивать с толку: вы начали rebase, прервались на разрешение конфликта, сделали `git reset`, а затем завершили rebase. В итоге `ORIG_HEAD` будет указывать на состояние после вашего `reset`, а не на то, что было до начала всего rebase. [Более надёжная альтернатива: reflog] Из-за этой особенности современный Git рекомендует использовать для восстановления не `ORIG_HEAD`, а журнал ссылок (reflog). Запись вида `branchname@{1}` (или `HEAD@{1}`) позволяет обратиться к предыдущему состоянию ветки и является более надёжным и предсказуемым способом отмены действий. Таким образом, если вы выполнили `git reset --hard HEAD~1`, отменив последний коммит, и пожалели об этом, вы можете восстановить его с помощью `git reset --hard ORIG_HEAD`. Команда `reset` как раз входит в список тех, что создают `ORIG_HEAD` перед изменением `HEAD`. Это позволяет использовать `ORIG_HEAD` как быстрый способ «вернуть всё как было» после сброса. Часто редактором по умолчанию для ввода сообщений commit является текстовый редактор vi. Его можно заменить на более дружелюбный редактор. Для настройки редактора, который Git будет использовать для сообщений коммитов, нужно изменить параметр `core.editor`. Это можно сделать глобально (для всех репозиториев) или локально (для текущего). [Основная команда настройки] Используйте `git config` с флагом `--global` (или `--local`), чтобы указать команду запуска вашего редактора. Важное замечание: для графических редакторов (VS Code, Sublime Text и т.п.) часто нужно добавлять флаг ожидания (например, `--wait` или `-w`). Без него Git может продолжить работу, не дожидаясь, пока вы закроете файл, что приведёт к пустому коммиту. Примеры для популярных редакторов:
[Проверка и использование] 1. Проверить текущую настройку: git config --global core.editor Если команда ничего не возвращает, редактор не настроен. 2. Использование: gосле настройки при выполнении `git commit` (без флага `-m`) Git автоматически откроет выбранный вами редактор для ввода сообщения. 3. Редактирование последнего коммита: чтобы изменить сообщение уже сделанного коммита, используйте `git commit --amend`. Откроется тот же редактор с текстом последнего сообщения. [Специализированные инструменты] Существуют также утилиты, созданные специально для удобного редактирования сообщений коммитов (например, с поддержкой Conventional Commits). Примерами могут служить `committed` (TUI-редактор) или `jot` (минималистичный встроенный редактор). Их можно установить и указать в качестве `core.editor` аналогичным образом. [Оформление commit-а с заголовком] Если коммит многострочный, и после первой строки есть пустая строка, то первая строка считается заголовком, а остальные строки это так называемое тело коммита. Пример такого оформления сообщения коммита: Добавлено несколько полезных фич. Описание фичи1 Общепринятая практика - в заголовке указывать краткое описание коммита (это тема коммита), а в теле коммита давать подробные пояснения. Тогда команда git log --oneline покажет только заголовки (первые строки), что удобно для быстрого обзора фиксаций, а команда git log выведет заголовки вместе с телом фиксации, выдавая полную информацию. [Правила оформления сообщений commit-ов] 1. Каждый коммит должен создавать рабочую версию репозитория. 2. Если сообщение многострочное, то оно должно быть разделено на заголовок (тему) фиксации и тело фиксации. Между темой и телом сообщения фиксации должна быть пустая строка. 3. Желательно, чтобы заголовок (тема) сообщения была ограничена 50 символами. Некоторые команды разработчиков договариваются между собой, что тема сообщения пишется в верхнем регистре (большими буквами). Также заголовок не должен заканчиваться точкой или другими знаками препинания. 4. Тело сообщения принято ограничивать 80 символами. 5. Тело сообщения должно объяснять, что было сделано, а не почему были сделаны эти изменения. 6. Тема сообщения должна отвечать на вопрос: что будет, если применить этот коммит? [Ссылки] 1. Краткий справочник по Git. |