Git на собеседовании спрашивают почти всегда, и вопросы выглядят как викторина на знание команд. Проверяют другое: есть ли у тебя модель того, что Git делает с репозиторием, или ты заучил флаги и надеешься не перепутать. Разница видна с первой фразы. «Rebase переписывает историю» — заученный факт. «Rebase проигрывает твои коммиты заново поверх другой ветки, получаются новые хеши — поэтому его не делают на общих ветках» — уже модель.
Ниже — вопросы, которые всплывают чаще всего, и то, что за ними стоит. Хороший ответ устроен одинаково: назвать механизм, дать одно правило или компромисс, замолчать. Три факта, из которых выводится почти всё остальное: ветка — подвижный указатель на коммит, коммит — снимок плюс ссылка на родителя, HEAD — «где ты сейчас». Если ответ не сходится с этими тремя, он неверный.
Локальное состояние против удалённого
Чем git fetch отличается от git pull
fetch скачивает новые коммиты и ссылки с удалённого репозитория, но не трогает твою рабочую ветку. Он обновляет только remote-tracking ссылки вроде origin/main, чтобы можно было сначала посмотреть, что изменилось. pull — это fetch плюс автоматический merge (или rebase) этих изменений в текущую ветку.
Практический вывод: fetch — вариант «посмотреть перед прыжком», pull — удобство, которое однажды удивит неожиданным merge-коммитом. Многие команды включают git config pull.rebase true, чтобы история оставалась линейной.
Что проверяют: понимаешь ли ты разницу между локальным и удалённым состоянием, а не просто две команды.
Что такое индекс (staging area)
Промежуточный слой между рабочей директорией и репозиторием. git add переносит изменения туда, git commit записывает ровно то, что лежит в индексе, а не то, что в файлах сейчас. Этот лишний шаг и позволяет собрать аккуратный коммит: застейджить часть файлов или даже часть одного файла через git add -p, вместо «закоммитить всё, что накопилось».
В Git три дерева: рабочая директория, индекс и HEAD (последний коммит). Почти любая непонятная команда становится понятной, если задать вопрос: какое из трёх деревьев она трогает?
HEAD и detached HEAD
HEAD — указатель на текущее место. Обычно он смотрит на ветку, а ветка — на коммит. Отсоединённый (detached) HEAD — это когда HEAD смотрит прямо на коммит, минуя ветку. Так бывает после git checkout по хешу или тегу. Смотреть по сторонам можно, коммитить тоже, но эти коммиты не принадлежат ни одной ветке — уйдёшь, и найти их будет сложно.
Спасение простое: git switch -c fix-here, и коммиты снова живут на ветке.
Ветки и слияния
Merge против rebase
merge соединяет две ветки merge-коммитом и сохраняет историю такой, какой она была. Нелинейно, зато честно. rebase проигрывает твои коммиты поверх другой ветки и даёт чистую линию — но коммиты становятся новыми, с новыми хешами, а старые остаются брошенными.
| Признак | merge | rebase |
|---|---|---|
| Форма истории | нелинейная, с точками слияния | линейная, как будто так и было |
| Хеши коммитов | сохраняются | пересоздаются заново |
| Где применять | общие ветки, релизы | своя локальная работа перед отправкой |
| Риск для команды | нет | есть, если ветку уже кто-то забрал |
Золотое правило одно: rebase — для своих непушнутых коммитов, никогда для ветки, которую уже кто-то скачал. Переписанная общая история заставляет всех остальных разбираться с коммитами, которых в твоей ветке больше нет.
Fast-forward и конфликты
Если целевая ветка не разошлась с твоей и просто отстала, Git не создаёт merge-коммит, а двигает указатель вперёд. Это fast-forward. Разошлись — появится настоящий merge-коммит. Флаг git merge --no-ff нужен, когда ты хочешь видеть коммит слияния специально, чтобы ветки фич читались в истории.
Конфликт Git размечает маркерами прямо в файле (границы HEAD и вливаемой ветки). Ты открываешь файл, приводишь его к тому результату, который считаешь правильным, удаляешь маркеры, stage и продолжаешь: git commit при слиянии или git rebase --continue. Инструмент не решит за тебя — это человеческое суждение о том, как должен выглядеть код. Передумал — git merge --abort откатывает всё назад.
git cherry-pick
Берёт изменения одного конкретного коммита и применяет их в текущей ветке как новый коммит. Полезно, когда багфикс нужно продублировать и в main, и в релизной ветке, не вливая туда целую ветку. Компромисс: коммит создаётся копией, и если злоупотреблять, получишь расходящиеся копии одного изменения, которые потом больно сводить.
Как отменять сделанное
Здесь правило зеркалит rebase: публичное отменяй через revert, приватное — через reset. revert добавляет новый коммит, который стирает эффект предыдущего, и история остаётся целой — безопасно для всего, что уже отправлено. reset двигает указатель ветки назад, то есть переписывает историю, — только для локальной непушнутой работы. Сделать reset на общей ветке и запушить силой — классический способ испортить коллеге день.
Что делают --soft, --mixed и --hard
Все три двигают HEAD на указанный коммит. Разница в том, сколько они трогают после этого, и это ровно три дерева:
| Флаг | Двигает HEAD | Индекс | Рабочая директория |
|---|---|---|---|
| --soft | да | сохранён (всё застейджено) | сохранена |
| --mixed (по умолчанию) | да | сброшен (изменения не в индексе) | сохранена |
| --hard | да | сброшен | уничтожена |
Отсюда и области применения: --soft — чтобы пересобрать коммиты (например, склеить последние несколько в один), --mixed — чтобы вытащить изменения из индекса, --hard — единственный, который теряет работу. К нему стоит тянуться осознанно.
stash и reflog
git stash откладывает незакоммиченные изменения и возвращает рабочую директорию в чистое состояние. Удобно, когда нужно срочно переключиться на другую ветку, не коммитя недоделанное. Обратно — git stash pop. Это рабочий приём, а не часть истории: в логе проекта сташ не остаётся.
А вот если ты сделал git reset --hard и потерял коммиты — обычно их можно вернуть через git reflog. Reflog записывает каждое перемещение HEAD, включая те, до которых уже не добраться ни с одной ветки. Находишь в списке нужный хеш и либо сбрасываешься на него, либо создаёшь ветку git branch rescue с этим хешем.
Упомянуть reflog самому, без вопроса — хороший ход на интервью. Он показывает, что ты знаешь: Git почти ничего не удаляет по-настоящему, пока не отработает сборка мусора.
Рабочие задачи, а не теория
Как найти коммит, который сломал сборку
git bisect. Отмечаешь заведомо хороший коммит и заведомо плохой, Git сам переключает на середину, ты проверяешь и помечаешь — и он бинарным поиском доходит до первого плохого коммита за log(n) шагов вместо честного перебора. Проверки можно автоматизировать: git bisect run запускает тест на каждом шаге. Закончил — git bisect reset.
Как поправить последний коммит
git commit --amend — исправить сообщение или добавить забытый файл. Важная деталь: amend пересоздаёт коммит с другим хешем, поэтому годится только для того, что ты ещё не отправлял. Amend на пушнутом коммите — та же ловушка с общей историей, что у rebase и reset.
В репозиторий попал .env
Добавить файл в .gitignore недостаточно — это не перестаёт отслеживать уже закоммиченный файл. Нужно снять его с отслеживания: git rm --cached .env, и это отдельным коммитом.
Если в файле был секрет и он уже пушнут, он остался в истории навсегда. Удаление из текущего дерева прошлые коммиты не чистит. Правильный порядок действий: сначала отозвать и перевыпустить секрет, потом чистить историю (git filter-repo или BFG). И помнить, что у всех, кто уже сделал pull, копия секрета всё равно осталась. Именно такой ответ — «сначала ротация, потом история» — интервьюеры и хотят услышать.
Что делать с этим на самом собеседовании
Разница между «прошёл» и «не прошёл» — показать модель вместо перечисления флагов. Расскажи, что команда делает с указателями, историей и тремя деревьями, назови одно правило, которое реально важно, и остановись. Не растекайся по всем опциям подряд.
- Опирайся на механизм. «Я бы откатил указатель ветки назад и оставил изменения в индексе» звучит лучше, чем попытка вспомнить, это был --soft или --mixed. Если сомневаешься — опиши эффект и скажи, что уточнишь по документации. Это читается лучше, чем уверенно названный неверный флаг.
- Сам предлагай страховку. Reflog, ротация секретов, «на общей ветке я так делать не буду» — всё это сигнал, что команды ты не только читал.
- Не уверен в названии команды — назови намерение. Интервьюер прекрасно понимает разницу между «не помню флаг» и «не понимаю, как это работает».
- Прогоняй ответы вслух. Git-вопросы любят формулировать как «а что будет, если», и тут важен не только факт, но и то, как ты его произносишь без пауз.
Типичные ошибки здесь почти всегда одни и те же: пересказ мануала без модели, молчание про риски переписывания истории и попытка спрятать незнание за уверенным тоном. Достаточно один раз честно сказать «rebase на общей ветке — плохая идея, потому что меняются хеши», и половина остальных вопросов про rebase, reset и amend проверится автоматически.
Итог простой. Git — система с небольшим числом понятий и очень большим числом производных от них команд. Держи в голове три дерева и то, что ветка — это указатель, называй механизм вместо заученного флага — и почти любой вопрос про Git перестаёт быть викториной на память и становится разговором о том, как ты управляешь историей изменений.
Комментарии (0)
Войдите, чтобы комментировать.
Пока нет комментариев. Будьте первым.