Git-курс
0/6 модулей

Модуль 1 — Что такое Git и зачем он нужен

Модель данных Git и четыре состояния файла. ~5 минут.

Снимки, не дельты

Когда ты делаешь коммит, Git сохраняет полный снимок всего проекта на этот момент. Не diff от предыдущего коммита — целиком все файлы (с дедупликацией внутри хранилища, поэтому реально места уходит мало).

История — это лента снапшотов:

commit C  →  index.html  app.js  README.md   (полный снимок)
   ↑
commit B  →  index.html  app.js               (полный снимок, app.js был другой)
   ↑
commit A  →  index.html                       (полный снимок, app.js ещё не было)

Аналогия: фотоальбом, а не дневник правок. Откатиться к любой версии — это просто «достать тот снапшот».

Четыре состояния файла

Один и тот же файл в Git может быть в одном из четырёх состояний. Понимание переходов между ними — ключ ко всему остальному.

1. Untracked — Git не знает о файле

Файл лежит в папке проекта, но никогда не был добавлен в Git. git status покажет его в красной секции «Untracked files».

Пример: создал notes.txt, ещё не делал git add.

2. Modified — Git знает, видит изменения

Файл уже когда-то закоммичен, ты его поменял, но изменения пока не в stage. git status покажет в секции «Changes not staged for commit».

Пример: отредактировал app.py, который был в прошлом коммите.

3. Staged — в индексе, готов к коммиту

Сделал git add: изменения отложены в stage (он же индекс). Это «черновик следующего коммита». В git status — секция «Changes to be committed».

Пример: git add app.py прошёл; git commit ещё нет.

4. Committed — записан в историю

После git commit снимок отправляется в историю репо. С этого момента состояние «зафиксировано» и его можно вытащить обратно когда угодно.

Жизненный цикл одного изменения:

Untracked  →  (git add)  →  Staged  →  (git commit)  →  Committed
                                            ↑
              изменил файл  →  Modified  →  (git add)  →  ...

Локально и удалённо

Вся история Git живёт в скрытой папке .git/ внутри проекта — это локальный репозиторий. Никакой связи с интернетом для базовой работы не нужно: коммиты, ветки, история — всё локально.

Удалённый репозиторий — копия твоего репо на сервере (GitHub, GitLab, Bitbucket, свой). С ним общаются через git push (отправить локальные коммиты) и git pull (забрать чужие). Подробности — в Модуле 5.

Проверь себя

Ты только что создал файл todo.md и сохранил. git add ещё не делал. В каком он состоянии?
Untracked
Modified
Staged
Committed
Файл app.py был в прошлом коммите. Ты его отредактировал, сохранил, но git add не делал. В каком состоянии файл?
Untracked
Modified
Staged
Committed
Ты сделал git add app.py. Прошло успешно, git commit ещё не запускал. В каком состоянии файл сейчас?
Untracked
Modified
Staged
Committed
Теперь ты понимаешь модель снимков и различаешь четыре состояния файла. Дальше — как создать репозиторий и начать с ним работать.

Модуль 2 — Настройка и создание репозитория

Первая конфигурация Git, git init, .gitignore. ~7 минут.

Первая настройка (один раз после установки Git)

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

git config --global user.name "Твоё Имя"
Имя автора коммитов. Видно всем, кто смотрит историю.
git config --global user.email "you@example.com"
Желательно тот же email, что и на GitHub/GitLab — тогда коммиты автоматически свяжутся с твоим аккаунтом.

Проверить, что записалось:

git config --global --list
Покажет все глобальные настройки.

Создание репозитория: init vs clone

Два способа начать работать с Git в проекте:

git init — новый репозиторий из существующей папки

Зайди в папку проекта (там может быть твой код или ещё ничего) и выполни:

git init
Создаёт скрытую папку .git/ — здесь будет вся история. Файлы проекта Git не трогает.

git clone — скачать существующий репозиторий

git clone <url>
Создаёт папку с именем репо рядом, тянет в неё всю историю. После — у тебя локальная копия со всеми ветками. Используй, если работаешь с уже существующим проектом на GitHub/GitLab.

.gitignore — что Git должен игнорировать

Не всё хочется хранить в репо: сборочные артефакты, кэши, секреты, виртуальные окружения. Список того, что Git должен пропустить, лежит в текстовом файле .gitignore в корне проекта. Сам файл — коммитится.

# зависимости / кэши
node_modules/
__pycache__/
*.pyc

# сборка
dist/
build/

# секреты — никогда не коммитить
.env
.env.local

# логи
*.log

# IDE
.vscode/
.idea/

Один паттерн на строку. Поддерживается glob: *.log, build/**. Строки с # — комментарии. Полезный совет: добавь .gitignore в самом начале, до первого коммита — иначе мусор успеет попасть в историю.

Открой Source Control: Ctrl+Shift+G (или иконка с ветвлением в левой панели). Если репо ещё нет — увидишь кнопку Initialize Repository, она просто запускает git init. Если репо есть — увидишь панель с текущими изменениями: справа от каждого файла кнопки + (stage), (откатить).

Попробуй в тренажёре

Этот терминал поддерживает базовые git-команды. В нём уже «лежат» два файла: README.md и index.html — но пока без git. Сделай по порядку:

  1. git init — создать репо
  2. git status — посмотри, что Git видит (там untracked файлы — мы их подложили)
  3. git add . — добавь всё в stage
  4. git status — заметь, как файлы переехали из «Untracked» в «Changes to be committed»
  5. git commit -m "init" — зафиксируй первый снимок в истории
  6. git log --oneline — убедись, что коммит появился
Теперь ты умеешь настроить Git и создать новый репозиторий — через CLI и через VSCode.

Модуль 3 — Базовый рабочий цикл: stage → commit

Главный цикл повседневной работы. ~8 минут.

Три команды, которые ты будешь печатать постоянно

git status
Что сейчас в каком состоянии: staged, modified, untracked. Запускай постоянно — между почти каждой парой команд. Это твой главный «компас».
git add <file>
Добавить конкретный файл в stage. Можно несколько через пробел: git add a.py b.py.
git add .
Добавить в stage всё изменённое и новое в текущей папке (и подпапках). Удобно, но коварно: легко закоммитить лишнее. Сначала всегда git status.
git commit -m "Добавить кнопку логина"
Зафиксировать всё, что в stage, как новый снапшот в истории. Флаг -m — короткое сообщение. Без него Git откроет редактор.
В Source Control панели: знак + рядом с файлом → stage этого файла. Знак + в заголовке «Changes» → stage всех. Поле сообщения сверху → текст коммита. Кнопка ✓ Commit (или Ctrl+Enter) → коммит. После коммита список изменений очищается.

Хорошие сообщения коммитов: правило 50/72

Сообщение коммита — это записка будущему себе и коллегам. Через полгода, когда что-то сломается, ты будешь искать «когда мы это меняли и почему» через git log. Качество сообщений == качество поиска.

Правила

  • Title ≤ 50 символов. Помещается в одну строчку любого UI.
  • Повелительное наклонение: «Add user auth», «Fix race in pool», «Update README». Не «Added», не «Fixing».
  • Смысл, а не механика: «Fix race in connection pool», не «Edit pool.go».
  • Если нужна подробность — пустая строка после title, затем тело до 72 символов в строке (отсюда «50/72»).

Хорошо / плохо

✓ Хорошо:

Add login button to header

Hooks up to existing /auth/login endpoint.
Closes ticket #PAY-142.

✗ Плохо:

fix
update file
.
WIP
asdfasdf

Плохие сообщения превращают git log в шум. Лучше потратить 10 секунд на формулировку — это спасает часы будущего поиска.

Разложи файлы по состояниям

Перетащи каждый файл в правильное состояние. У каждого подписано, что с ним только что сделали.

Доступные файлы
notes.txt (новый, ещё нет git add)
app.py (только что сделан git add app.py)
README.md (закоммичен вчера, не менялся)
.env.local (создан только что)
config.json (изменён и сделан git add)
main.go (закоммичен в прошлом коммите)
Untracked
Staged
Committed
Перетащи файлы из пула в нужную зону. Правильные становятся зелёными, неправильные — красными. Перепутал — перетащи в другую зону или обратно в пул.
Теперь ты умеешь делать цикл add → commit и писать сообщения, которые будут понятны через полгода.

Модуль 4 — Ветки

Параллельные линии работы. ~10 минут.

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

Ветка в Git — это подвижный указатель на коммит. И всё. Не копия файлов, не отдельная папка — просто текстовая ссылка на хэш одного коммита.

Когда ты делаешь новый коммит, ветка-указатель автоматически переезжает на этот новый коммит. Текущая ветка хранится в специальном указателе HEAD.

Аналогия: ветка = параллельная вселенная кода. Можно начать новую линию работы, экспериментировать, а потом либо слить обратно в main, либо удалить, если не получилось.

Команды

git branch
Список локальных веток. Звёздочка перед именем — текущая.
git branch feature-x
Создать ветку feature-x от текущего коммита. На неё не переключается — просто создаётся указатель.
git switch feature-x
Переключиться на ветку feature-x. Современный синоним старой команды git checkout feature-x.
git switch -c feature-x
Создать ветку и сразу переключиться (одной командой). Старый эквивалент — git checkout -b feature-x.
git merge feature-x
Слить ветку feature-x в текущую. Обычный сценарий: переключился на main, потом мержишь в неё свою feature.
Внизу слева, в статусбаре, — имя текущей ветки. Клик по нему открывает выпадающее меню: список существующих веток (выбор = switch), кнопка Create new branch (= switch -c). Очень удобно при ежедневной работе.

Merge vs Rebase — концептуально

Merge

Создаёт merge-коммит с двумя родителями: твой последний коммит и последний коммит сливаемой ветки. История сохраняется как есть — видно, что было параллельно. Безопасно (не переписывает прошлое), но граф становится «лохматым».

Rebase

Переписывает коммиты ветки так, как будто они изначально росли поверх target-ветки. История получается линейной и чистой. Но коммиты пересоздаются с новыми хэшами — нельзя rebase'ить то, что уже запушено и используется другими.

В этом курсе работаем только с merge — он проще и безопаснее для начала.

Поиграй с веткой

Каждая кнопка ниже = одна git-команда. Граф перерисовывается после каждого шага. Рекомендуемый сценарий — сверху вниз, чтобы получить merge-коммит:

  1. git commit (на main — он сейчас активен) — ещё один коммит на main
  2. git branch feature — создать ветку feature (указатель)
  3. git switch feature — переключиться
  4. git commit — коммит уже на feature
  5. git switch main — назад на main
  6. git commit — коммит на main (теперь main и feature разошлись)
  7. git merge feature — слить
Если ты прошёл сценарий по порядку (commit → branch → switch feature → commit → switch main → commit → merge feature) — сколько merge-коммитов в графе?
0
1
2
3
Теперь ты умеешь создавать ветки, переключаться, мержить и понимаешь, чем merge отличается от rebase.

Модуль 5 — Работа с удалённым репозиторием

push, pull, fetch и зачем нужен origin/main. ~7 минут.

Привязка к удалённому репо

Сначала — один раз — указать Git, где живёт удалённая копия:

git remote add origin <url>
Связать локальный репо с удалённым. origin — традиционное имя для основного удалённого. URL — то, что показывает GitHub/GitLab на странице репо (HTTPS или SSH).

Отправить локальные коммиты — push

git push -u origin main
Первый push. Флаг -u (или --set-upstream) запоминает связь «локальная main ↔ origin/main», и дальше можно просто:
git push
Без аргументов — отправит текущую ветку туда, где она tracking. Самая частая команда.

Забрать чужие коммиты — pull и fetch

git pull
Скачать чужие коммиты И сразу слить их в твою ветку. pull = fetch + merge (или + rebase, в зависимости от настроек).
git fetch
Только скачать обновлённые ветки origin в локальный кэш — без слияния. После fetch твой код не изменился; можно посмотреть, что нового, через git log origin/main, и решить, что делать.

Что такое origin/main

Это tracking branch — локальный кэш, как ветка main выглядела на удалённом репо при последнем fetch или pull. Может отставать от настоящего origin (пока не сделаешь fetch).

Полезно для сравнения: «что у меня локально нового по сравнению с origin/main» — git log origin/main..HEAD. Или наоборот: «что у origin есть, чего у меня нет» — git log HEAD..origin/main.

В верхней панели Source Control — три кнопки в выпадающем меню «...»: Sync (= pull + push), Push, Pull. В самом низу окна, в статусбаре, индикатор ↓N ↑M: коммитов позади / впереди origin. Клик по нему — синхронизация.

Сценарии — что делать?

Сценарий 1. Локально 2 новых коммита, у origin ничего нового. Что делать, чтобы поделиться с командой?
git push
git pull
git fetch
git merge
Сценарий 2. У origin 3 новых коммита (коллега запушил), локально новых коммитов нет. Что делать?
git push
git pull
git fetch
ничего не делать
Сценарий 3. И там, и там есть новые коммиты — у тебя 1 локальный, у origin 2 чужих. Что делать?
сразу git push
сначала git pull, потом git push
git fetch
удалить ветку и склонировать заново
Сценарий 4. Хочу посмотреть, что нового у origin, но не сливать ничего в свою ветку. Что делать?
git pull
git fetch
git push
git status
Теперь ты понимаешь push / pull / fetch и знаешь, какую команду выбрать в типовых ситуациях.

Модуль 6 — Конфликты и их разрешение

Когда Git не может слить две ветки сам. ~7 минут.

Почему возникает конфликт

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

Возникает при git merge, git rebase, git pull (потому что pull = fetch + merge), иногда при cherry-pick и stash pop.

Маркеры конфликта в файле

Когда Git не справляется, он оставляет в файле специальные маркеры:

def hello():
<<<<<<< HEAD
    print("Привет, мир!")
=======
    print("Hello, world!")
>>>>>>> feature
    return 0
  • <<<<<<< HEAD — начало твоей версии (текущая ветка)
  • ======= — разделитель
  • >>>>>>> feature — конец входящей версии (название ветки, которую ты сливаешь)

Нужно: выбрать одну версию, или собрать гибрид руками, и обязательно удалить все три маркера. Файл с маркерами — это сломанный код.

Mini merge editor

Жми на hunk — он попадёт в Result. Можно «Accept Both», тогда обе версии останутся (и почти всегда после этого нужна ручная правка).

HEAD — твоя ветка (main)
def hello(): print("Привет, мир!")
Incoming — feature
def hello(): print("Hello, world!")
(result пуст — кликни на hunk выше)

VSCode Merge Editor — без маркеров вручную

Когда возникает конфликт, VSCode подсвечивает файл и предлагает открыть Merge Editor — три пейна: Current / Incoming / Result. Кнопки Accept Current, Accept Incoming, Accept Both на каждом конфликтном блоке. Внизу — кнопка Complete Merge. Можно и просто редактировать файл в редакторе — на каждом блоке те же три кнопки и кнопка «Compare Changes».

После того, как разрешил конфликт

Маркеры удалены, код собран. Дальше:

git add <file>
Помечаешь файл как «конфликт решён». Можно сразу git add ., если уверен.
git commit
Без -m — Git сам подставит дефолтное сообщение «Merge branch ...», нужно только сохранить. После — merge завершён.

Если решил, что не хочешь продолжать merge — git merge --abort откатит всё к состоянию до начала merge.

Теперь ты читаешь маркеры конфликта и разрешаешь merge-конфликты — руками или через VSCode Merge Editor.

Готово 🎉

Курс пройден. Теперь ты умеешь:

  • Объяснить модель Git: снимки, не дельты; три состояния файла
  • Настраивать Git и инициализировать репозиторий (CLI и VSCode)
  • Делать цикл git addgit commit и писать хорошие сообщения
  • Работать с ветками: git branch, git switch, merge
  • Пушить и пулить с удалённым репо через origin
  • Разрешать merge-конфликты в VSCode

Что дальше

Углубление — Pro Git book: бесплатная книга на git-scm.com. Особенно полезны главы про rebase, reflog и тонкости merge-стратегий.