From ed6760355d63ec9392a60f784ccc9dd3004e0d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=98=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2?= Date: Wed, 29 Jul 2026 17:54:52 +0300 Subject: [PATCH 1/2] docs: expand Git interview answers --- src/pages/git/index.md | 281 +++++++++++++++++++++++++++++++++++------ 1 file changed, 239 insertions(+), 42 deletions(-) diff --git a/src/pages/git/index.md b/src/pages/git/index.md index 88f278c..eddcb0f 100644 --- a/src/pages/git/index.md +++ b/src/pages/git/index.md @@ -23,9 +23,30 @@ Version control workflow определяет, как создаются branche **Полный ответ** -Version control workflow определяет, как создаются branches, pull requests, releases, hotfixes и rollback. Без общей -договоренности изменения сложнее ревьюить, релизы сложнее собирать, а история становится шумной. Workflow должен -соответствовать размеру команды, частоте релизов и риску продукта. +Version control workflow описывает путь изменения от задачи до production: где создать ветку, как оформить коммиты и pull +request, какие проверки обязательны, кто выполняет review, каким способом изменения попадают в основную ветку и как +выпускаются или откатываются. + +Например, команда может договориться о следующем процессе: + +1. `main` защищена от прямого push; +2. работа ведется в короткоживущей feature-ветке, связанной с issue; +3. pull request должен пройти lint, tests и build; +4. минимум один reviewer проверяет корректность и понятность изменения; +5. после squash merge commit попадает в release notes; +6. проблемный релиз откатывается через `revert`, а не переписыванием общей истории. + +Такой workflow делает состояние репозитория предсказуемым и переносит часть контроля качества из человеческой памяти в +branch protection и CI. По связям issue → pull request → commit → release можно восстановить, зачем появилось изменение и +где обсуждались ограничения. + +Слишком сложный процесс тоже вреден: длинные release-ветки, много ручных согласований и крупные pull requests увеличивают +lead time и количество конфликтов. Небольшой продукт с частыми релизами обычно выигрывает от trunk-based development и +коротких веток, а продукт с несколькими поддерживаемыми версиями или строгим release governance может использовать release +branches. + +На интервью важно не назвать единственный "правильный" workflow, а объяснить, как выбранный процесс снижает риски именно +вашей команды и какие проблемы он создает взамен. @@ -43,9 +64,30 @@ Feature branch workflow держит изменения в отдельных в **Полный ответ** -Feature branch workflow держит изменения в отдельных ветках до merge. Trunk-based development предполагает маленькие -частые изменения в основной ветке, часто с feature flags и сильными automated checks. Первый подход проще для -изолированной работы, второй лучше для частых релизов и меньших merge conflicts. +В feature branch workflow каждая задача разрабатывается в отдельной ветке и попадает в основную ветку после pull request, +review и CI. Это удобно для изоляции незавершенной работы, внешних contributors и изменений, которым требуется отдельное +обсуждение. Но чем дольше живет ветка, тем сильнее она расходится с `main`: интеграция откладывается, конфликты становятся +крупнее, а обратная связь приходит поздно. + +Trunk-based development строится вокруг постоянно интегрируемой основной ветки. Разработчики делают небольшие изменения и +сливают их часто, обычно через очень короткие branches или напрямую при строгой защите trunk. Незавершенную функциональность +скрывают feature flags, branch by abstraction или совместимыми промежуточными изменениями. Поэтому deployment можно +отделить от release: код уже находится в production, но функция еще выключена для пользователей. + +Например, новую форму можно добавлять по частям: + +- сначала совместимый backend API; +- затем UI за выключенным feature flag; +- после этого telemetry и постепенное включение; +- в конце удаление старого пути и флага. + +Trunk-based development требует быстрых reliable checks, небольших pull requests, дисциплины обратной совместимости и +умения дробить работу. Feature branches проще начать использовать, но они не должны превращаться в ветки, живущие недели. +Также trunk-based development не означает отсутствие review или бесконтрольный push в `main`: review может оставаться +обязательным, просто изменение должно проходить его быстро. + +Выбор зависит от частоты релизов, зрелости CI/CD, размера изменений и требований к изоляции. Главный trade-off — +краткосрочная изоляция против ранней интеграции. @@ -63,9 +105,31 @@ release process. Хорошая команда фиксирует branch protect **Полный ответ** -Ответственность разделена: автор отвечает за изменение, reviewer — за проверку, maintainers — за правила репозитория и -release process. Хорошая команда фиксирует branch protection, required checks, review rules и ownership, чтобы качество -не зависело только от внимательности одного человека. +Качество кода — общая ответственность, но у участников разные зоны контроля. + +Автор должен понять задачу, ограничить scope, проверить diff, добавить или обновить tests, описать риски и убедиться, что +изменение можно безопасно доставить. Reviewer проверяет не только style, но и корректность решения, edge cases, +поддерживаемость, безопасность и соответствие архитектуре. Maintainers задают правила: branch protection, required checks, +merge strategy, permissions, CODEOWNERS, release process и порядок работы с инцидентами. + +Автоматизация создает повторяемый базовый уровень качества: + +- formatter и linter проверяют механические правила; +- unit, integration и end-to-end tests проверяют поведение; +- type checking и build находят несовместимости; +- security и dependency checks обнаруживают известные риски; +- branch protection не позволяет обойти обязательные проверки случайным merge. + +При этом CI не понимает продуктовый смысл, а reviewer не должен вручную выполнять работу линтера. Хороший процесс +распределяет проверки по самому дешевому и надежному уровню. + +Опасная модель — считать reviewer последней линией защиты и перекладывать на него ответственность автора. Это приводит к +огромным pull requests и формальному approval. Обратная крайность — считать, что зеленый CI гарантирует качество: тесты +могут не покрывать логическую ошибку, миграцию данных или деградацию UX. + +После дефекта команда должна улучшать систему, а не искать одного виноватого: добавить test, checklist, ownership rule или +наблюдаемость. На интервью полезно привести пример, где качество обеспечивалось сочетанием личной ответственности, +review и автоматических ограничений. @@ -83,9 +147,29 @@ requests, bugs, decisions и releases были связаны между соб **Полный ответ** -Issues должны жить в одном понятном месте: GitHub Issues, Jira, YouTrack, Linear или другой системе. Важно, чтобы pull -requests, bugs, decisions и releases были связаны между собой. Иначе команда теряет контекст, почему изменение было -сделано и какие ограничения обсуждались. +Команде нужен один source of truth для задач и дефектов. Конкретный инструмент вторичен: это может быть GitHub Issues, +Jira, YouTrack или Linear. Важнее, чтобы участники знали, где искать актуальный статус, критерии готовности, ответственного, +решения и связи с кодом. + +Хороший issue обычно содержит: + +- проблему и пользовательский эффект; +- acceptance criteria и явные ограничения; +- ссылки на дизайн, логи, ADR или связанные задачи; +- результат обсуждения спорных решений; +- связь с pull request, release и последующим мониторингом. + +Например, pull request может содержать `Closes #123`. После merge GitHub автоматически закроет issue, а из задачи можно +перейти к diff и понять, каким изменением она реализована. Для production bug полезно также связать issue с incident, +исправлением, тестом, который воспроизводит проблему, и версией релиза. + +Проблема возникает, когда одна и та же задача вручную дублируется в Jira и GitHub Issues. Статусы и описания расходятся, а +команда не понимает, какая запись актуальна. Если несколько систем неизбежны, одна должна быть основной, а остальные — +ссылаться на нее или синхронизироваться автоматически. + +Issue не обязан хранить весь технический контекст. Долгосрочное архитектурное решение лучше зафиксировать в ADR, а +чувствительные данные, credentials и персональную информацию нельзя переносить в публичный tracker. Но issue должен +оставлять достаточно контекста, чтобы через несколько месяцев понять причину изменения, а не только его название. @@ -97,15 +181,37 @@ requests, bugs, decisions и releases были связаны между соб **Короткий ответ** -Husky настраивает Git hooks в проекте. Например, pre-commit может запускать lint-staged, а commit-msg - проверять формат -сообщения. +Husky настраивает Git hooks в проекте. Например, `pre-commit` может запускать lint-staged, а `commit-msg` — проверять формат +сообщения. Hooks дают быстрый локальный feedback, но не заменяют CI: их можно пропустить или не установить. **Полный ответ** -Husky настраивает Git hooks в проекте. Например, `pre-commit` может запускать lint-staged, а `commit-msg` - проверять -формат сообщения. +Husky помогает хранить настройку Git hooks рядом с кодом проекта. Git вызывает hooks в определенные моменты, например +перед созданием commit, после merge или перед push. Husky подключает проектные scripts к этим событиям, чтобы все +разработчики могли использовать одинаковые локальные проверки. + +Типичный набор: + +- `pre-commit` запускает `lint-staged`, чтобы форматировать и проверять только staged files; +- `commit-msg` запускает commitlint и проверяет соглашение о сообщениях; +- `pre-push` выполняет небольшой набор быстрых tests или type checking. + +Преимущество hooks — ранний feedback. Разработчик узнает о formatting error до push, а не после нескольких минут ожидания +CI. Проверка staged files также обычно быстрее полного запуска lint по репозиторию. + +Но hooks нельзя считать защитной границей: + +- установка dependencies могла не выполниться; +- hook можно пропустить через `--no-verify`; +- локальная среда может отличаться от CI; +- слишком долгий hook разработчики начнут обходить; +- platform-specific shell command может не работать у части команды. + +Поэтому обязательные проверки должны повторяться в CI, а локальные hooks стоит делать быстрыми, детерминированными и +понятными. В hook не следует помещать тяжелый end-to-end suite или действия, изменяющие удаленные ресурсы. -Hooks дают быстрый локальный feedback, но не заменяют CI: их можно пропустить или не установить. +На интервью полезно объяснить не только "Husky запускает lint", но и границу ответственности: Husky улучшает developer +experience и предотвращает простые ошибки локально, а CI остается независимым источником истины перед merge. @@ -123,9 +229,27 @@ resolution, pull request и code review. Если был опыт SVN, Mercurial **Полный ответ** -Ожидается не только название Git, но и понимание ежедневных операций: branch, commit, merge, rebase, revert, conflict -resolution, pull request и code review. Если был опыт SVN, Mercurial или monorepo tooling, полезно объяснить, чем -отличались процессы и какие ограничения это создавало. +Это вопрос про практический опыт, а не проверка списка названий. Сильный ответ начинается с основной системы, например Git, +а затем показывает, какие задачи вы решали: создавали branches, формировали понятные commits, обновляли ветку через merge +или rebase, разрешали conflicts, откатывали изменения, участвовали в code review и выпускали releases. + +Полезно привести конкретный сценарий: + +> В основной работе использовал Git и GitHub. Для задач создавал короткие branches, открывал pull requests, проходил +> required CI checks и squash merge. При обновлении feature-ветки использовал rebase, а изменения в общей ветке отменял +> через revert. Для параллельной работы с hotfix применял worktree. + +Git — distributed version control system: каждый clone содержит историю и позволяет создавать commits и branches локально. +В централизованной SVN основная история находится на сервере, а типичный workflow и модель branching отличаются. Опыт с +другой VCS стоит упоминать только вместе с практическими отличиями, а не как набор терминов. + +Monorepo tools, GitHub, GitLab и Bitbucket не являются отдельными version control systems. Это инфраструктура вокруг Git: +hosting, pull requests, permissions, CI/CD и инструменты масштабирования репозитория. На интервью лучше разделять эти +понятия. + +Если опыт ограничен Git, не нужно придумывать работу с SVN или Mercurial. Гораздо ценнее подробно рассказать, как вы +разрешили сложный conflict, восстановили потерянный commit через `reflog`, выбрали merge strategy или улучшили командный +workflow. @@ -139,16 +263,33 @@ resolution, pull request и code review. Если был опыт SVN, Mercurial **Короткий ответ** -git revert создает новый коммит, отменяющий изменения выбранного коммита. Он безопасен для общей ветки, потому что не -переписывает историю. +`git revert` создает новый commit, отменяющий изменения выбранного commit, поэтому подходит для общей опубликованной +ветки. `git reset` перемещает указатель ветки и может менять index и working tree, поэтому обычно применяется к локальной +истории. **Полный ответ** -`git revert` создает новый коммит, отменяющий изменения выбранного коммита. Он безопасен для общей ветки, потому что не -переписывает историю. +`git revert ` вычисляет обратный patch и создает новый commit. Исходный commit и вся опубликованная история +сохраняются, поэтому коллеги могут получить отмену обычным pull. Revert может потребовать разрешения conflicts, если более +поздние изменения затронули те же строки. Для revert merge commit нужно явно указать mainline parent через `-m`. -`git reset` перемещает указатель ветки. Варианты `--soft`, `--mixed` и `--hard` по-разному работают с index и рабочими -файлами. Reset опубликованной ветки требует последующего force push и может сломать работу коллег. +`git reset ` перемещает текущую branch и `HEAD` на другой commit. Режим определяет, что произойдет с index и working +tree: + +- `--soft` перемещает branch, но оставляет изменения staged; +- `--mixed` используется по умолчанию, сбрасывает index, но сохраняет изменения в файлах; +- `--hard` приводит branch, index и tracked files к выбранному commit и может уничтожить незакоммиченные изменения. + +Например, ошибочный commit уже попал в `main`. Безопасное действие — `git revert ` и новый pull request с отменой. +Если тот же commit существует только в локальной feature-ветке, можно выполнить `git reset --soft HEAD~1`, исправить staged +changes и создать commit заново. + +Reset опубликованной ветки изменяет ее историю и обычно требует force push. Это ломает parent chain, на который могли +опираться branches коллег. Поэтому его не используют для общей ветки без явной координации. + +Иногда удаленный reset commit можно восстановить через `reflog`, пока объект не очищен сборщиком мусора, но это аварийный +механизм, а не стратегия безопасности. Главное правило для интервью: `revert` добавляет историю и безопасно отменяет +публичное изменение, `reset` переписывает локальное положение branch. @@ -160,14 +301,35 @@ git revert создает новый коммит, отменяющий изме **Короткий ответ** -merge объединяет истории и обычно создает merge commit. Реальные commit hashes существующей ветки сохраняются. +`merge` объединяет две линии истории и сохраняет существующие commits. `rebase` последовательно переносит commits на новую +базу, создавая для них новые hashes. Merge безопаснее для общей истории, rebase удобен для очистки локальной feature-ветки. **Полный ответ** -`merge` объединяет истории и обычно создает merge commit. Реальные commit hashes существующей ветки сохраняются. +Git хранит commits как граф. `git merge feature` связывает две линии истории: при необходимости создается merge commit с +двумя parents. Уже существующие commits и их hashes не меняются. Если текущая branch не расходилась, Git может выполнить +fast-forward без отдельного merge commit. + +`git rebase main` находит commits feature-ветки после общей базы и последовательно применяет их patches поверх актуального +`main`. У новых commits меняется parent, а значит меняется и hash, даже если содержимое файлов осталось тем же. В результате +история выглядит линейной. + +Практический workflow может быть таким: + +1. перед review разработчик выполняет `git fetch` и `git rebase origin/main`; +2. разрешает conflicts в контексте каждого переносимого commit; +3. запускает tests; +4. обновляет уже опубликованную feature-ветку через `git push --force-with-lease`; +5. после approval команда делает squash merge или fast-forward по своим правилам. + +Merge лучше показывает реальную структуру совместной работы и не требует переписывать опубликованные commits. Rebase +упрощает линейное чтение истории и позволяет привести локальные commits в порядок, но conflicts иногда приходится решать +несколько раз — для каждого переносимого commit. Обычный rebase также может распрямить merge commits, если специально не +использовать режим сохранения merges. -`rebase` переносит коммиты на новую базу, создавая для них новые hashes и линейную историю. Rebase удобен для локальной -feature-ветки, но опубликованную общую историю без договоренности не переписывают. +Не стоит rebase общую ветку, которой пользуются другие разработчики, без договоренности. Универсально лучшей стратегии нет: +команда выбирает ее с учетом требований к audit trail, частоты интеграции и удобства диагностики. На интервью важно +объяснить изменение commit identity и правило "rebase private history, merge shared history". @@ -179,17 +341,31 @@ feature-ветки, но опубликованную общую историю **Короткий ответ** -Безопасные варианты: +Можно сделать временный commit, сохранить изменения через `git stash push -u` или открыть hotfix в отдельном +`git worktree`. Выбор зависит от того, нужно ли сохранить staged state и работать с двумя branches одновременно. **Полный ответ** -Безопасные варианты: +Самый прозрачный вариант — создать небольшой временный commit в текущей feature-ветке. Он надежно хранится в истории, его +можно позже изменить через interactive rebase или squash перед merge. Такой подход особенно удобен, если работа уже +логически делится на commit, даже если она еще не готова для pull request. -- сделать небольшой временный коммит в текущей ветке; -- выполнить `git stash push -u`, переключиться на hotfix, затем вернуть изменения через `git stash pop`; -- использовать отдельный `git worktree`, чтобы одновременно работать с двумя ветками. +`git stash push -u -m "WIP: feature"` временно сохраняет tracked и untracked changes и очищает working tree. После hotfix +можно вернуться в исходную branch и выполнить `git stash pop` или безопаснее сначала `git stash apply`. Флаг `-u` важен, +если появились новые untracked files; ignored files он не включает. При изменении тех же строк во время hotfix возврат +stash может создать conflicts. -Не стоит терять изменения через `reset --hard` или переносить незавершенный код в hotfix. +`git worktree add ../project-hotfix -b hotfix/issue origin/main` создает вторую working directory того же репозитория. В +одной директории остается незавершенная feature, в другой можно сразу исправлять production bug. Это хороший вариант, +когда нужно параллельно запускать приложение или сравнивать две branches. Git не позволяет одновременно checkout одной и +той же branch в двух worktrees, поэтому для hotfix создают отдельную branch. + +Перед переключением полезно проверить `git status`, чтобы понимать staged, unstaged и untracked changes. Не следует +использовать `git reset --hard` или удалять файлы ради чистого working tree: так легко потерять работу. Также не стоит +случайно переносить незавершенный feature-код в hotfix. + +На интервью сильный ответ предлагает несколько безопасных вариантов и объясняет, почему `worktree` лучше stash при +длительной параллельной работе, а временный commit надежнее неименованного набора изменений. @@ -201,16 +377,37 @@ feature-ветки, но опубликованную общую историю **Короткий ответ** -Git берет коммиты feature-ветки и последовательно применяет их поверх нового develop. Содержимое может сохраниться, но -commits получают новые parent links и hashes. +Git находит commits feature-ветки после общей базы и последовательно применяет их поверх свежего `develop`. Из-за новых +parent links commits получают новые hashes, а conflicts разрешаются во время replay. **Полный ответ** -Git берет коммиты feature-ветки и последовательно применяет их поверх нового `develop`. Содержимое может сохраниться, но -commits получают новые parent links и hashes. +При `git rebase develop` Git сначала определяет общую базу текущей feature-ветки и `develop`. Затем временно отделяет +уникальные commits feature-ветки, перемещает branch на новый `develop` и по очереди воспроизводит изменение каждого commit. +Это не физическое перемещение старых объектов, а создание новых commits с похожими patches. + +Hash commit зависит не только от diff, но и от parent, author/committer metadata и сообщения. После смены parent hashes +становятся другими. Старые commits некоторое время могут оставаться доступными через `reflog`, но branch уже указывает на +новую цепочку. + +Если patch конфликтует с актуальным `develop`, rebase останавливается: + +1. разработчик разрешает conflict; +2. добавляет исправленные файлы через `git add`; +3. продолжает `git rebase --continue`; +4. при необходимости отменяет весь процесс через `git rebase --abort`. + +`git rebase --skip` удаляет текущий patch из новой истории, поэтому применять его нужно только при понимании, что изменение +уже присутствует или больше не требуется. Patch-equivalent commit, который уже попал в `develop`, Git также может не +воспроизводить повторно. Обычный rebase меняет структуру merge commits; для сохранения сложной topology нужен отдельный +режим. + +После rebase важно запустить tests: текстовый conflict может отсутствовать, но поведение feature способно логически +сломаться из-за изменений в `develop`. Если feature-ветка уже опубликована, обычный push будет отклонен. Используют +`git push --force-with-lease`, который проверяет, что удаленная branch не была неожиданно обновлена другим разработчиком. -Конфликты разрешают по одному, продолжая `git rebase --continue`. После rebase уже опубликованной ветки обычно нужен -`git push --force-with-lease`, а не обычный force push. +На интервью ключевой механизм стоит сформулировать так: rebase replay-ит patches на новой базе, поэтому создается новая +цепочка commits, а не просто меняется визуальное расположение старых. From 7a5adb15440dee92533a940659cdb98979ab9c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=98=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2?= Date: Thu, 30 Jul 2026 18:51:34 +0300 Subject: [PATCH 2/2] docs: format Git interview answers --- src/pages/git/index.md | 152 +++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 75 deletions(-) diff --git a/src/pages/git/index.md b/src/pages/git/index.md index eddcb0f..ac18c1e 100644 --- a/src/pages/git/index.md +++ b/src/pages/git/index.md @@ -23,8 +23,8 @@ Version control workflow определяет, как создаются branche **Полный ответ** -Version control workflow описывает путь изменения от задачи до production: где создать ветку, как оформить коммиты и pull -request, какие проверки обязательны, кто выполняет review, каким способом изменения попадают в основную ветку и как +Version control workflow описывает путь изменения от задачи до production: где создать ветку, как оформить коммиты и +pull request, какие проверки обязательны, кто выполняет review, каким способом изменения попадают в основную ветку и как выпускаются или откатываются. Например, команда может договориться о следующем процессе: @@ -37,13 +37,13 @@ request, какие проверки обязательны, кто выполн 6. проблемный релиз откатывается через `revert`, а не переписыванием общей истории. Такой workflow делает состояние репозитория предсказуемым и переносит часть контроля качества из человеческой памяти в -branch protection и CI. По связям issue → pull request → commit → release можно восстановить, зачем появилось изменение и -где обсуждались ограничения. +branch protection и CI. По связям issue → pull request → commit → release можно восстановить, зачем появилось изменение +и где обсуждались ограничения. -Слишком сложный процесс тоже вреден: длинные release-ветки, много ручных согласований и крупные pull requests увеличивают -lead time и количество конфликтов. Небольшой продукт с частыми релизами обычно выигрывает от trunk-based development и -коротких веток, а продукт с несколькими поддерживаемыми версиями или строгим release governance может использовать release -branches. +Слишком сложный процесс тоже вреден: длинные release-ветки, много ручных согласований и крупные pull requests +увеличивают lead time и количество конфликтов. Небольшой продукт с частыми релизами обычно выигрывает от trunk-based +development и коротких веток, а продукт с несколькими поддерживаемыми версиями или строгим release governance может +использовать release branches. На интервью важно не назвать единственный "правильный" workflow, а объяснить, как выбранный процесс снижает риски именно вашей команды и какие проблемы он создает взамен. @@ -64,15 +64,15 @@ Feature branch workflow держит изменения в отдельных в **Полный ответ** -В feature branch workflow каждая задача разрабатывается в отдельной ветке и попадает в основную ветку после pull request, -review и CI. Это удобно для изоляции незавершенной работы, внешних contributors и изменений, которым требуется отдельное -обсуждение. Но чем дольше живет ветка, тем сильнее она расходится с `main`: интеграция откладывается, конфликты становятся -крупнее, а обратная связь приходит поздно. +В feature branch workflow каждая задача разрабатывается в отдельной ветке и попадает в основную ветку после pull +request, review и CI. Это удобно для изоляции незавершенной работы, внешних contributors и изменений, которым требуется +отдельное обсуждение. Но чем дольше живет ветка, тем сильнее она расходится с `main`: интеграция откладывается, +конфликты становятся крупнее, а обратная связь приходит поздно. -Trunk-based development строится вокруг постоянно интегрируемой основной ветки. Разработчики делают небольшие изменения и -сливают их часто, обычно через очень короткие branches или напрямую при строгой защите trunk. Незавершенную функциональность -скрывают feature flags, branch by abstraction или совместимыми промежуточными изменениями. Поэтому deployment можно -отделить от release: код уже находится в production, но функция еще выключена для пользователей. +Trunk-based development строится вокруг постоянно интегрируемой основной ветки. Разработчики делают небольшие изменения +и сливают их часто, обычно через очень короткие branches или напрямую при строгой защите trunk. Незавершенную +функциональность скрывают feature flags, branch by abstraction или совместимыми промежуточными изменениями. Поэтому +deployment можно отделить от release: код уже находится в production, но функция еще выключена для пользователей. Например, новую форму можно добавлять по частям: @@ -82,9 +82,9 @@ Trunk-based development строится вокруг постоянно инт - в конце удаление старого пути и флага. Trunk-based development требует быстрых reliable checks, небольших pull requests, дисциплины обратной совместимости и -умения дробить работу. Feature branches проще начать использовать, но они не должны превращаться в ветки, живущие недели. -Также trunk-based development не означает отсутствие review или бесконтрольный push в `main`: review может оставаться -обязательным, просто изменение должно проходить его быстро. +умения дробить работу. Feature branches проще начать использовать, но они не должны превращаться в ветки, живущие +недели. Также trunk-based development не означает отсутствие review или бесконтрольный push в `main`: review может +оставаться обязательным, просто изменение должно проходить его быстро. Выбор зависит от частоты релизов, зрелости CI/CD, размера изменений и требований к изоляции. Главный trade-off — краткосрочная изоляция против ранней интеграции. @@ -107,10 +107,10 @@ release process. Хорошая команда фиксирует branch protect Качество кода — общая ответственность, но у участников разные зоны контроля. -Автор должен понять задачу, ограничить scope, проверить diff, добавить или обновить tests, описать риски и убедиться, что -изменение можно безопасно доставить. Reviewer проверяет не только style, но и корректность решения, edge cases, -поддерживаемость, безопасность и соответствие архитектуре. Maintainers задают правила: branch protection, required checks, -merge strategy, permissions, CODEOWNERS, release process и порядок работы с инцидентами. +Автор должен понять задачу, ограничить scope, проверить diff, добавить или обновить tests, описать риски и убедиться, +что изменение можно безопасно доставить. Reviewer проверяет не только style, но и корректность решения, edge cases, +поддерживаемость, безопасность и соответствие архитектуре. Maintainers задают правила: branch protection, required +checks, merge strategy, permissions, CODEOWNERS, release process и порядок работы с инцидентами. Автоматизация создает повторяемый базовый уровень качества: @@ -127,8 +127,8 @@ merge strategy, permissions, CODEOWNERS, release process и порядок ра огромным pull requests и формальному approval. Обратная крайность — считать, что зеленый CI гарантирует качество: тесты могут не покрывать логическую ошибку, миграцию данных или деградацию UX. -После дефекта команда должна улучшать систему, а не искать одного виноватого: добавить test, checklist, ownership rule или -наблюдаемость. На интервью полезно привести пример, где качество обеспечивалось сочетанием личной ответственности, +После дефекта команда должна улучшать систему, а не искать одного виноватого: добавить test, checklist, ownership rule +или наблюдаемость. На интервью полезно привести пример, где качество обеспечивалось сочетанием личной ответственности, review и автоматических ограничений. @@ -148,8 +148,8 @@ requests, bugs, decisions и releases были связаны между соб **Полный ответ** Команде нужен один source of truth для задач и дефектов. Конкретный инструмент вторичен: это может быть GitHub Issues, -Jira, YouTrack или Linear. Важнее, чтобы участники знали, где искать актуальный статус, критерии готовности, ответственного, -решения и связи с кодом. +Jira, YouTrack или Linear. Важнее, чтобы участники знали, где искать актуальный статус, критерии готовности, +ответственного, решения и связи с кодом. Хороший issue обычно содержит: @@ -163,8 +163,8 @@ Jira, YouTrack или Linear. Важнее, чтобы участники зна перейти к diff и понять, каким изменением она реализована. Для production bug полезно также связать issue с incident, исправлением, тестом, который воспроизводит проблему, и версией релиза. -Проблема возникает, когда одна и та же задача вручную дублируется в Jira и GitHub Issues. Статусы и описания расходятся, а -команда не понимает, какая запись актуальна. Если несколько систем неизбежны, одна должна быть основной, а остальные — +Проблема возникает, когда одна и та же задача вручную дублируется в Jira и GitHub Issues. Статусы и описания расходятся, +а команда не понимает, какая запись актуальна. Если несколько систем неизбежны, одна должна быть основной, а остальные — ссылаться на нее или синхронизироваться автоматически. Issue не обязан хранить весь технический контекст. Долгосрочное архитектурное решение лучше зафиксировать в ADR, а @@ -181,8 +181,8 @@ Issue не обязан хранить весь технический конт **Короткий ответ** -Husky настраивает Git hooks в проекте. Например, `pre-commit` может запускать lint-staged, а `commit-msg` — проверять формат -сообщения. Hooks дают быстрый локальный feedback, но не заменяют CI: их можно пропустить или не установить. +Husky настраивает Git hooks в проекте. Например, `pre-commit` может запускать lint-staged, а `commit-msg` — проверять +формат сообщения. Hooks дают быстрый локальный feedback, но не заменяют CI: их можно пропустить или не установить. **Полный ответ** @@ -196,8 +196,8 @@ Husky помогает хранить настройку Git hooks рядом с - `commit-msg` запускает commitlint и проверяет соглашение о сообщениях; - `pre-push` выполняет небольшой набор быстрых tests или type checking. -Преимущество hooks — ранний feedback. Разработчик узнает о formatting error до push, а не после нескольких минут ожидания -CI. Проверка staged files также обычно быстрее полного запуска lint по репозиторию. +Преимущество hooks — ранний feedback. Разработчик узнает о formatting error до push, а не после нескольких минут +ожидания CI. Проверка staged files также обычно быстрее полного запуска lint по репозиторию. Но hooks нельзя считать защитной границей: @@ -229,9 +229,9 @@ resolution, pull request и code review. Если был опыт SVN, Mercurial **Полный ответ** -Это вопрос про практический опыт, а не проверка списка названий. Сильный ответ начинается с основной системы, например Git, -а затем показывает, какие задачи вы решали: создавали branches, формировали понятные commits, обновляли ветку через merge -или rebase, разрешали conflicts, откатывали изменения, участвовали в code review и выпускали releases. +Это вопрос про практический опыт, а не проверка списка названий. Сильный ответ начинается с основной системы, например +Git, а затем показывает, какие задачи вы решали: создавали branches, формировали понятные commits, обновляли ветку через +merge или rebase, разрешали conflicts, откатывали изменения, участвовали в code review и выпускали releases. Полезно привести конкретный сценарий: @@ -239,13 +239,13 @@ resolution, pull request и code review. Если был опыт SVN, Mercurial > required CI checks и squash merge. При обновлении feature-ветки использовал rebase, а изменения в общей ветке отменял > через revert. Для параллельной работы с hotfix применял worktree. -Git — distributed version control system: каждый clone содержит историю и позволяет создавать commits и branches локально. -В централизованной SVN основная история находится на сервере, а типичный workflow и модель branching отличаются. Опыт с -другой VCS стоит упоминать только вместе с практическими отличиями, а не как набор терминов. +Git — distributed version control system: каждый clone содержит историю и позволяет создавать commits и branches +локально. В централизованной SVN основная история находится на сервере, а типичный workflow и модель branching +отличаются. Опыт с другой VCS стоит упоминать только вместе с практическими отличиями, а не как набор терминов. -Monorepo tools, GitHub, GitLab и Bitbucket не являются отдельными version control systems. Это инфраструктура вокруг Git: -hosting, pull requests, permissions, CI/CD и инструменты масштабирования репозитория. На интервью лучше разделять эти -понятия. +Monorepo tools, GitHub, GitLab и Bitbucket не являются отдельными version control systems. Это инфраструктура вокруг +Git: hosting, pull requests, permissions, CI/CD и инструменты масштабирования репозитория. На интервью лучше разделять +эти понятия. Если опыт ограничен Git, не нужно придумывать работу с SVN или Mercurial. Гораздо ценнее подробно рассказать, как вы разрешили сложный conflict, восстановили потерянный commit через `reflog`, выбрали merge strategy или улучшили командный @@ -264,32 +264,32 @@ workflow. **Короткий ответ** `git revert` создает новый commit, отменяющий изменения выбранного commit, поэтому подходит для общей опубликованной -ветки. `git reset` перемещает указатель ветки и может менять index и working tree, поэтому обычно применяется к локальной -истории. +ветки. `git reset` перемещает указатель ветки и может менять index и working tree, поэтому обычно применяется к +локальной истории. **Полный ответ** `git revert ` вычисляет обратный patch и создает новый commit. Исходный commit и вся опубликованная история -сохраняются, поэтому коллеги могут получить отмену обычным pull. Revert может потребовать разрешения conflicts, если более -поздние изменения затронули те же строки. Для revert merge commit нужно явно указать mainline parent через `-m`. +сохраняются, поэтому коллеги могут получить отмену обычным pull. Revert может потребовать разрешения conflicts, если +более поздние изменения затронули те же строки. Для revert merge commit нужно явно указать mainline parent через `-m`. -`git reset ` перемещает текущую branch и `HEAD` на другой commit. Режим определяет, что произойдет с index и working -tree: +`git reset ` перемещает текущую branch и `HEAD` на другой commit. Режим определяет, что произойдет с index и +working tree: - `--soft` перемещает branch, но оставляет изменения staged; - `--mixed` используется по умолчанию, сбрасывает index, но сохраняет изменения в файлах; - `--hard` приводит branch, index и tracked files к выбранному commit и может уничтожить незакоммиченные изменения. Например, ошибочный commit уже попал в `main`. Безопасное действие — `git revert ` и новый pull request с отменой. -Если тот же commit существует только в локальной feature-ветке, можно выполнить `git reset --soft HEAD~1`, исправить staged -changes и создать commit заново. +Если тот же commit существует только в локальной feature-ветке, можно выполнить `git reset --soft HEAD~1`, исправить +staged changes и создать commit заново. Reset опубликованной ветки изменяет ее историю и обычно требует force push. Это ломает parent chain, на который могли опираться branches коллег. Поэтому его не используют для общей ветки без явной координации. -Иногда удаленный reset commit можно восстановить через `reflog`, пока объект не очищен сборщиком мусора, но это аварийный -механизм, а не стратегия безопасности. Главное правило для интервью: `revert` добавляет историю и безопасно отменяет -публичное изменение, `reset` переписывает локальное положение branch. +Иногда удаленный reset commit можно восстановить через `reflog`, пока объект не очищен сборщиком мусора, но это +аварийный механизм, а не стратегия безопасности. Главное правило для интервью: `revert` добавляет историю и безопасно +отменяет публичное изменение, `reset` переписывает локальное положение branch. @@ -301,8 +301,9 @@ Reset опубликованной ветки изменяет ее истори **Короткий ответ** -`merge` объединяет две линии истории и сохраняет существующие commits. `rebase` последовательно переносит commits на новую -базу, создавая для них новые hashes. Merge безопаснее для общей истории, rebase удобен для очистки локальной feature-ветки. +`merge` объединяет две линии истории и сохраняет существующие commits. `rebase` последовательно переносит commits на +новую базу, создавая для них новые hashes. Merge безопаснее для общей истории, rebase удобен для очистки локальной +feature-ветки. **Полный ответ** @@ -310,9 +311,9 @@ Git хранит commits как граф. `git merge feature` связывает двумя parents. Уже существующие commits и их hashes не меняются. Если текущая branch не расходилась, Git может выполнить fast-forward без отдельного merge commit. -`git rebase main` находит commits feature-ветки после общей базы и последовательно применяет их patches поверх актуального -`main`. У новых commits меняется parent, а значит меняется и hash, даже если содержимое файлов осталось тем же. В результате -история выглядит линейной. +`git rebase main` находит commits feature-ветки после общей базы и последовательно применяет их patches поверх +актуального `main`. У новых commits меняется parent, а значит меняется и hash, даже если содержимое файлов осталось тем +же. В результате история выглядит линейной. Практический workflow может быть таким: @@ -327,8 +328,8 @@ Merge лучше показывает реальную структуру сов несколько раз — для каждого переносимого commit. Обычный rebase также может распрямить merge commits, если специально не использовать режим сохранения merges. -Не стоит rebase общую ветку, которой пользуются другие разработчики, без договоренности. Универсально лучшей стратегии нет: -команда выбирает ее с учетом требований к audit trail, частоты интеграции и удобства диагностики. На интервью важно +Не стоит rebase общую ветку, которой пользуются другие разработчики, без договоренности. Универсально лучшей стратегии +нет: команда выбирает ее с учетом требований к audit trail, частоты интеграции и удобства диагностики. На интервью важно объяснить изменение commit identity и правило "rebase private history, merge shared history". @@ -346,14 +347,14 @@ Merge лучше показывает реальную структуру сов **Полный ответ** -Самый прозрачный вариант — создать небольшой временный commit в текущей feature-ветке. Он надежно хранится в истории, его -можно позже изменить через interactive rebase или squash перед merge. Такой подход особенно удобен, если работа уже +Самый прозрачный вариант — создать небольшой временный commit в текущей feature-ветке. Он надежно хранится в истории, +его можно позже изменить через interactive rebase или squash перед merge. Такой подход особенно удобен, если работа уже логически делится на commit, даже если она еще не готова для pull request. -`git stash push -u -m "WIP: feature"` временно сохраняет tracked и untracked changes и очищает working tree. После hotfix -можно вернуться в исходную branch и выполнить `git stash pop` или безопаснее сначала `git stash apply`. Флаг `-u` важен, -если появились новые untracked files; ignored files он не включает. При изменении тех же строк во время hotfix возврат -stash может создать conflicts. +`git stash push -u -m "WIP: feature"` временно сохраняет tracked и untracked changes и очищает working tree. После +hotfix можно вернуться в исходную branch и выполнить `git stash pop` или безопаснее сначала `git stash apply`. Флаг `-u` +важен, если появились новые untracked files; ignored files он не включает. При изменении тех же строк во время hotfix +возврат stash может создать conflicts. `git worktree add ../project-hotfix -b hotfix/issue origin/main` создает вторую working directory того же репозитория. В одной директории остается незавершенная feature, в другой можно сразу исправлять production bug. Это хороший вариант, @@ -383,12 +384,12 @@ parent links commits получают новые hashes, а conflicts разре **Полный ответ** При `git rebase develop` Git сначала определяет общую базу текущей feature-ветки и `develop`. Затем временно отделяет -уникальные commits feature-ветки, перемещает branch на новый `develop` и по очереди воспроизводит изменение каждого commit. -Это не физическое перемещение старых объектов, а создание новых commits с похожими patches. +уникальные commits feature-ветки, перемещает branch на новый `develop` и по очереди воспроизводит изменение каждого +commit. Это не физическое перемещение старых объектов, а создание новых commits с похожими patches. Hash commit зависит не только от diff, но и от parent, author/committer metadata и сообщения. После смены parent hashes -становятся другими. Старые commits некоторое время могут оставаться доступными через `reflog`, но branch уже указывает на -новую цепочку. +становятся другими. Старые commits некоторое время могут оставаться доступными через `reflog`, но branch уже указывает +на новую цепочку. Если patch конфликтует с актуальным `develop`, rebase останавливается: @@ -397,14 +398,15 @@ Hash commit зависит не только от diff, но и от parent, aut 3. продолжает `git rebase --continue`; 4. при необходимости отменяет весь процесс через `git rebase --abort`. -`git rebase --skip` удаляет текущий patch из новой истории, поэтому применять его нужно только при понимании, что изменение -уже присутствует или больше не требуется. Patch-equivalent commit, который уже попал в `develop`, Git также может не -воспроизводить повторно. Обычный rebase меняет структуру merge commits; для сохранения сложной topology нужен отдельный -режим. +`git rebase --skip` удаляет текущий patch из новой истории, поэтому применять его нужно только при понимании, что +изменение уже присутствует или больше не требуется. Patch-equivalent commit, который уже попал в `develop`, Git также +может не воспроизводить повторно. Обычный rebase меняет структуру merge commits; для сохранения сложной topology нужен +отдельный режим. После rebase важно запустить tests: текстовый conflict может отсутствовать, но поведение feature способно логически сломаться из-за изменений в `develop`. Если feature-ветка уже опубликована, обычный push будет отклонен. Используют -`git push --force-with-lease`, который проверяет, что удаленная branch не была неожиданно обновлена другим разработчиком. +`git push --force-with-lease`, который проверяет, что удаленная branch не была неожиданно обновлена другим +разработчиком. На интервью ключевой механизм стоит сформулировать так: rebase replay-ит patches на новой базе, поэтому создается новая цепочка commits, а не просто меняется визуальное расположение старых.