Ветка — для каждой задачи
Работа идёт не в main, а в отдельной ветке от её актуальной версии:
git switch main
git pull
git switch -c feature/login
Дальше цикл повторяется:
git status # что изменилось
git diff # как именно
git add src/login.py
git commit -m "Добавить вход по коду из письма"
Индекс (staging) — промежуточная зона: в коммит попадает только то, что добавлено через git add. Перед каждым коммитом смотрят git status и git diff — так в историю не попадают отладочные строки, лишние файлы и секреты.
Готовую ветку отправляют на сервер и открывают pull request:
git push -u origin feature/login
Хороший коммит
- Одно логическое изменение, которое собирается и проходит тесты.
- Сообщение — что и зачем, в повелительном наклонении: «Добавить вход по коду», «Исправить округление в итоговой сумме».
- «fix», «wip», «правки» — плохие сообщения: через месяц никто не поймёт, что в них.
В .gitignore заносят то, что не должно попасть в репозиторий: результаты сборки, зависимости, файлы IDE и секреты.
merge и rebase
Ветка отстала от main — её нужно обновить. Есть два способа.
- merge соединяет ветки коммитом слияния, история остаётся как была.
- rebase переносит коммиты ветки поверх main. Получаются новые коммиты с другими хешами, история становится линейной.
Отсюда главное правило: rebase переписывает историю, поэтому его делают только с локальными или личными ветками. Переписать опубликованную общую ветку — значит сломать работу коллег, у которых остались старые коммиты. Если личную ветку после rebase нужно отправить снова — git push --force-with-lease: в отличие от --force, он не затрёт чужие новые коммиты.
Конфликты
Конфликт возникает, когда обе ветки изменили одни и те же строки. Git отмечает их в файле:
<<<<<<< HEAD
total = price * count
=======
total = round(price * count, 2)
>>>>>>> feature/rounding
Сверху — ваша версия, снизу — входящая. Нужно понять смысл обоих изменений и собрать правильный итог — часто это комбинация. Затем убрать маркеры, git add и продолжить: git commit или git rebase --continue. После — обязательно собрать проект и прогнать тесты: код без маркеров ещё не значит рабочий.
Запутались — git merge --abort или git rebase --abort вернут всё как было. Частые небольшие слияния дают меньше конфликтов, чем одно большое в конце.
Как отменить
| Что нужно | Команда |
|---|---|
| Отменить правки в файле | git restore файл |
| Убрать файл из индекса | git restore --staged файл |
| Поправить последний неопубликованный коммит | git commit --amend |
| Отменить локальные коммиты, сохранив правки | git reset --soft HEAD~1 |
| Отменить опубликованный коммит | git revert <хеш> |
git reset двигает ветку назад и годится только для локальных коммитов. --hard при этом удаляет изменения — самый частый способ потерять работу. git revert создаёт новый коммит, отменяющий старый, и историю не переписывает — поэтому для опубликованного используют его.
Если всё-таки потеряли коммит — git reflog помнит, куда указывала ветка, и позволяет вернуться.
Что запомнить
- Каждая задача — в своей ветке, каждый коммит — одно изменение.
- Перед коммитом —
git statusиgit diff. - rebase — только для неопубликованного, push после него — с
--force-with-lease. - reset — для локального, revert — для опубликованного.