# Контроль версий: зачем он нужен и базовые понятия Git<no value>

## Что мы изучим?

- Что такое **контроль версий** (Version Control) и почему им пользуется каждый разработчик.
- Что такое **Git**.
- Три области: **Working Directory**, **Staging Area**, **Repository**.
- Что такое **Commit**.
- Первоначальную настройку Git.

## Зачем это нужно?

Знакома такая папка?

```text
project_final.py
project_final_v2.py
project_final_v2_WORKS.py
project_final_v3_dont_touch.py
project_final_v3_fixed_REALLY_FINAL.py
```

Проблемы:

- **Какая версия работает?** Что именно изменилось между v2 и v3?
- **«Я что-то сломал, а вчера всё работало!»** Как вернуться к вчерашнему состоянию?
- **Командная работа:** два человека отредактировали один и тот же файл. Как объединить изменения, не перезаписав друг друга?
- **Резервная копия:** ноутбук украли. Проект потерян?

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

## Объяснение с основ

### Что такое контроль версий?

**Контроль версий** (Version Control) — система, которая **записывает историю файлов**: каждое изменение, когда оно сделано, кем и зачем. Можно вернуться в любую точку в прошлом, сравнить версии и объединить работу нескольких людей.

### Что такое Git?

**Git** — самая распространённая система контроля версий в мире, с огромным отрывом. Она:

- **Локальная** — вся история хранится **на вашем компьютере**, в скрытой папке `.git`. Работает даже без интернета.
- **Распределённая** — у каждого разработчика есть **полная** копия всей истории.
- **Быстрая и бесплатная**, изначально написана Линусом Торвальдсом, создателем Linux.

**Git ≠ GitHub!** Git — это **инструмент**, который работает на вашем компьютере. **GitHub** — это **сайт**, который хранит копию вашего репозитория в облаке и добавляет инструменты для совместной и командной работы. Мы познакомимся с ним в третьем уроке.

### Repository

**Repository** (репозиторий, сокращённо **Repo**) = проект, который отслеживает Git: папка с файлами **плюс** скрытая папка `.git`, где хранится вся история.

### Commit — снимок

**Commit** = сохранённый **снимок** проекта в определённый момент, у которого есть:

- **Сообщение**, объясняющее, что изменилось и зачем.
- **Автор** (имя и email) и **время**.
- **Уникальный идентификатор** (Hash), например `a3f9c21`.
- Ссылка на **предыдущий** Commit — так образуется **цепочка** истории.

```text
(a3f9c21) ◄── (7b2e004) ◄── (e91d5aa)   ← HEAD (latest)
"Initial      "Add price     "Fix VAT
 project"      calculator"    rounding"
```

{{< box "analogy" "Аналогия: точки сохранения в игре" >}}
**Commit** = точка сохранения в компьютерной игре. Перед битвой с боссом вы сохраняетесь. Если проиграли — возвращаетесь к этой точке. Разница: в Git **каждая** точка сохранения остаётся навсегда, с описанием, и можно вернуться к любой из них или сравнить их.
{{< /box >}}

### Три области

Это самое важное понятие урока. Каждый файл проекта находится в одной из трёх «областей»:

```text
 Working Directory        Staging Area            Repository (.git)
 (the files you edit)     (ready for the next     (committed history)
                           commit)
       │                        │                        │
       │──── git add ──────────►│                        │
       │                        │──── git commit ───────►│
       │◄──────────────────── (checkout / restore) ──────│
```

| Область | Что это | Как туда попасть |
|---|---|---|
| **Working Directory** | Папка, в которой вы работаете: файлы в том виде, в каком они сейчас на диске | Просто редактируете файлы |
| **Staging Area** (её также называют Index) | «Область подготовки»: изменения, которые вы выбрали для **следующего** Commit | `git add` |
| **Repository** | Сохранённая история: все Commit | `git commit` |

**Зачем нужен Staging?** Потому что иногда вы изменили 5 файлов, но только 3 из них относятся к одному логическому изменению («исправление бага в калькуляторе»). Staging позволяет выбрать **точно**, что войдёт в каждый Commit, чтобы каждый Commit был одной логической единицей.

{{< box "analogy" "Аналогия: групповая фотография" >}}
**Working Directory** = все люди на мероприятии. **Staging Area** = люди, которых вы пригласили встать перед камерой («давай, ты, в кадр»). **Commit** = нажатие кнопки: фото сохраняется в альбоме (Repository) навсегда. Кто не встал перед камерой, того на фото нет, даже если он на мероприятии.
{{< /box >}}

### Состояния файлов

| Состояние | Значение |
|---|---|
| **Untracked** | Новый файл, который Git ещё не отслеживает |
| **Modified** | Известный файл, который изменился с последнего Commit, но ещё не в Staging |
| **Staged** | Изменение в Staging, готово к Commit |
| **Committed** (Unmodified) | Идентичен последнему Commit, «чистый» |

## Синтаксис

**Установка:** Git был установлен в первый день курса. Проверьте: `git --version`.

**Однократная настройка** (один раз на компьютер). Git записывает имя и email в каждый Commit:

```powershell
git config --global user.name "Dana Cohen"
git config --global user.email "dana@example.com"
git config --global init.defaultBranch main
git config --global core.editor "code --wait"
```

| Команда | Значение |
|---|---|
| `user.name` / `user.email` | Кто написал Commit. В уроке 3 — тот же email, что и в аккаунте GitHub. |
| `init.defaultBranch main` | Главная ветка будет называться `main` (современное соглашение). |
| `core.editor "code --wait"` | Если Git нужно открыть редактор, он откроет VS Code. |
| `--global` | Настройка действует для всех проектов на компьютере. |

**Проверка:**

```powershell
git config --global --list
```

## Первый пример кода

Посмотрим на идею «трёх областей» в командах. В следующем уроке подробно разберём каждую.

```powershell
mkdir ~\dev\kodkod6\git-demo
cd ~\dev\kodkod6\git-demo
git init
```

**Вывод:**

```text
Initialized empty Git repository in C:/Users/dana/dev/kodkod6/git-demo/.git/
```

Теперь есть репозиторий. Создана скрытая папка `.git`. Её можно увидеть через `ls -Force` (PowerShell) или `ls -a` (Bash).

## Разбор кода построчно

| Строка | Объяснение |
|---|---|
| `mkdir ...git-demo` | Обычная папка для проекта. |
| `cd ...git-demo` | Войти в неё. **Все команды Git действуют на репозиторий текущей папки.** |
| `git init` | **init**ialize: превращает папку в репозиторий и создаёт внутри неё `.git`. |
| `.git/` | «Мозг» репозитория: все Commit, история и настройки. **Не трогайте её вручную.** Если её удалить, удалится вся история (сами файлы останутся). |

## Ещё один пример

**Путь одного изменения через три области**, с `git status` после каждого шага (все детали — в следующем уроке):

```powershell
New-Item hello.py
git status
git add hello.py
git status
git commit -m "Add hello.py"
git status
```

**Вывод (сокращённо):**

```text
Untracked files:
        hello.py

Changes to be committed:
        new file:   hello.py

[main (root-commit) 3c1f2a9] Add hello.py
 1 file changed, 0 insertions(+), 0 deletions(-)

nothing to commit, working tree clean
```

| Шаг | Состояние `hello.py` | Область |
|---|---|---|
| После `New-Item` | **Untracked** | Только Working Directory |
| После `git add` | **Staged** | Staging Area |
| После `git commit` | **Committed**, и «working tree clean» | Repository |

## Типичная ошибка

**Ошибка 1: `git init` не в той папке**, например в домашней папке (`C:\Users\dana`) или внутри папки, которая уже находится внутри другого репозитория. Тогда Git отслеживает **все** файлы на компьютере, или создаются запутанные вложенные репозитории.

**Всегда:** `cd` в папку проекта, `pwd`, чтобы убедиться, и только потом `git init`. А если ошиблись — удалите скрытую папку `.git`, созданную по ошибке (только её!).

**Ошибка 2: «Я сделал `git add`, значит, сохранено».** Нет! `add` только подготавливает. В историю сохраняет только **`commit`**. А изменение, сделанное **после** `add`, не войдёт, пока вы снова не сделаете `add`.

**Ошибка 3: думать, что Git делает резервную копию в облако.** Git локален. Если ноутбук потерян, репозиторий потерян вместе с ним — если только вы не сделали **push** на GitHub (урок 3).

**Ошибка 4: не настроить `user.name` / `user.email`.**

```text
Author identity unknown
*** Please tell me who you are.
```

Git отказывается делать Commit, не зная, кто автор. Выполните команды `config` из примера выше.

<!-- exercises:start — generated by scripts/intro6/sync_site_exercises.py; edit scripts/intro6/exercises/ -->
## Практика

Упражнения опираются только на то, что пройдено в этом уроке и в предыдущих. Сначала попробуйте сами, и только потом открывайте решение.

### Упражнение 1: Зачем нужен контроль версий?

В папке Дани такие файлы:

```text
project_final.py
project_final_v2.py
project_final_v2_WORKS.py
project_final_v3_dont_touch.py
```

Назовите три проблемы этого метода и как Git решает каждую.

{{< solution >}}
| Проблема | Как Git её решает |
|---|---|
| Непонятно, чем отличаются файлы и что изменилось в каждом | Каждый **Commit** сохраняет точно, что изменилось, с сообщением, объясняющим почему |
| Нельзя узнать, какая версия действительно последняя рабочая | Есть одна упорядоченная история, и **HEAD** указывает на текущее состояние |
| Когда работают несколько человек, каждый добавляет «ещё одну версию» | Все работают с одним **репозиторием**, и Git умеет объединять изменения |
{{< /solution >}}

### Упражнение 2: Три области

Для каждого действия — в какой области находится изменение после него: Working Directory, Staging Area или Repository?

1. Вы отредактировали `calculator.py` и сохранили его.
2. Вы выполнили `git add calculator.py`.
3. Вы выполнили `git commit -m "Add subtract"`.

{{< solution >}}
1. **Working Directory** — изменение существует только в файле на диске.
2. **Staging Area** — изменение отмечено как часть следующего Commit.
3. **Repository** — изменение сохранено как снимок в истории.
{{< /solution >}}

### Упражнение 3: Первая настройка

Напишите команды, которые задают для Git имя `Dana Cohen` и email `dana@example.com`, а затем создают новый репозиторий в текущей папке. Зачем Git нужны имя и email?

{{< solution >}}
```powershell
git config --global user.name "Dana Cohen"
git config --global user.email "dana@example.com"
git init
```

Git записывает в каждый Commit, **кто** его сделал. Без имени и email Git не согласится сделать Commit. `--global` сохраняет настройку один раз для всех репозиториев на компьютере.
{{< /solution >}}

### Упражнение 4: Цепочка Commit

```text
(a3f9c21) <── (7b2e004) <── (e91d5aa)  <- HEAD
"Initial      "Add price     "Fix VAT
 project"      calculator"    rounding"
```

1. Что такое каждый из идентификаторов `a3f9c21`, `7b2e004`, `e91d5aa`?
2. На что указывает HEAD?
3. Почему каждый Commit «указывает» на предыдущий?

{{< solution >}}
1. Это **идентификаторы Commit** — каждый Commit получает уникальный идентификатор (здесь сокращённый).
2. **HEAD** указывает на текущий Commit — `e91d5aa`, «Fix VAT rounding». В этом состоянии файлы находятся сейчас.
3. Так образуется **история**: от каждого Commit можно вернуться назад, увидеть, что было до него, и вернуться в любую точку в прошлом.
{{< /solution >}}

### Упражнение 5: Зачем нужна Staging Area?

Сегодня вы изменили в проекте три вещи: исправили баг в калькуляторе, улучшили README и добавили временный тестовый файл, который не хотите сохранять. Как здесь помогает Staging Area?

{{< solution >}}
Staging Area позволяет **выбрать**, что войдёт в каждый Commit:

1. `git add calculator.py` → Commit: «Fix rounding bug in calculator».
2. `git add README.md` → Commit: «Improve README».
3. Временный тестовый файл вообще не добавляется.

Так каждый Commit — это **одно логическое изменение** с понятным сообщением, а не смесь всего, чего вы касались за день.
{{< /solution >}}

<!-- exercises:end -->

## Итоги

- **Контроль версий** записывает каждое изменение и позволяет возвращаться назад, сравнивать и работать в команде. **Git** — инструмент. **GitHub** — сайт, который хранит его в облаке.
- **Repository** = проект + скрытая папка `.git` со всей историей.
- **Commit** = снимок с сообщением, автором, временем и идентификатором (Hash).
- Три области: **Working Directory** → (`git add`) → **Staging Area** → (`git commit`) → **Repository**.
- Однократная настройка: `git config --global user.name` / `user.email`.

<!-- docs:start — generated by scripts/intro6/site_docs.py; edit the links there -->

## Официальная документация

- [Pro Git — About Version Control](https://git-scm.com/book/en/v2/Getting-Started-About-Version-Control)
- [Pro Git — What is Git?](https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F)
- [Pro Git — First-Time Git Setup](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup)

<!-- docs:end -->
