Git для собеседования на DevOps / SRE

Курс помогает системно повторить Git на уровне, который обычно проверяют на собеседованиях DevOps/SRE. Разберём ключевые команды, ветвление и merge-стратегии, работу с удалёнными репозиториями, а также практики командной разработки и диагностику проблем.

1. База Git: коммиты, история, индексация и откат изменений

База Git: коммиты, история, индексация и откат изменений

Git на собеседованиях DevOps / SRE проверяют не как инструмент разработчика, а как инструмент безопасного изменения инфраструктурного кода: уметь объяснить, что именно попадёт в релиз, как быстро найти источник регрессии, и как откатиться без потери данных.

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

  • что такое коммит и как устроена история
  • что такое индекс (staging area) и зачем он нужен
  • как смотреть изменения и историю
  • как откатывать изменения безопасно и разрушительно (и как восстановиться)
  • !Схема трёх зон Git и команд, которые перемещают изменения между ними

    Модель Git в одном абзаце

    Git хранит историю как цепочку (точнее, граф) коммитов. Каждый коммит:

  • указывает на снимок состояния файлов проекта
  • содержит метаданные (автор, дата) и сообщение
  • хранит ссылки на родительские коммиты (обычно один родитель, при merge — два)
  • Важная привычка для собеседования: говорить не «Git хранит дельты», а «коммит — это снимок, а Git оптимизирует хранение под капотом». Это соответствует формулировке из книги Pro Git.

    Источник: Pro Git (Scott Chacon, Ben Straub) — Git Basics

    Коммит как единица изменения

    Что считается хорошим коммитом

    В DevOps/SRE контексте коммит должен быть удобен для:

  • ревью
  • поиска причины инцидента
  • быстрого отката
  • Практика:

  • один коммит — одна логическая правка
  • сообщение: короткий заголовок + (опционально) пояснение почему сделано изменение
  • не смешивать рефакторинг и функциональную правку в одном коммите (сложнее откатывать)
  • Что такое HEAD

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

    Полезно проговаривать на собеседовании:

  • «переместить HEAD» — значит изменить, какой коммит считается текущим
  • «откатить» — может означать разные операции: переместить HEAD, создать обратный коммит, вернуть файлы в рабочей директории
  • Индекс (staging area): зачем он нужен

    Индекс (staging area) — промежуточный слой между рабочей директорией и коммитом. Он позволяет:

  • коммитить часть изменений, даже если в рабочей директории изменено много файлов
  • готовить релизные изменения постепенно
  • делать аккуратные коммиты, полезные для git bisect и откатов
  • Типичный поток:

  • Вы меняете файлы в рабочей директории.
  • Командой git add добавляете в индекс то, что хотите включить в следующий коммит.
  • Командой git commit фиксируете индекс как новый коммит.
  • Ключевая формулировка: git add добавляет изменения в индекс, а не «в Git».

    Осмотр изменений: что именно будет закоммичено

    Команды, которые помогают не ошибиться перед коммитом:

  • git status — показывает состояние рабочей директории и индекса
  • git diff — показывает изменения в рабочей директории относительно индекса
  • git diff --staged — показывает изменения в индексе относительно HEAD
  • Пример типичного сценария:

    Собеседования любят вопрос: «Как закоммитить только часть файла?» Короткий ответ: git add -p.

    Справка: Документация git-add

    История: как читать и объяснять

    git log и полезные варианты

  • git log — подробная история
  • git log --oneline --decorate --graph --all — компактный вид, удобен для объяснения графа коммитов
  • git show <commit> — что именно в конкретном коммите (патч + метаданные)
  • Справка: Документация git-log

    Хеш коммита: почему он важен

    Коммиты идентифицируются хешем. В практике DevOps/SRE хеш полезен, когда:

  • нужно точно сослаться на версию артефакта/конфига
  • нужно откатить конкретный коммит
  • нужно воспроизвести состояние репозитория на момент инцидента
  • Важно: в большинстве команд можно использовать короткий префикс хеша, если он однозначен.

    Откат и отмена: разные задачи — разные команды

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

    Классификация действий

    | Задача | Что меняется | Типичный инструмент | |---|---|---| | Убрать локальные правки в файле (не staged) | рабочая директория | git restore <file> | | Убрать из индекса (unstage), но оставить правки в файлах | индекс | git restore --staged <file> | | Вернуть проект к состоянию старого коммита, сохранив историю | история + новый коммит | git revert <commit> | | Переместить HEAD на другой коммит (переписать локальную историю) | HEAD и, опционально, индекс/рабочая директория | git reset |

    Справка: Документация git-restore

    git restore: вернуть файлы в нужное состояние

    Типовые случаи:

  • git restore file.txt — выбросить незакоммиченные изменения в file.txt (опасно, изменения пропадут)
  • git restore --staged file.txt — убрать файл из индекса (unstage), но оставить изменения в рабочей директории
  • На собеседовании важно проговаривать, что именно вы теряете. git restore может быть разрушительным для незакоммиченных правок.

    git reset: переместить HEAD и управлять индексом

    git reset часто проверяют как индикатор понимания staging area.

    Три режима reset

  • git reset --soft <commit>
  • - двигает HEAD на указанный коммит - индекс и рабочая директория остаются как были - удобно, если хотите «переупаковать» последние коммиты, не теряя подготовленных изменений

  • git reset --mixed <commit> (обычно это режим по умолчанию)
  • - двигает HEAD - сбрасывает индекс до состояния указанного коммита - рабочая директория сохраняет изменения (они становятся unstaged)

  • git reset --hard <commit>
  • - двигает HEAD - сбрасывает индекс - сбрасывает рабочую директорию - разрушительно: локальные незакоммиченные изменения пропадут

    Справка: Документация git-reset

    Важное собеседовательное уточнение

  • git reset переписывает историю для текущей ветки (локально).
  • Если вы уже запушили коммиты в shared ветку, reset может создать проблемы другим (потребуются force push и согласование процесса).
  • git revert: «откат» без переписывания истории

    git revert <commit> создаёт новый коммит, который логически отменяет изменения указанного коммита.

    Почему это любят в production-процессах:

  • история остаётся линейной и честной
  • не нужно переписывать опубликованную историю
  • проще объяснить аудитору и коллегам: «вот коммит, который откатил проблему»
  • Справка: Документация git-revert

    Восстановление после ошибок: git reflog

    git reflog показывает, куда указывал HEAD в прошлом. Это ваш «чёрный ящик», который часто спасает после:

  • случайного git reset --hard
  • перемещения ветки
  • потери ссылки на коммит
  • Практический смысл:

  • даже если коммит «пропал из истории ветки», какое-то время на него ещё можно сослаться через reflog и вернуть
  • Справка: Документация git-reflog

    Мини-набор для собеседования: что уметь сказать вслух

  • Коммит — это снимок состояния проекта с метаданными и ссылкой на родителя.
  • HEAD — указатель на текущий коммит.
  • Индекс (staging) — слой, который определяет, что попадёт в следующий коммит.
  • git diff и git diff --staged отвечают на разные вопросы.
  • git reset — про перемещение HEAD и управление индексом/рабочей директорией, часто с переписыванием истории.
  • git revert — безопасный откат через новый коммит.
  • git reflog — способ восстановиться после «необратимых» действий.
  • 2. Ветки и слияния: rebase, merge, cherry-pick, разрешение конфликтов

    Ветки и слияния: rebase, merge, cherry-pick, разрешение конфликтов

    На собеседованиях DevOps / SRE ветки и слияния проверяют как умение безопасно доставлять изменения в инфраструктурный код, не ломая историю и не создавая проблем коллегам. В прошлой статье мы разобрали коммиты, HEAD, staging и откаты (reset, revert, reflog). Теперь опираемся на эти понятия, потому что ветки и слияния в Git — это, по сути, управление указателями на коммиты и тем, как строится история.

    !Граф коммитов: merge против rebase и что происходит с указателями

    Что такое ветка в Git

    Ветка в Git — это имя-указатель на конкретный коммит. Когда вы делаете новый коммит в этой ветке, указатель ветки перемещается вперёд на новый коммит, а HEAD обычно указывает на текущую ветку.

    Практические следствия (важно проговаривать на интервью):

  • Ветка почти ничего не “весит”: это просто ссылка на коммит.
  • “Слить ветку” означает сделать так, чтобы история содержала изменения из обеих линий разработки.
  • Конфликты возникают не “между ветками”, а при попытке применить два набора изменений к одним и тем же строкам/участкам файлов.
  • Справка: Pro Git — Git Branching

    Merge: объединение историй

    git merge берёт изменения из одной ветки и интегрирует их в текущую ветку.

    Fast-forward merge

    Fast-forward возможен, когда текущая ветка не имеет своих новых коммитов относительно ветки, которую мы вливаем. Тогда Git просто передвигает указатель ветки вперёд.

    Признаки и последствия:

  • Не создаётся отдельный merge-коммит.
  • История остаётся линейной.
  • В инфраструктурных репозиториях это часто нормально для короткоживущих feature-веток.
  • Команды:

    Merge commit (не fast-forward)

    Если в обеих ветках есть свои коммиты, Git создаёт merge-коммит с двумя родителями.

    Плюсы merge-коммита:

  • История честно отражает факт параллельной работы.
  • Легче “откатить целиком фичу” одним git revert -m (это часто обсуждают на уровне понимания, даже если команду используют редко).
  • Минусы merge-коммита:

  • История может стать менее читаемой, особенно при большом количестве веток.
  • Команды:

    Справка: Документация git-merge

    Rebase: перенос коммитов и переписывание истории

    git rebase берёт коммиты вашей ветки и “переигрывает” их поверх другой базы. Важно: Git создаёт новые коммиты с новыми хешами, даже если изменения выглядят одинаково.

    Типичный сценарий: у вас есть feature, основанная на старом main, и вы хотите обновить её последними изменениями main, сохранив линейную историю.

    Почему rebase любят и почему его боятся

    Плюсы:

  • Линейная история: проще читать git log, проще делать git bisect.
  • Можно “почистить” серию коммитов до PR, используя интерактивный rebase.
  • Минусы и риски:

  • Rebase переписывает историю: если эти коммиты уже опубликованы и кто-то на них опирается, вы создадите проблемы (потребуется согласованный --force-with-lease, появятся дубликаты коммитов, сложнее синхронизация).
  • Правило для собеседования, которое звучит убедительно:

  • Rebase безопасен на локальных, ещё не расшаренных коммитах.
  • Merge безопаснее для опубликованных веток, если вы не уверены в процессе.
  • Справка: Документация git-rebase

    Интерактивный rebase (то, что часто ждут на интервью)

    git rebase -i позволяет упорядочить и “упаковать” историю перед тем, как отправить её на ревью.

    Что обычно делают:

  • squash или fixup: объединить мелкие коммиты.
  • reword: исправить сообщения.
  • drop: убрать случайные коммиты.
  • Пример:

    В DevOps/SRE это полезно, когда вы, например, поэтапно правили Terraform/Helm и хотите оставить понятную историю: “добавили ресурс”, “добавили мониторинг”, “добавили алерты”, а не 20 промежуточных “fix”.

    Справка: Pro Git — Rewriting History

    Cherry-pick: точечный перенос коммита

    git cherry-pick применяет изменения конкретного коммита в текущую ветку и создаёт новый коммит.

    Это полезно в продакшене, когда:

  • нужно срочно перенести фикс из main в release (или наоборот) без слияния всей ветки;
  • нужно забрать один полезный коммит из чужой ветки, не забирая остальное.
  • Пример:

    Риски и нюансы:

  • Это тоже создаёт новый коммит с новым хешем.
  • Если потом вы будете мёржить ветки целиком, возможны повторы или конфликты, если Git не сможет корректно сопоставить изменения.
  • Справка: Документация git-cherry-pick

    Конфликты: почему возникают и как их разруливать

    Конфликт возникает, когда Git не может автоматически объединить изменения. Чаще всего это ситуация, когда в двух линиях разработки изменён один и тот же участок файла.

    Как выглядит конфликт

    Git помечает конфликтные места маркерами:

  • <<<<<<< ваша версия
  • ======= разделитель
  • >>>>>>> версия другой стороны
  • Дальше ваша задача — сделать файл корректным (убрать маркеры, оставить правильный результат) и сообщить Git, что конфликт решён.

    Универсальный алгоритм разрешения конфликтов

  • Понять контекст: что именно пытались объединить.
  • Открыть конфликтные файлы и привести их к правильному итоговому виду.
  • Пометить файлы как решённые через git add.
  • Завершить операцию:
  • при merge: сделать коммит (Git сам предложит сообщение merge-коммита);
  • при rebase: продолжить rebase.
  • Команды, которые обычно ожидают услышать:

    Полезные “кнопки безопасности”:

  • git merge --abort — откатить merge и вернуться к состоянию до попытки.
  • git rebase --abort — откатить rebase и вернуться к исходному состоянию.
  • Справка: Документация git-status

    Типовые причины конфликтов в DevOps/SRE репозиториях

  • В одном PR меняли values Helm, в другом — те же ключи.
  • Параллельно правили один и тот же Terraform-модуль.
  • В разных ветках “переформатировали” файлы (например, terraform fmt) и одновременно вносили логические правки.
  • Практика для снижения конфликтов:

  • Делать изменения “узкими” и логически цельными (связь с прошлой статьёй про хорошие коммиты).
  • Часто подтягивать базовую ветку (merge или rebase — в зависимости от процесса).
  • Отдельно коммитить массовое форматирование, чтобы оно не смешивалось с логикой.
  • Merge или rebase: что говорить на собеседовании

    Вопрос звучит просто, но проверяет зрелость.

    Обычно ждут, что вы различите:

  • техническую разницу: merge добавляет merge-коммит (или fast-forward), rebase переписывает коммиты;
  • процессную разницу: опубликованную историю лучше не переписывать без правил.
  • Удобная формулировка:

  • В feature-ветке до PR можно делать rebase (включая rebase -i), чтобы подготовить чистую историю.
  • После публикации ветки и начала совместной работы чаще используют merge (или строго регламентированный rebase с --force-with-lease, если команда так договорилась).
  • Мини-набор команд для интервью

  • git branch, git switch -c <name> — создать/переключиться на ветку.
  • git merge <branch> — влить ветку.
  • git rebase <upstream> — перенести коммиты на новую базу.
  • git rebase -i <range> — упорядочить/склеить коммиты перед ревью.
  • git cherry-pick <commit> — точечно перенести коммит.
  • git status, git diff — понять, что происходит при конфликте.
  • git merge --abort, git rebase --abort — безопасно отменить неудачную попытку.
  • Связь с предыдущей темой про откаты

    При работе с ветками важно правильно выбирать инструмент отката:

  • Если нужно отменить изменения, которые уже попали в общую ветку, чаще выбирают git revert (без переписывания истории).
  • Если вы переписали историю через rebase и что-то пошло не так, часто спасает git reflog (вернуть “пропавшие” состояния HEAD).
  • Справка: Документация git-revert

    3. Удалённые репозитории: fetch/pull/push, теги, upstream и workflow

    Удалённые репозитории: fetch/pull/push, теги, upstream и workflow

    В первых двух темах курса мы разобрали локальную модель Git: коммиты, HEAD, staging, историю, а также ветки, merge/rebase, cherry-pick и конфликты. На собеседованиях DevOps / SRE следующий слой вопросов почти всегда про работу с удалёнными репозиториями: как безопасно синхронизироваться с командой, как доставлять изменения в shared-ветки, как маркировать релизы тегами и как объяснить выбранный workflow.

    !Диаграмма показывает, что fetch обновляет remote-tracking ветки, pull переносит изменения в вашу локальную ветку, а push публикует ваши коммиты

    Удалённый репозиторий и remote-tracking ветки

    Удалённый репозиторий в Git описывается как remote (часто по умолчанию это origin). Важная деталь: после git fetch Git не меняет вашу локальную ветку напрямую, а обновляет remote-tracking ветки вида origin/main, origin/release.

    Ключевые формулировки для интервью:

  • origin/main это не ветка на сервере и не ваша локальная ветка, а локальная ссылка, отражающая последнее известное состояние main на origin.
  • git fetch безопасен: он не трогает рабочую директорию и не переписывает ваши коммиты, а только приносит объекты и двигает remote-tracking ссылки.
  • Полезные команды:

    Справка: git-fetch, Pro Git — Remotes

    Fetch: получить изменения, не меняя вашу ветку

    git fetch скачивает новые коммиты, теги и обновляет remote-tracking ветки.

    Типичный безопасный цикл перед любыми действиями:

  • git fetch --all --prune
  • Посмотреть, что изменилось: git log --oneline --decorate --graph --all
  • Сравнить вашу ветку с origin/main: git diff main..origin/main
  • --prune удаляет локальные remote-tracking ссылки на ветки, которые удалили на сервере.

    Справка: git-fetch

    Pull: fetch плюс интеграция (merge или rebase)

    git pull это удобная композиция из двух шагов:

  • git fetch
  • Интеграция в текущую ветку
  • По умолчанию интеграция часто происходит через merge, но это зависит от настроек и команды. Важный момент для интервью: pull может неожиданно создать merge-коммит или начать rebase, поэтому в критичных ситуациях многие предпочитают делать fetch, а затем явное merge или rebase.

    Pull с merge

    Эффект: обновит origin/main, затем сольёт origin/main в вашу локальную main.

    Pull с rebase

    Эффект: обновит origin/main, затем переместит ваши коммиты feature поверх обновлённой базы. Это часто соответствует процессу: держать feature-ветку актуальной и линейной, но важно помнить из прошлой темы: rebase переписывает коммиты.

    Если команда договорилась всегда использовать rebase при pull, это часто фиксируют настройкой:

    Справка: git-pull

    Push: опубликовать коммиты и обновить ветки на сервере

    git push отправляет ваши коммиты и двигает ветку на удалённом репозитории.

    Первый push и привязка upstream

    Если вы создали новую ветку локально, при первом push удобно сразу задать upstream:

    После этого:

  • git push будет понимать, куда пушить по умолчанию
  • git pull будет понимать, откуда тянуть
  • в git branch -vv будет видно отслеживание
  • Справка: git-push

    Upstream: что именно означает

    Upstream для локальной ветки это удалённая ветка, которую локальная ветка отслеживает. Это отвечает на вопросы:

  • с чем сравнивать, когда вы смотрите статус “ahead/behind”
  • куда по умолчанию делает push и откуда по умолчанию делает pull
  • Проверка:

    Установка или смена upstream:

    Справка: git-branch

    Force push и почему DevOps/SRE должны быть осторожны

    git push --force переписывает историю удалённой ветки. Это ломает работу коллег, если они уже основывались на старых коммитах.

    Если процесс допускает переписывание истории в PR-ветках, на собеседовании лучше говорить про более безопасный вариант:

    Смысл --force-with-lease: Git выполнит force push только если удалённая ветка не изменилась с момента, когда вы её последний раз видели (то есть вы случайно не затрёте чужие коммиты).

    Справка: git-push

    Теги: маркировка релизов и “точки в истории”

    В DevOps/SRE теги часто используют как:

  • метки релизов v1.2.3
  • ссылки на состояние инфраструктуры на момент инцидента
  • точки для сборки артефактов в CI
  • Важно: тег указывает на конкретный коммит. В отличие от ветки, тег обычно не “двигают”.

    Справка: git-tag, Pro Git — Tagging

    Lightweight и annotated теги

  • Lightweight тег это просто имя, указывающее на коммит.
  • Annotated тег это полноценный объект Git с сообщением, автором и датой, и его можно подписывать (GPG).
  • Для релизов чаще рекомендуют annotated:

    Публикация тегов на сервер

    По умолчанию git push теги не отправляет.

    Отправить конкретный тег:

    Отправить все теги:

    Удалить тег на сервере:

    Или в более читаемой форме:

    Справка: git-push, git-tag

    Origin и upstream: частый сценарий с форками

    На собеседованиях иногда дают ситуацию: у вас fork репозитория.

    Типичная договорённость по именам remote:

  • origin это ваш fork
  • upstream это основной репозиторий организации
  • Добавить upstream:

    Дальше частый процесс:

  • Обновить локальную main из upstream/main
  • Запушить в свой fork origin/main
  • Здесь --ff-only полезен как “предохранитель”: он обновит ветку только fast-forward, не создавая merge-коммитов случайно.

    Справка: git-remote, git-merge

    Workflow для DevOps/SRE: что важно уметь объяснить

    Вопрос “какой workflow вы используете” проверяет не названия, а понимание компромиссов: стабильность, скорость доставки, аудит и откаты.

    Частый вариант: trunk-based с короткими ветками

    Суть:

  • main всегда в рабочем состоянии
  • изменения живут в коротких feature-ветках
  • интеграция через PR и CI
  • релизы размечаются тегами
  • Типичный цикл:

  • git switch -c feature/...
  • Коммиты маленькими логическими порциями (из первой статьи)
  • Регулярно обновляться от origin/main через fetch + rebase или merge по правилам команды
  • PR, ревью, CI
  • Merge в main (часто через merge-commit или squash-merge, зависит от политики)
  • Тег релиза и деплой
  • Что хорошо проговаривать:

  • почему main защищают (branch protection), и прямой push запрещён
  • почему для отката в main чаще используют git revert, а не переписывание истории
  • Release-ветки и hotfix

    Если есть отдельная release/* ветка, то часто:

  • новые фичи идут в main
  • в release попадают только отобранные коммиты
  • хотфикс в release могут переносить обратно в main (или наоборот) через cherry-pick
  • Это связывает текущую тему с прошлой статьёй про cherry-pick: в продакшене это реальный инструмент для точечного переноса.

    Что спросить у команды, чтобы выбрать правильные команды Git

    На интервью полезно уточнять процесс, а не угадывать:

  • разрешён ли rebase в опубликованных ветках
  • допускается ли force-with-lease и где именно
  • как принято обновлять feature-ветки: merge или rebase
  • как размечают релизы: теги, release-ветки, оба варианта
  • Мини-набор команд для интервью по удалённым

  • git remote -v показать remotes
  • git fetch --all --prune безопасно обновиться
  • git pull понимать как fetch + merge/rebase
  • git push -u origin <branch> первый push с upstream
  • git branch -vv увидеть tracking и ahead/behind
  • git push --force-with-lease безопаснее, чем --force
  • git tag -a vX.Y.Z -m "..." релизные теги
  • git push origin <tag> или git push --tags публикация тегов
  • Связь с предыдущими темами

  • Понимание rebase и переписывания истории критично для pull --rebase и для безопасного --force-with-lease.
  • Понимание merge-коммитов и конфликтов важно для pull и для интеграции PR.
  • Практики “хороших коммитов” из первой статьи напрямую влияют на качество ревью, git bisect и скорость отката в main через git revert.
  • 4. Командные практики: PR/MR, code review, gitignore, хуки и стандарты коммитов

    Командные практики: PR/MR, code review, gitignore, хуки и стандарты коммитов

    Git на собеседованиях DevOps / SRE часто оценивают не по знанию отдельных команд, а по тому, как вы снижаете риск изменений в командной работе. В прошлых статьях мы разобрали локальную модель Git, ветки, merge/rebase, работу с удалёнными репозиториями, теги и --force-with-lease. Теперь соберём это в практики, которые обычно реально применяются в инфраструктурных репозиториях: PR/MR, ревью, стандарты коммитов, .gitignore и хуки.

    !Схема типичного жизненного цикла PR/MR с автоматическими проверками и ревью

    PR и MR как единица доставки изменений

    PR (Pull Request) и MR (Merge Request) это механизм, который связывает техническую часть Git (ветки, коммиты, слияния) с процессом: обсуждение, ревью, автоматические проверки, аудит.

    Термины:

  • PR обычно говорят в GitHub
  • MR обычно говорят в GitLab
  • по смыслу это одно и то же: предложение влить изменения из вашей ветки в целевую ветку (часто main)
  • Ссылки:

  • GitHub Docs: About pull requests
  • GitLab Docs: Merge requests
  • Что интервьюер обычно хочет услышать

    Не как нажать кнопку, а как вы управляете риском.

    Обычно ожидают, что вы проговорите:

  • PR это точка контроля: ревью + CI + журнал изменений
  • целевая ветка защищена: прямой push запрещён, требуются проверки и аппрувы
  • изменения должны быть маленькими и понятными, чтобы их было легко ревьюить и откатывать
  • Типичный жизненный цикл PR/MR

  • Создаёте ветку от актуальной базы
  • Делаете небольшие логические коммиты
  • Обновляете ветку от целевой ветки, чтобы снизить вероятность конфликтов
  • Публикуете ветку и открываете PR/MR
  • CI и проверки политики (например, линтеры, тесты, сканы)
  • Code review и правки по замечаниям
  • Слияние по политике команды
  • Ключевые команды, связывающие темы курса:

    Code review: как ревьюят изменения DevOps / SRE

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

    Что считать хорошим PR/MR

    Хороший PR/MR это тот, который можно быстро и безопасно:

  • понять
  • проверить
  • принять
  • откатить
  • Практика оформления описания PR/MR:

  • Что меняется, одной фразой
  • Зачем меняется, с привязкой к инциденту, задаче или требованию
  • Как проверить
  • Риски и план отката
  • Чеклист ревью для инфраструктурных репозиториев

    Ниже не универсальная истина, а список вопросов, которые показывают зрелость на интервью.

    Функциональность и корректность:

  • изменение делает ровно то, что заявлено в описании
  • нет случайных правок в соседних файлах
  • конфигурация валидна (например, формат, схемы, наличие обязательных полей)
  • Безопасность и секреты:

  • нет секретов в репозитории и в истории
  • нет случайного логирования чувствительных данных
  • понятны права и доступы (IAM, RBAC) и они минимальны
  • Надёжность и эксплуатация:

  • есть мониторинг и алерты там, где это нужно
  • есть лимиты и таймауты, чтобы сбои не разрастались
  • есть план отката: git revert для изменений в общей ветке, либо возврат версии артефакта по тегу
  • Доставка изменений:

  • PR достаточно малый, чтобы его можно было ревьюить
  • коммиты атомарные и читаемые
  • понятен эффект применения: что будет создано, изменено, удалено
  • Политики слияния: merge commit, squash, rebase merge

    На собеседованиях любят спросить: как лучше мёржить PR? Правильный ответ зависит от процесса, но важно понимать последствия.

    Три распространённые политики:

  • merge commit: сохраняет ветвление, удобно видеть контекст параллельной работы
  • squash merge: превращает весь PR в один коммит в целевой ветке, история становится проще, но теряются промежуточные коммиты
  • rebase merge: переносит коммиты PR поверх целевой ветки, история линейная, но в целевой ветке окажутся все коммиты из PR
  • Практическая формулировка для интервью:

  • если ценим аудит и контекст ветвления, подойдёт merge commit
  • если ценим короткую линейную историю в main, часто выбирают squash merge
  • если ценим линейность и хотим сохранить отдельные коммиты PR, выбирают rebase merge, но требуют дисциплины в коммитах
  • Важно связать с предыдущими темами:

  • rebase переписывает историю коммитов, поэтому его безопаснее делать до публикации или по договорённости с --force-with-lease
  • для отката уже слитого изменения в общей ветке чаще используют git revert, а не reset
  • Стандарты коммитов: что писать и зачем

    Коммит это минимальная единица истории. В DevOps/SRE хороший стандарт коммитов ускоряет:

  • ревью
  • поиск причины инцидента
  • откат
  • чтение git log и релиз-нотов
  • Базовые правила коммитов

  • один коммит, одна логическая правка
  • не смешивать форматирование и логику
  • сообщение отвечает на вопрос что и по возможности почему
  • Полезные команды из предыдущих тем, когда нужно привести историю в порядок до PR:

    Справка:

  • git-commit
  • git-rebase
  • Conventional Commits как стандарт сообщений

    Часто в командах используют формат Conventional Commits, потому что он помогает автоматизировать релиз-ноты и понимать тип изменения.

    Примеры:

    Ссылка:

  • Conventional Commits
  • На интервью полезно сказать, что стандарт важен не сам по себе, а потому что:

  • можно автоматически строить changelog
  • проще фильтровать историю по типу изменений
  • меньше споров в ревью о стиле сообщений
  • .gitignore: как не коммитить лишнее и опасное

    .gitignore описывает, какие файлы Git должен не отслеживать, когда они появляются в рабочей директории.

    Важно: .gitignore не удаляет уже отслеживаемые файлы из истории. Если файл уже был закоммичен, добавление в .gitignore его не "спрячет".

    Справка:

  • gitignore
  • Что обычно игнорируют в DevOps/SRE репозиториях

  • локальные директории IDE
  • временные файлы и кэши
  • артефакты сборки
  • файлы с секретами, которые могут появиться локально (но лучше, чтобы они вообще не создавались в репозитории)
  • Пример .gitignore для типичных инструментов:

    Как перестать отслеживать файл, если его уже закоммитили

  • Убедиться, что файл не должен быть в истории
  • Удалить его из индекса, но оставить в рабочей директории
  • Добавить в .gitignore
  • Если проблема в том, что в историю уже попали секреты, то одного rm недостаточно: секрет останется в старых коммитах. В этом случае нужен отдельный процесс реагирования: ротация секрета и переписывание истории по регламенту команды.

    Проверка, почему файл игнорируется

    Команда, которая экономит время в отладке:

    Справка:

  • git-check-ignore
  • Git hooks: автоматизация правил до CI

    Git hooks это локальные скрипты, которые Git может запускать на определённых событиях: перед коммитом, перед пушем и так далее.

    Ключевой нюанс для интервью:

  • хуки по умолчанию не версионируются и не передаются при git clone
  • значит, полагаться только на хуки нельзя, критичные проверки должны быть в CI
  • Справка:

  • githooks
  • Какие хуки чаще всего встречаются

  • pre-commit: линтеры, форматирование, быстрые проверки
  • commit-msg: проверка формата сообщения коммита (например, Conventional Commits)
  • pre-push: более тяжёлые проверки перед отправкой в удалённый репозиторий
  • Пример идеи:

  • pre-commit запускает terraform fmt и terraform validate
  • commit-msg проверяет, что сообщение коммита начинается с feat: или fix:
  • CI повторяет критичные проверки, чтобы не зависеть от локальной среды разработчика
  • Как команды распространяют хуки

    Есть два популярных подхода.

  • Использовать core.hooksPath и хранить скрипты в репозитории
  • Использовать отдельный инструмент, который устанавливает хуки одинаково для всех
  • Частый пример: фреймворк pre-commit.

  • pre-commit framework
  • На интервью сильная формулировка:

  • хуки это удобство и ускорение обратной связи
  • CI это источник истины
  • Как связать всё в единую историю изменений

    Если вас просят описать процесс целиком, удобная связка тем курса звучит так:

  • Я делаю маленькие коммиты и использую staging (git add -p), чтобы коммиты были атомарными
  • Я работаю в короткой ветке, периодически обновляю её от origin/main через fetch и затем rebase или merge по политике команды
  • Я публикую ветку с upstream и открываю PR/MR
  • PR/MR проходит CI и review по чеклисту: безопасность, эксплуатация, откат
  • Слияние делаем по политике, релиз размечаем тегом
  • Если нужно откатиться в общей ветке, использую git revert, а для восстановления после ошибок у меня есть git reflog
  • Эта последовательность показывает, что вы не просто знаете команды, а понимаете, как они поддерживают безопасную доставку изменений в production.

    5. Отладка и спасение: bisect, reflog, reset vs revert, submodules

    Отладка и спасение: bisect, reflog, reset vs revert, submodules

    В предыдущих статьях курса мы разобрали базовую модель Git (коммиты, HEAD, staging), работу с ветками (merge, rebase, cherry-pick), удалённые репозитории (fetch/pull/push, upstream, теги) и командные практики (PR/MR, ревью, хуки). Эта статья про то, что особенно любят на собеседованиях DevOps / SRE: как быстро найти источник регрессии и как безопасно восстановиться после ошибок.

    Здесь будут четыре темы, которые вместе закрывают типичные интервью-сценарии:

  • git bisect для поиска коммита, который сломал систему
  • git reflog как способ вернуть «пропавшие» коммиты после опасных операций
  • практическое сравнение reset и revert на уровне процесса и рисков
  • git submodule: что это, как работает, где ломается в CI и как это объяснить
  • !Двоичный поиск проблемного коммита с помощью git bisect

    git bisect: найти коммит, который внёс регрессию

    Что такое bisect и зачем он DevOps / SRE

    git bisect автоматизирует двоичный поиск по истории: вы даёте Git две точки в истории:

  • коммит или тег, где всё точно работало (good)
  • коммит, где точно сломано (bad)
  • Дальше Git будет переключать репозиторий на «серединные» коммиты и просить вас пометить их как good или bad, пока не найдёт первый «плохой» коммит.

    Почему это важно в DevOps/SRE:

  • ускоряет RCA, когда проблема проявилась после серии деплоев
  • хорошо сочетается с инфраструктурным кодом, где «проверка» может быть terraform plan, helm template, прогон smoke-теста
  • требует дисциплины атомарных коммитов, о которой мы говорили в первой статье
  • Документация: git-bisect

    Базовый сценарий: руками помечать good/bad

  • Стартуем bisect и задаём «плохую» точку (обычно текущий HEAD) и «хорошую» точку.
  • Git переключит рабочую директорию на выбранный коммит. Вы выполняете проверку (тест/план/запуск) и отмечаете результат.
  • Когда Git найдёт первый плохой коммит, он выведет его хеш.
  • Обязательно завершите bisect и вернитесь на исходную ветку.
  • Автоматизация: bisect run

    На собеседованиях сильный ответ звучит так: «я стараюсь автоматизировать критерий good/bad скриптом, чтобы исключить человеческую ошибку».

    Git умеет запускать команду/скрипт и интерпретировать код возврата:

  • 0 означает good
  • 1..127 означает bad
  • 125 означает skip (нельзя проверить этот коммит)
  • Пример (условный):

    Важные нюансы bisect, которые любят спрашивать

  • Если коммит невозможно проверить (например, не собирается из-за внешних причин), используйте git bisect skip.
  • Если «плохая» точка это релизный тег, а «хорошая» это предыдущий тег, это хороший признак зрелого релизного процесса.
  • Bisect работает по достижимой истории. Если у вас сложный граф, полезно заранее понимать, по какой линии вы ищете.
  • git reflog: вернуть «пропавшие» коммиты и состояния

    Что такое reflog

    git reflog показывает историю перемещений HEAD и ссылок веток локально. Это «чёрный ящик» Git: даже если вы переписали историю (reset, rebase) и коммиты исчезли из обычного git log, их часто можно найти в reflog.

    Документация: git-reflog

    Типичные аварии, которые лечит reflog

  • случайный git reset --hard
  • неудачный rebase, после которого вы потеряли нужную точку
  • вы «переехали» веткой на другой коммит и забыли, где было раньше
  • Практический сценарий восстановления после reset --hard

  • Посмотреть reflog.
  • Вы увидите записи вида HEAD@{n} и хеши.

  • Безопасный подход: создать спасательную ветку на нужной точке.
  • Переключиться на неё и проверить состояние.
  • Если нужно восстановить исходную ветку, вы выбираете действие по ситуации:
  • если это локальная ветка и вы уверены, что можно переписать историю, используйте git reset на нужный коммит
  • если это общая ветка, обычно безопаснее не переписывать её историю
  • Почему reflog часто упоминают вместе с безопасностью

    DevOps/SRE важно проговаривать ограничение: reflog в основном локальный, и его нельзя воспринимать как командный механизм восстановления для всех. Для команды источником истины остаются удалённые ветки и теги.

    reset vs revert: не команды, а выбор стратегии

    В первой статье курса мы уже обсуждали, что reset двигает HEAD и может переписывать историю, а revert создаёт новый коммит-откат. Здесь закрепим это через типовые рабочие ситуации.

    Документация: git-reset, git-revert

    Ключевая идея

  • git reset отвечает на вопрос: «я хочу, чтобы ветка указывала на другой коммит».
  • git revert отвечает на вопрос: «я хочу отменить эффект изменений, не переписывая историю».
  • Таблица выбора для интервью

    | Ситуация | Что обычно выбирают | Почему | |---|---|---| | Вы ещё не публиковали коммиты (локально) и хотите поправить историю | git reset или rebase -i | можно переписать локальную историю без ущерба другим | | Коммит уже в общей ветке (main, release) | git revert | не ломает коллегам историю, остаётся понятный аудит | | Нужно «откатить фичу целиком» после merge-коммита | git revert (с параметрами для merge) | создаёт обратный коммит, история остаётся согласованной | | Вы сделали reset --hard и потеряли коммит | git reflog + восстановление | reflog помогает найти хеш потерянного состояния |

    Что говорить про риск reset в командной работе

    На интервью ожидают, что вы проговорите процессный момент:

  • reset для опубликованных веток обычно приводит к push --force.
  • push --force опасен.
  • если процесс допускает переписывание истории в PR-ветках, лучше говорить про git push --force-with-lease как про предохранитель.
  • Документация: git-push

    Мини-сценарии, которые часто дают устно

  • «Я случайно закоммитил лишнее, но не пушил».
  • «Я запушил в feature-ветку, но хочу переписать серию коммитов до PR».
  • «Проблемный коммит уже в main, нужен безопасный откат».
  • Submodules: закрепление зависимости на коммите

    Что такое submodule

    Submodule позволяет держать один Git-репозиторий внутри другого, но важная деталь: родительский репозиторий хранит не содержимое вложенного репозитория, а ссылку на конкретный коммит этого вложенного репозитория.

    Сильная формулировка для собеседования:

  • submodule это способ прибить зависимость к точной версии, выраженной хешем коммита
  • это повышает воспроизводимость, но добавляет сложности в разработке и CI
  • Документация: git-submodule

    !Как родительский репозиторий фиксирует submodule по хешу коммита

    Как правильно клонировать репозиторий с submodules

    Частая проблема: люди клонируют репозиторий и получают пустую директорию submodule.

    Правильные варианты:

    Или если уже клонировали:

    Обновление submodule до новой версии

    Типичный процесс:

  • Перейти в директорию submodule и забрать изменения.
  • Вернуться в родительский репозиторий и закоммитить изменение ссылки.
  • Важно: в родительском репозитории меняется именно ссылка на коммит submodule, поэтому это должно проходить ревью так же, как обычное изменение зависимости.

    Submodules в CI: типовые поломки и как их предотвращают

    Частые причины падений пайплайна:

  • CI не инициализирует submodule и сборка не видит нужные файлы
  • у CI нет прав доступа к приватному submodule-репозиторию
  • забыли --recursive, а внутри submodule есть свои submodules
  • Что обычно делают:

  • в CI шагом выполняют git submodule update --init --recursive
  • проверяют доступы токенов/ключей, если submodule приватный
  • фиксируют правила в документации репозитория, потому что ошибка повторяется у новичков
  • Когда submodules стоит избегать

    На интервью полезно быть честным: submodules работают, но добавляют когнитивную нагрузку и нюансы доставки.

    Альтернативы, которые иногда предпочитают команды:

  • зависимости через пакетный менеджер или артефакты
  • Git subtree
  • vendor-копия кода, если это оправдано процессом
  • Уместная позиция DevOps/SRE: выбирать механизм, который повышает воспроизводимость и снижает вероятность «сломать сборку из-за процедуры», даже если он менее «красивый».

    Мини-набор формулировок для собеседования

  • git bisect позволяет быстро найти первый коммит, который сделал систему «плохой», используя двоичный поиск по истории.
  • git reflog помогает восстановиться после reset/rebase, потому что показывает историю перемещений HEAD локально.
  • reset чаще про переписывание указателя ветки, revert про безопасную отмену эффекта через новый коммит.
  • submodule фиксирует зависимость на конкретный коммит; это улучшает воспроизводимость, но требует правильного клона (--recurse-submodules) и явного шага в CI.