Урок по треку Инструменты 7 мин

Git для собеседования за 7 минут

Коммиты и ветки, merge и rebase, reset и revert, cherry-pick, reflog и разрешение конфликтов.

Как Git хранит историю

Git хранит не диффы, а снимки. Каждый коммит указывает на дерево файлов, на родителя (или двух родителей у merge-коммита), автора и сообщение. Хеш коммита считается от всего этого, поэтому любое изменение коммита (сообщения, родителя, файлов) даёт новый коммит с новым хешем.

Ветка (branch) это просто подвижный указатель на коммит. HEAD указывает на текущую ветку (или прямо на коммит, тогда это detached HEAD).

Три зоны, через которые проходит изменение:

  • рабочая копия (working tree): файлы на диске;
  • индекс (staging area): то, что попадёт в следующий коммит (git add);
  • репозиторий: коммиты (git commit).
git status            # что изменено и что в индексе
git add -p            # добавить изменения кусками
git commit -m "fix: ..."
git log --oneline --graph --all

merge и rebase

Обе команды вливают изменения одной ветки в другую, но по-разному.

merge создаёт merge-коммит с двумя родителями. История честная, ничего не переписывается. Если целевая ветка не ушла вперёд, Git делает fast-forward: просто двигает указатель, без merge-коммита (--no-ff заставит создать его).

rebase берёт твои коммиты и заново применяет их поверх другой ветки. Получаются новые коммиты с новыми хешами, история линейная.

git switch feature
git rebase main        # переносим коммиты feature поверх main
git switch main
git merge feature      # теперь это fast-forward

Золотое правило: не делай rebase коммитов, которые уже запушены и на которых работают другие. Ты перепишешь историю, и у коллег она разойдётся с твоей. Если всё же переписал свою личную ветку, пушь через git push --force-with-lease: он откажет, если на сервере появились чужие коммиты, которых ты не видел.

git rebase -i HEAD~3 позволяет склеить (squash/fixup), переименовать (reword), удалить (drop) или переставить последние коммиты перед ревью.

reset, revert, restore

  • git reset двигает указатель текущей ветки на другой коммит. Режимы:
    • --soft: изменения из «отброшенных» коммитов остаются в индексе;
    • --mixed (по умолчанию): остаются в рабочей копии, индекс сбрасывается;
    • --hard: рабочая копия и индекс приводятся к коммиту, незакоммиченные правки теряются.
  • git revert <commit> создаёт новый коммит, отменяющий изменения указанного. История не переписывается, поэтому это безопасный способ отменить то, что уже в общей ветке.
  • git restore <file> откатывает файл в рабочей копии к индексу, git restore --staged <file> убирает файл из индекса.
git reset --soft HEAD~1   # «раскоммитить» последний коммит, правки в индексе
git revert a1b2c3d        # отменить коммит в main новым коммитом

cherry-pick

git cherry-pick <hash> применяет изменения одного коммита к текущей ветке и создаёт новый коммит (новый хеш). Типичный сценарий: хотфикс сделан в main, его нужно перенести в ветку релиза.

reflog: машина времени

git reflog хранит, куда указывал HEAD (и ветки) за последнее время (по умолчанию записи живут 90 дней, а недостижимые из веток 30 дней), только локально. Если сделал reset --hard или неудачный rebase, коммиты не исчезли сразу:

git reflog                  # находим состояние до ошибки, например HEAD@{2}
git reset --hard HEAD@{2}

Потерять безвозвратно можно только то, что ни разу не было закоммичено (или застешено).

Конфликты

Конфликт возникает, когда обе стороны изменили одни и те же строки (или одна изменила файл, а другая удалила). Git помечает место маркерами:

<<<<<<< HEAD
const limit = 10;
=======
const limit = 20;
>>>>>>> feature

Порядок: открыть файлы, выбрать итоговый вариант, убрать маркеры, git add и продолжить (git commit для merge, git rebase --continue для rebase). Передумал: git merge --abort или git rebase --abort.

Учти: при rebase «ours» это ветка, на которую переносишь (upstream), а «theirs» это твои переносимые коммиты. При merge наоборот привычно: ours это текущая ветка.

fetch, pull, stash

  • git fetch скачивает новые коммиты в remote-tracking ветки (origin/main), твои ветки не трогает.
  • git pull = fetch + merge (или rebase, если pull.rebase=true или --rebase).
  • git stash прячет незакоммиченные правки, git stash pop возвращает.

Частые ошибки

  • rebase общей ветки и push --force без --with-lease.
  • reset --hard при незакоммиченных правках: их reflog не спасёт.
  • Путают revert (новый коммит) и reset (перенос указателя).
  • Коммитят .env и секреты: удалить файл новым коммитом мало, он остаётся в истории.

Что спросят на собесе

  • Чем merge отличается от rebase и когда что использовать.
  • Как отменить коммит, который уже в общей ветке, и почему не reset.
  • Что делают reset --soft, --mixed, --hard.
  • Как восстановить ветку после неудачного reset --hard или rebase.
  • Как разрешить конфликт при rebase и что такое cherry-pick.

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.