Git-беглость на собеседовании
Ментальные модели, что реально проверяет сеньорское git-собеседование: для каждой — что прощупывают плюс ответ в одно предложение. Merge против rebase, reset против revert, что такое HEAD, reflog, force-with-lease, хранение снимками. Весь трек, готовый к воспроизведению.
Сеньорские вопросы по git на собеседовании редко про синтаксис — они прощупывают, держишь ли ты правильную ментальную модель. «Merge или rebase?» — это не про предпочтение; это проверка, понимаешь ли ты историю как общую или локальную. Кандидат, отвечающий одним чётким предложением и называющий компромисс, звучит как сеньор; тот, кто перечисляет команды, звучит как заучивший шпаргалку.
К концу этого урока ты сможешь отвечать на канонические git-вопросы собеседования так, как это делает сеньор: назвать, что вопрос на самом деле проверяет, затем дать верный ответ в одно предложение — превратив весь трек в готовую к воспроизведению беглость.
После этого урока ты сможешь отбивать ключевые сеньорские git-вопросы — merge против rebase, reset против revert, что такое HEAD/ветка/индекс, восстановление потерянных коммитов, fast-forward против three-way, force-with-lease против force, хранение снимками, отмена запушенного коммита — каждый как «что они проверяют» плюс ответ в одно предложение.
Merge против rebase — проверяют, уважаешь ли ты общую историю. Оба интегрируют одну ветку в другую; разница в том, что они делают с историей.
- Merge сохраняет историю в точности и связывает две линии merge-коммитом (два родителя). Недеструктивно, безопасно на общих ветках, но история нелинейна.
- Rebase переписывает твои коммиты на новую базу, давая чистую линейную историю, — но создаёт новые коммиты, поэтому никогда не должен касаться коммитов, которые другие уже стянули.
Ответ в одно предложение: «Rebase локально, чтобы держать собственную ветку чистой и линейной; merge для интеграции в общие ветки, потому что rebase опубликованной истории ломает всех, у кого она есть». Это предложение — rebase локально, merge общее — и есть вся суть.
Reset против revert — проверяют переписывание-против-дописывания и общее-против-локального. Оба «отменяют», но противоположно:
git revertдописывает новый коммит, инвертирующий более ранний. История сохранена. Безопасно на общих ветках — так отменяют запушенный коммит.git resetдвигает указатель ветки назад, переписывая историю (а с--hard— и рабочее дерево). Безопасно только для локальных, незапушенных коммитов.
Ответ в одно предложение: «Revert, чтобы отменить уже запушенное, потому что он добавляет новый коммит и сохраняет историю; reset, чтобы отменить локальные коммиты, потому что он переписывает историю и не должен касаться общих веток».
Что такое HEAD, ветка и индекс? Проверяют, знаешь ли ты по-настоящему простую модель git. Три указателя и область подготовки:
- Ветка — это просто подвижный указатель на один коммит. Не более — файл из 40 символов под
.git/refs/. - HEAD — указатель на текущую ветку (обычно) — он говорит «где я и что станет родителем следующего коммита». Detached HEAD значит, что он указывает прямо на коммит, а не на ветку.
- Индекс (область подготовки) — это предлагаемый следующий коммит, снимок, который заморозит
git commit.
Ответ в одно предложение: «Ветка — указатель на коммит, HEAD — указатель на мою текущую ветку, а индекс — область подготовки, держащая снимок, который запишет мой следующий коммит».
▸Почему это работает
Почему «ветка — это просто указатель» так важно на собеседованиях? Потому что почти любое запутанное поведение git растворяется, как только ты это держишь. Создание ветки мгновенно, потому что это запись одного файла в 40 байт. Переключение веток — просто сдвиг HEAD. «Потеря» коммитов после reset — на самом деле просто сдвиг указателя с них: коммиты всё ещё существуют, без ссылок, ровно поэтому reflog может их вернуть. Модель указателей — ключ, отпирающий остальное.
Восстановление потерянных коммитов и модель хранения — проверяют, паникуешь ли ты. Два связанных вопроса:
- «Ты сделал reset —hard и потерял коммит — восстанови». «
git reflogперечисляет каждую позицию, что держал HEAD; я нахожу там SHA потерянного коммита и делаюgit branchилиgit resetназад к нему — коммит был без ссылок, никогда не удалён». - «Git хранит diff’ы или снимки?» «Снимки — каждый коммит ссылается на полное дерево проекта; git вычисляет diff’ы по запросу для отображения и хранит объекты эффективно (дельты в packfile), но модель — снимок на коммит, а не цепочка патчей».
Модель снимков — причина, по которой git быстр в ветвлении и по которой checkout любого коммита дёшев: он просто читает дерево этого коммита.
Fast-forward против three-way и force-with-lease против force — проверяют инстинкты безопасности. Два момента, отделяющие сеньоров от остальных:
- Fast-forward против three-way merge: «Если целевая ветка не разошлась, git просто сдвигает указатель вперёд — fast-forward, без merge-коммита. Если у обеих сторон новые коммиты, git делает three-way merge через общего предка и создаёт merge-коммит».
- Почему
--force-with-leaseвместо--force: «--forceбезусловно перезаписывает remote и может стереть запушенный коммит коллеги;--force-with-leaseсначала проверяет, что remote всё ещё там, где я видел его в последний раз, и прерывается, если кто-то запушил — так я никогда не затру работу, которой не видел».
Этот последний ответ — самое сеньорски звучащее предложение на git-собеседовании, потому что он показывает, что ты оптимизируешь под неуничтожение чужой работы.
Раунд быстрых вопросов, отвеченный как сеньор.
«Проведи меня через отмену коммита, уже запушенного в main». — «Раз он общий, я никогда не переписываю историю. Я делаю git revert <sha>, который дописывает новый коммит, инвертирующий изменение, и пушу обычно. Reset переписал бы общую историю и сломал каждый клон».
«Ты сделал git reset --hard, и твои последние два коммита исчезли — верни их». — «Они без ссылок, а не удалены. git reflog показывает каждую позицию HEAD; я нахожу SHA до reset и делаю git reset --hard <sha> или git branch rescue <sha>, чтобы их переякорить».
«Rebase или merge для фичеветки, что вот-вот ляжет на main?» — «Rebase фичи на origin/main, пока она ещё моя, чтобы держать её линейной и ревьюабельной; интеграция в сам main происходит через PR. Я никогда не rebase’ю коммиты, которые другие уже стянули».
«Почему --force-with-lease?» — «Он отказывается пушить, если remote сдвинулся с моего последнего fetch, так что я могу переписывать свою ветку, ни разу не затерев коммит, который коллега в неё запушил».
Четыре ответа, четыре ментальные модели — хранение, указатели, интеграция, безопасность отмены — и ни следа заучивания команд.
▸Частая ошибка
Ловушка — отвечать командами вместо моделей. «Как отменить запушенный коммит?», отвеченное как «git reset —hard и force push», — это красный флаг: показывает, что ты переписал бы общую историю. Сеньорский ответ начинается с принципа (никогда не переписывай то, что есть у других) и лишь затем называет инструмент (revert). Интервьюеры слушают модель под командой; начинай с модели, и команда следует естественно.
Интервьюер спрашивает: «Как ты отменишь коммит, уже на общем main, и почему именно так?» Какой сеньорский ответ?
Сеньорское git-собеседование проверяет ментальные модели, а не синтаксис, и они сводятся к четырём: хранение (git держит снимки, не diff’ы), указатели (ветка — указатель на коммит, HEAD указывает на текущую ветку, индекс — следующий снимок), интеграция (rebase локально для линейной истории, merge для общего; fast-forward, когда не разошлись, иначе three-way) и безопасность отмены (revert дописывает и безопасен на общей истории, reset переписывает и только локален, reflog восстанавливает коммиты без ссылок, force-with-lease никогда не затирает невиданную работу). Начинай каждый ответ с принципа, затем называй команду. Это весь git-трек, сжатый в готовую к воспроизведению беглость, — и завершение этого капстоун-юнита.
Практика
Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.