Git: как устроен и что о нём спрашивают на собеседовании
Git учат по шпаргалке из пяти команд, и этого хватает ровно до первого конфликта или случайного коммита не в ту ветку. Дальше начинается паника, копирование папки проекта на всякий случай и вопросы в чат.
Проблема в том, что шпаргалка не объясняет модель. А модель простая, и понимание её экономит потом много нервов.
Что происходит внутри
Git хранит не изменения, а снимки. Каждый коммит это состояние всего дерева файлов плюс ссылка на родителя.
Из этого следует почти всё остальное:
История это цепочка коммитов. У каждого есть родитель, у слияния два родителя.
Ветка это просто указатель на коммит. Не копия файлов, не отдельная папка, а движущаяся метка. Поэтому создание ветки мгновенно и ничего не стоит.
HEAD это указатель на текущее место. Обычно он указывает на ветку, а ветка на коммит.
Когда вы понимаете, что ветка это метка, половина страшных команд перестаёт быть страшной: вы просто двигаете метки.
Три состояния файла
Рабочая директория: то, что вы видите и правите.
Индекс (staging): то, что попадёт в следующий коммит. Именно сюда кладёт git add.
Репозиторий: то, что уже зафиксировано коммитом.
Отдельный шаг с индексом кажется лишним, пока не понадобится закоммитить часть изменений, а часть оставить. Тогда он оказывается очень удобным.
Ежедневный набор команд
Их правда немного.
git status чтобы понять, где вы находитесь и что происходит. Первая команда при любом замешательстве.
git add и git commit для фиксации.
git pull и git push для обмена с удалённым репозиторием.
git switch или git checkout для перехода между ветками.
git log --oneline --graph чтобы увидеть историю картинкой.
git diff чтобы посмотреть, что именно изменилось.
Всё остальное используется ситуативно, и вот про это ситуативное обычно и спрашивают.
Merge и rebase
Два способа объединить работу, и вечная тема для споров.
Merge создаёт коммит слияния с двумя родителями. История сохраняется как была, со всеми ветвлениями. Честно, но со временем граф превращается в спагетти.
Rebase переносит ваши коммиты поверх другой ветки, переписывая их. История становится линейной и читаемой, но коммиты получают новые идентификаторы.
Отсюда главное правило: не делать rebase в ветке, которую уже забрали другие. Вы перепишете историю, а у коллег останется старая, и дальше будет больно.
Рабочий компромисс, который используют многие команды: rebase внутри своей ветки, чтобы привести её в порядок перед отправкой, и merge при вливании в основную.
Конфликты
Конфликт возникает, когда две ветки поменяли одно и то же место по-разному. Git не угадывает, а отдаёт решение вам.
Что делать: открыть файл, увидеть маркеры, выбрать нужный вариант или собрать из обоих, убрать маркеры, добавить файл и продолжить операцию.
Что помогает конфликтов избегать: маленькие ветки, частые обновления от основной, договорённость в команде о форматировании (иначе автоформаттер порождает конфликты на ровном месте).
Когда всё сломалось
Самое ценное знание, которое обычно приходит через боль.
Закоммитил не то. git commit --amend для последнего коммита, если он ещё не ушёл на сервер.
Закоммитил не в ту ветку. Переносится через cherry-pick в правильную, а из неправильной убирается reset.
Сделал reset –hard и потерял работу. Обычно всё ещё живо: git reflog показывает, где вы были, и туда можно вернуться. Эта команда спасает чаще всех остальных.
Нужно откатить коммит, который уже все забрали. git revert, который создаёт обратный коммит, а не переписывает историю.
Хочу отложить незаконченное. git stash, но не забывайте про него: стеш имеет привычку копиться месяцами.
Как работают в командах
Обычно одна из двух схем.
Ветка на задачу с вливанием в основную через пулл-реквест. Самая распространённая: основная ветка всегда рабочая, каждая задача живёт отдельно, ревью происходит до вливания.
Транковая разработка. Все пишут в основную ветку маленькими кусками, фичи прячутся за флагами. Требует сильной культуры тестирования, зато нет долгоживущих веток и мучительных слияний.
Отдельно про сообщения коммитов: короткая первая строка в повелительном наклонении, при необходимости подробности через пустую строку. Многие команды используют соглашение с префиксами вроде fix, feat, docs, потому что по ним удобно собирать changelog.
Что спрашивают на собеседовании
Чем merge отличается от rebase и когда что использовать. Что такое HEAD и что такое ветка. Как отменить последний коммит, если он уже отправлен и если ещё нет. Что делать с конфликтом. Зачем нужен индекс. Как найти коммит, в котором появился баг (тут ждут упоминания bisect).
Вопросы редко бывают сложными, но их задают почти всем: Git это общий инструмент независимо от языка и роли.
Как выучить нормально
Совет практический: заведите тестовый репозиторий и сломайте его сознательно. Сделайте конфликт и разрешите. Сделайте reset и восстановитесь через reflog. Переберите коммиты через rebase. На реальном проекте вы такого не попробуете, а на песочнице ничего не жалко.
А проверить, что закрепилось, можно вопросами. В Сеньорчике блок по инструментам и процессам входит в треки разработки и тестирования: вопросы с реальных собеседований, с вариантами ответов и разбором. Движок возвращает темы, где вы ошибаетесь. Десять минут в день в Telegram, бесплатно.