Система контроля версий (СКВ, VCS) – это формализованный механизм фиксации, идентификации и согласованного объединения изменений исходных артефактов (кода, данных, документации). В прикладном смысле СКВ даёт: (1) историю (кто, что, когда и почему изменил), (2) ветвление и слияние для параллельной работы, (3) воспроизводимость результатов. В формальном смысле современная распределённая СКВ (как Git) опирается на направленный ациклический граф (DAG) коммитов с криптографической адресацией, обеспечивая неизменяемость истории и детерминированное объединение.
Для подготовки к ЕГЭ по информатике тема СКВ полезна как «сшивка» нескольких разделов: графы и топологический порядок, хеш-функции и кодирование, строки и формальные языки (паттерны .gitignore), алгоритмы (трёхстороннее слияние), оценка сложности и логика (инварианты репозитория).
Репозиторий как математический объект
Модель репозитория представим в виде кортежа:
R = (C, E, H, ρ, r0)
где
C – множество коммитов;
E ⊆ C × C – ориентированные рёбра «родитель → потомок»;
H : C → {0,1}^n – инъективная адресация коммита (хеш);
ρ : C → T – метаданные (автор, время, сообщение, указатели на деревья файлов);
r0 ∈ C – корневой коммит (или множество корней для инициализации).
Граф (C, E) – DAG, поскольку рёбра задают причинно-временной порядок фиксаций и по определению не образуют циклов.
Криптографическая адресация (идея)
Пусть B – байтовое представление содержимого коммита (включая ссылки на родителей и деревья файлов). Тогда хеш:
H(c) = hash(B(c))
Для Git используется SHA-1/SHA-256 (в новых настройках). Свойства полезны практику: устойчивость к коллизиям и необратимость, что поддерживает доверие к идентификаторам.
Ветви и указатели
Ветвь – это именованный указатель ref на некоторый вершину c ∈ C. Движение ветви – переназначение ref := c', где c' – новый коммит, родитель которого – старое значение ref (fast-forward) или результат слияния (merge-коммит с несколькими родителями).
Слияние как трёхстороннее сопоставление
Пусть есть общий предок B, и две независимые линии изменений A и D. Объединение вычисляет дифференциалы
Δ1 = diff(B, A), Δ2 = diff(B, D)
и применяет трёхстороннее согласование (B, A, D) → M. При пересечении правок одного диапазона возникает конфликт, требующий явного разрешения.

Единицы хранения
blob – содержимое файла;
tree – каталог (имя → ссылка на blob/tree);
commit – метаданные + ссылки на tree и родителей;
tag – человекочитаемая метка на коммит.
Рабочие области
Working Directory – ваши файлы на диске;
Index (staging) – «снимок» для будущего коммита;
HEAD – текущая позиция (обычно указывает на ветвь).
Ключевой инвариант: содержимое будущего коммита определяется индексом, а не рабочей директорией.
Базовые команды (детерминированный минимум)
git init # инициализация репозитория
git status # текущее состояние
git add <path> # индексировать изменения
git commit -m "msg" # зафиксировать индекс в коммит
git log --oneline --graph --decorate
git branch <name> # создать ветвь
git switch <name> # переключиться
git merge <name> # слить указанную ветвь в текущую
git rebase <base> # переписать историю на новую базу (локально)
git remote add origin <url>
git push -u origin <branch>
git pull --ff-only # безопасное обновление: только fast-forward
# Создание и первая фиксация
git init && git add . && git commit -m "Init"
# Новая ветвь от текущей
git switch -c feature/x
# Интерактивный индекс (только нужные куски)
git add -p
# Безопасная синхронизация
git fetch origin
git rebase origin/main # до публикации
git pull --ff-only # после публикации
# Слияние без коммита (просмотр результата)
git merge --no-commit --no-ff feature/x
# Отмена последнего коммита, сохранив изменения в WD
git reset --soft HEAD~1
# Аннулировать файл до состояния HEAD
git checkout -- path/to/file
# Теги релизов
git tag -a v1.2.0 -m "Release 1.2.0"
git push origin v1.2.0
.gitignore (фрагмент-шаблон):
# Python
__pycache__/
*.py[cod]
.venv/
# Node
node_modules/
dist/
# OS
.DS_Store
Thumbs.db
Упражнение 1. «Топологический порядок коммитов»
Условие. Дан граф коммитов (рёбра направлены от родителя к ребёнку):
C0 → C1 → C3
C0 → C2 → C3 → C4
Решение.
Упражнение 2. «Разбор конфликта при трёхстороннем слиянии»
Условие. Базовый файл B:
value = 10
В ветви A:
value = 10
value += 5
В ветви D:
value = 12
Слить A и D.
Решение. Общий предок – строка value = 10. Изменения конфликтуют: одна ветвь меняет константу, другая добавляет строку. Варианты корректного разрешения зависят от доменной логики:
value = 12
value += 5
value = 15
Правильно – зафиксировать выбранную семантику в сообщении коммита и тестах.
Упражнение 3. «Безопасность истории»
Условие. Вы ошибочно закоммитили пароль в config.json и уже отправили в общий репозиторий. Что делать? Приведите корректную последовательность шагов.
Решение.
Упражнение 4. «Консистентный .gitignore»
Условие. Проект на Python + Node. Требования: не хранить кэш, виртуальные окружения, каталоги сборки и артефакты ОС. Составьте фрагмент .gitignore и поясните, почему он предотвращает рост репозитория.
Решение.
# Python
__pycache__/
*.py[cod]
.venv/
# Node
node_modules/
dist/
# Build
build/
*.egg-info/
# OS
.DS_Store
Thumbs.db
Обоснование: исключаются детерминируемые/воспроизводимые артефакты и «мусор» ОС, тем самым уменьшается размер истории и ускоряется клонирование.
Упражнение 5. «Политика ветвления и релизов»
Условие. В компании принята схема: стабильная main, рабочие feature/*, интеграционная develop, релизы тегируются vMAJOR.MINOR.PATCH. Опишите корректную последовательность действий при выпуске минорного релиза 1.5.0 с одной новой фичей feature/login.
Решение.
Система контроля версий – не просто инструмент сохранения файлов, а формальная дисциплина управления изменениями: DAG коммитов с криптоадресацией, строгие правила ветвления, трёхстороннее слияние и инварианты стабильности. Следование изложенным правилам повышает предсказуемость разработки, сокращает стоимость ошибок и обеспечивает воспроизводимость результатов. Для ЕГЭ это даёт прямые бонусы: понимание графов, хешей, формальных языков и алгоритмов слияния – всё это тренирует вычислительное мышление, скорость и аккуратность решения задач.