Git

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

Уровень: начальный 20 разделов ⏱ 3–4 часа

1. Что такое Git

Git хранит полное состояние проекта (снимки, а не дельты) в папке .git. Работа выполняется локально, а обмен происходит с удалёнными репозиториями: GitHub, GitLab, Bitbucket.

Три зоны: working directory (файлы) → staging (index) → repository (коммиты).

2. Установка и настройка

git --version

git config --global user.name  "Имя"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
Имя и почта попадают в каждый коммит — настрой локально один раз, иначе Git будет ругаться при первом коммите.

3. Репозиторий и первые коммиты

git init
echo "hello" > README.md
git add README.md
git commit -m "Старт проекта"
git status

4. История и просмотр

git log --oneline --graph --all
git show HEAD        # последний коммит
git blame file.py    # кто менял строки

5. Файл .gitignore

# не попадают в репозиторий
__pycache__/
*.pyc
.env
node_modules/
dist/

Создавай .gitignore в начале проекта: среда, кэши и секреты не должны попадать в историю.

6. Ветки

git branch feat-login
git checkout feat-login        # или: git switch feat-login
git checkout -b feat-api       # новая ветка сразу
git branch -d feat-login       # удалить

Ветка — легковесная ссылка на коммит; главная обычно main.

7. Merge — слияние

git switch main
git merge feat-login           # влить ветку в main
git merge --no-ff feat-login   # явный merge-коммит

Если одни и те же строки меняли оба — возникнет конфликт. Решается вручную в файле, затем git add и git commit.

8. Rebase и история

git switch feat-api
git rebase main        # перенос ветки поверх main
git rebase -i HEAD~3   # интерактивно: squash, rename, reorder
Rebase переписывает историю. Не делай rebase на общих (публикованных) ветках — можешь сломать работу коллег.

9. Удалённый репозиторий

git remote add origin https://gitlab.com/user/proj.git
git push -u origin main
git pull
git clone https://github.com/user/proj.git

pull = fetch + merge; fetch только скачивает.

10. Отмена изменений

git restore file.py        # отменить правки в рабочей копии
git restore --staged file.py   # убрать из индекса
git reset --hard HEAD~1     # откатить (опасно!)
git commit --amend -m "новое сообщение"

11. Stash — заначка

git stash            # спрятать незакоммиченное
git stash pop        # вернуть
git stash list

Удобно, когда надо срочно переключиться на другую ветку.

12. Workflow командной работы

  1. от main → ветка фичи (feature/x).
  2. коммиты с осмысленными сообщениями.
  3. git fetch + rebase перед push.
  4. Push → Pull Request/Merge Request → код-ревью (в GitLab это отдельный урок).
Атомарные коммиты: один коммит = одна логическая правка. Так история читается, а поиск в git log работает.

13. Конфигурация и алиасы

Настраивай Git один раз, чтобы работать быстрее. Полезные настройки лежат в ~/.gitconfig:

[alias]
  co = checkout
  br = branch
  st = status -sb
  lg = log --oneline --graph --all
  last = log -1 HEAD --stat

Алиасы превращают длинные команды в короткие: git lg покажет весь граф веток, git last — последний коммит со списком изменённых файлов.

git config --global alias.co checkout
git config --global alias.st "status -sb"
Алиасы — личные: храни их в dotfiles и переноси на новую машину вместе с остальным конфигом.
Не сокращай опасные команды: алиас git reset --hard по одной букве — прямой путь к потере работы одним нажатием.

14. Теги и семантическое версионирование

Тег — именованная метка коммита, обычно для релизов. Соблюдение схемы MAJOR.MINOR.PATCH помогает команде понимать масштаб изменений:

ВерсияКогда повышать
MAJORломающие изменения API
MINORновая функциональность (без поломок)
PATCHисправления багов
git tag v1.2.0
git push origin v1.2.0
git tag -a v1.2.0 -m "Релиз: новый поиск"   # подписанный тег

Подписанные теги (-a -m) хранят автора и сообщение — в опенсорсе так принято отмечать релизы.

Тег всегда ставь на тот коммит, который реально деплоили. Лучше пометить старый коммит, чем сделать новый коммит «для релиза».

15. Экстренные сценарии: восстановление

Удалённые или потерянные изменения часто восстанавливаемы — Git почти ничего не выбрасывает неделями. Типовые приёмы:

git reflog                    # журнал всех операций с HEAD
git reset --hard HEAD@{3}      # вернуть состояние 3 шага назад
git fsck --lost-found          # найти потерянные объекты
git checkout --detach <hash>  # осмотреть коммит из reflog

git reflog — «кнопка отмены» для коммитов: он запоминает, где HEAD был до сброса, отката или rebase.

Всё это работает только для существующих объектов. Если изменения не были ни в одной из зон Git — удалённый файл без коммита не восстановить.

16. Работа с open source: fork и upstream

В GitHub и GitLab опенсорсный вклад обычно идёт через форк: копию репозитория под своим аккаунтом, поддержание синхронизации с оригиналом (upstream) и pull request.

git remote add upstream https://github.com/original/proj.git
git fetch upstream
git checkout main
git merge upstream/main     # обновить свою копию
git push origin main

Дальше — обычный цикл: ветка фичи, коммиты, push, PR. Решение конфликтов — как в разделе 7.

Перед большим PR синхронизируйся с upstream: чем свежее база, тем меньше конфликтов и быстрее ревью мейнтейнеров.
Вместо merge можно использовать git pull --rebase upstream main — история своей копии останется линейной, но перезапишется, что безопасно только в форке.

17. Conventional Commits и качество истории

Осмысленный коммит — это документация. Соглашение Conventional Commits ставит тип перед сообщением, и из истории можно автоматически строить changelog и версии:

feat(auth): добавить вход по email
fix(api): корректный код 404 при отсутствии записи
docs(readme): описание установки
refactor: вынести валидацию в отдельный модуль

Инструменты commitlint и standard-version собирают из таких сообщений релиз-патчи и changelog автоматически — команда получает историю релизов бесплатно.

Несодержательные сообщения («правки», «обновлено», «asdf») превращают git log в бесполезный поток. Один коммит — одна логическая правка, и сообщение объясняет «зачем», а не «что» (это видно в diff).

18. Безопасность: секреты и подпись коммитов

Секреты, попавшие в историю, остаются в ней навсегда, даже если файл удалён. Правило: перед коммитом проверяй git status и git diff, а .env держи в .gitignore с первого дня.

Если секрет всё же попал в историю — немедленно меняй его (ротируй), а историю чисти инструментом git-filter-repo: только он аккуратно переписывает историю с изъятием файла.

pip install git-filter-repo
git filter-repo --invert-paths --path .env
git push --force

Уровень доверия: подпись коммитов (GPG или SSH) позволяет верифицировать автора — на GitHub такие коммиты получают значок Verified. Настраивается через git config --global commit.gpgsign true.

Force push переписывает общую историю: сначала синхронизируйся с командой. И всё равно считай попавший в сеть секрет скомпрометированным.

19. Большие файлы: Git LFS

Git плохо дружит с бинарными файлами: каждый коммит хранит полную копию, репозиторий раздувается. Для ассетов, дампов баз и медиа есть Git LFS — вместо реального файла хранится указатель, а содержимое — в отдельном хранилище:

git lfs install
git lfs track "*.psd" "models/*.fbx"
git add .gitattributes

Решение о LFS принимай до первых коммитов: подключение LFS к уже раздутому репозиторию — болезненный рефакторинг истории.

Правило минимума: если файл генерируется из исходников (build, dist) — не храни его в Git вовсе; LFS оправдан только для настоящих исходных ресурсов.

20. Отладка: bisect, worktree и инструменты

Git умеет искать, кто внёс регрессию. git bisect выполняет бинарный поиск по истории: помечаешь плохой и хороший коммит — Git сам переключается к середине, пока не найдёт «виновника»:

git bisect start
git bisect bad          # текущее состояние сломано
git bisect good v1.0.0  # эта версия работала
# далее: протестировать → git bisect good/bad
git bisect reset

Поиск и чтение кода: git grep «pattern» — поиск по всей ветке, git log -S«string» — найти коммит, изменивший число вхождений строки, git log -p file — история изменений файла.

Параллельная работа без смены каталога: git worktree add ../feat2 branch-name создаёт вторую рабочую копию той же репы — правишь две ветки одновременно, коммиты не мешают.

В CI для больших репозиториев используй shallow clone (--depth 1): там нужна не вся история, а текущее состояние.
Связывай коммиты с задачами: Fixes #123 в сообщении автоматически закроет issue и создаст ссылку в истории.

Что дальше

Непрерывная интеграция, ревью и пайплайны — в уроке GitLab. Автоматизация сборки — Docker.

← Вернуться к курсам