gitaspen docs

Работа с git и репозиториями

Повседневные правила: что попадает в историю, как выглядит коммит, как ведутся ветки и версии, что делать при ошибке. Границы репозиториев и выделение переиспользуемых единиц — в REUSE; здесь то, что происходит внутри репозитория каждый день.

5 минут

Повседневные правила: что попадает в историю, как выглядит коммит, как ведутся ветки и версии, что делать при ошибке. Границы репозиториев и выделение переиспользуемых единиц — в REUSE; здесь то, что происходит внутри репозитория каждый день.

Место в цепочке

Откуда пришлиЭтот документКуда ведёт
решено, где границы репозиториевчто коммитим, как ведём ветки и версиисборка релиза из зафиксированного состояния

Что этот документ оставляет следующему: помеченное версией состояние, из которого воспроизводимо собирается релиз. Сборка из репозитория с незакоммиченными правками невоспроизводима — по артефакту нельзя понять, что в нём.


Что попадает в историю

ПопадаетНе попадает
исходный кодсекреты, пароли, ключи, токены
конфигурация без секретовфайлы окружения с реальными значениями
миграции схемырезультаты сборки, каталоги зависимостей
документация проектавременные и системные файлы редакторов
примеры файлов окружения без значенийбольшие бинарные артефакты (для них — отдельное хранилище)

Файл .gitignore заводится первым, до первого коммита: файл, попавший в историю, оттуда не исчезает при последующем добавлении в игнор — он остаётся во всех прошлых состояниях.

Рядом с файлом окружения держат его пример с теми же ключами и пустыми значениями: по нему видно, что нужно задать при развёртывании.


Коммит

Коммит — законченная единица: он делает одно изменение целиком и оставляет проект в рабочем состоянии. Коммит, который «доломает следующий», ломает и возможность откатиться на него.

Сообщение отвечает на вопрос «что меняется и зачем», а не пересказывает диф:

Код
fix(gateway): не терять заголовок авторизации при перенаправлении

Перенаправление собирало новый запрос без заголовков, и клиент получал 401
после первого же редиректа.
  • первая строка — суть, в настоящем времени, без точки в конце;
  • тело — причина и следствие, если они не очевидны;
  • одно изменение — один коммит: смешанные в одном коммите правка ошибки и переименование файлов невозможно ни просмотреть, ни откатить по отдельности.

Служебные пометки об инструментах и соавторстве в сообщение не добавляются, если это не оговорено: история должна отражать содержание изменения.


Ветки

Основная ветка всегда в рабочем состоянии: из неё в любой момент собирается релиз.

Работа ведётся в отдельной ветке и вливается, когда закончена и проверена. Долгоживущие ветки избегают: чем дольше ветка живёт, тем дороже слияние, и тем позже обнаруживается конфликт замысла, а не только текста.

Ветка называется по задаче: feat/<что>, fix/<что>, chore/<что>.

Постоянные ветки под конкретного потребителя общего кода не создаются — это форк, который расходится с источником. Различия потребителей выражаются настройкой, а не веткой.


Версии и метки

Готовое к поставке состояние помечается меткой. Метка неизменяема: она указывает на конкретное состояние, и переставлять её на другое нельзя — иначе «та же версия» будет означать разный код.

Нумерация по смыслу изменения:

ЧастьМеняется, когда
старшаяконтракт сломан, потребителю нужно менять код
средняядобавлена возможность, старое продолжает работать
младшаяисправление без изменения поведения

Для переиспользуемых единиц это обязательно: потребитель закрепляет версию и должен понимать, чем грозит обновление.


Просмотр изменений

Изменение просматривается до вливания. Что проверяется: соответствие архитектурным границам, отсутствие секретов, наличие проверок, понятность имён.

Просмотр — про содержание, а не про вкус. Замечание формулируется как проблема и её следствие («здесь бизнес-логика попала в клиент — при смене транспорта её придётся переносить»), а не как предпочтение.


Ошибки и как из них выходить

Секрет попал в репозиторий. Удаление файла следующим коммитом не помогает: значение остаётся в истории и в клонах. Порядок действий: отозвать и заменить значение (оно скомпрометировано), затем при необходимости переписать историю и предупредить всех, у кого есть клоны. Отзыв обязателен, чистка истории — вторична.

Ошибочный коммит уже в общей ветке. Исправляется обратным коммитом, а не переписыванием общей истории: перезапись ломает работу всем, у кого есть клоны.

Изменения потерялись. Локально почти ничего не пропадает бесследно: git reflog показывает состояния, на которых был репозиторий, включая те, что уже не видны из веток.

Тяжёлый файл попал в историю. Репозиторий не уменьшится сам: объект остаётся во всех прошлых состояниях. Крупные файлы кладут в отдельное хранилище с самого начала.


Обязательное перед выкладыванием

  • в истории нет секретов — проверяется поиском по репозиторию и по истории, а не по текущим файлам;
  • в репозитории лежит пример файла окружения, а не сам файл;
  • рабочее дерево чисто, состояние помечено;
  • описание проекта отвечает, что это, как запустить и как проверить, что запустилось.

Типичные отказы

ПризнакПричинаЧто делать
сборка релиза отказывается стартоватьнезакоммиченные правкизафиксировать или убрать; релиз собирается из чистого состояния
файл в .gitignore, но продолжает отслеживатьсяпопал в историю раньше игнораубрать из индекса; при секрете — отозвать значение
репозиторий разросся до гигабайтовбинарные артефакты в историивынести в отдельное хранилище; историю чистить отдельной операцией
слияние ветки превращается в отдельную работуветка жила слишком долговливать чаще, дробить задачу
«та же версия» ведёт себя по-разномуметку переставилиметки неизменяемы, выпустить новую
откат на прошлый коммит ломает сборкукоммиты не самодостаточныодин коммит — одно законченное изменение
Инструкция не помогла?

Откройте исходник документа по ссылке «Предложить правку» — там же видно, что и когда в нём менялось.