Введение
Профессиональное владение Git выходит за рамки базовых commit’ов. Senior-инженерам необходимо управлять сложными стратегиями ветвления, эффективно разрешать конфликты и поддерживать чистую историю проекта. В этом руководстве рассматриваются практические Git workflows и техники для профессиональных команд разработки.
Управление ветками
Workflow с feature-ветками
# Начните с обновлённой main
git checkout main
git pull origin main
# Создайте feature-ветку
git checkout -b feature/user-authentication
# Работайте, делайте commit, push
git add .
git commit -m "Add login form component"
git push -u origin feature/user-authentication
# Поддерживайте ветку в актуальном состоянии относительно main
git fetch origin
git rebase origin/main
# Или используйте merge, если вам так удобнее
git merge origin/main
# После ревью выполните merge в main
git checkout main
git merge --no-ff feature/user-authentication
git push origin main
# Очистка
git branch -d feature/user-authentication
git push origin --delete feature/user-authentication
Соглашения об именовании веток
feature/add-user-auth # Новая функциональность
bugfix/fix-login-error # Исправления ошибок
hotfix/security-patch # Срочные исправления в production
release/v1.2.0 # Подготовка релиза
docs/update-readme # Документация
refactor/cleanup-models # Рефакторинг кода
Лучшие практики для commit’ов
Атомарные commit’ы
Каждый commit должен представлять собой одно логическое изменение:
# Плохо: один commit с несколькими изменениями
git commit -m "Add login, fix header, update styles"
# Хорошо: отдельные commit’ы
git commit -m "Add login form validation"
git commit -m "Fix header alignment on mobile"
git commit -m "Update button styles for consistency"
Формат сообщения commit’а
<type>(<scope>): <subject>
<body>
<footer>
Пример:
feat(auth): add JWT token refresh mechanism
Implement automatic token refresh when access token expires.
The refresh happens 5 minutes before expiration to prevent
interruption of user sessions.
Closes #123
Типы:
feat: Новая функциональностьfix: Исправление ошибкиdocs: Документацияstyle: Форматирование (без изменения кода)refactor: Реструктуризация кодаtest: Добавление тестовchore: Задачи по сопровождению
Интерактивное добавление в индекс
# Добавляйте в индекс отдельные фрагменты
git add -p
# y: добавить этот фрагмент
# n: пропустить этот фрагмент
# s: разделить на более мелкие фрагменты
# e: отредактировать фрагмент вручную
# Интерактивно добавляйте в индекс отдельные файлы
git add -i
Стратегии слияния
Merge vs Rebase
# Merge: сохраняет историю, создаёт merge commit
git checkout main
git merge feature/branch
# Rebase: линейная история, переписывает commit’ы
git checkout feature/branch
git rebase main
git checkout main
git merge feature/branch # Fast-forward
Когда использовать каждый вариант
| Сценарий | Стратегия |
|---|
| Публичные ветки | Merge |
| Личные feature-ветки | Rebase |
| Общие feature-ветки | Merge |
| Обновление от main | Rebase (обычно) |
Разрешение конфликтов
# Во время merge
git merge feature/branch
# CONFLICT в file.txt
git status # Посмотреть конфликтующие файлы
# Отредактируйте файлы, чтобы разрешить конфликты
# Удалите маркеры конфликта: <<<<<<<, =======, >>>>>>>
# Отметить как решённое
git add file.txt
git commit
# Во время rebase
git rebase main
# CONFLICT в file.txt
# Разрешите конфликты
git add file.txt
git rebase --continue
# Или при необходимости прервите
git rebase --abort
Оставить локальную или удалённую версию
# Оставить нашу версию (текущая ветка)
git checkout --ours file.txt
# Оставить их версию (входящая ветка)
git checkout --theirs file.txt
# Для бинарных файлов
git checkout --ours -- path/to/binary.png
git add path/to/binary.png
Переписывание истории
Исправить последний commit
# Исправить сообщение commit’а
git commit --amend -m "New message"
# Добавить забытые файлы
git add forgotten-file.txt
git commit --amend --no-edit
Интерактивный rebase
# Отредактировать последние 5 commit’ов
git rebase -i HEAD~5
# В редакторе:
# pick abc1234 Первый commit
# reword def5678 Второй commit # Изменить сообщение
# squash ghi9012 Третий commit # Объединить с предыдущим
# fixup jkl3456 Четвёртый commit # Объединить, отбросить сообщение
# drop mno7890 Пятый commit # Удалить полностью
# edit pqr1234 Шестой commit # Остановиться для редактирования
# Во время остановки на edit
# Внесите изменения
git add .
git commit --amend
git rebase --continue
Squash commit’ов перед merge
# Свести все commit’ы feature-ветки в один
git checkout feature/branch
git rebase -i main
# Пометить все, кроме первого, как 'squash'
# Или squash merge
git checkout main
git merge --squash feature/branch
git commit -m "Add complete feature"
Stash изменений
Базовый stash
# Спрятать текущие изменения в stash
git stash
# Stash с сообщением
git stash save "WIP: working on login form"
# Включить неотслеживаемые файлы
git stash -u
# Включить неотслеживаемые и игнорируемые
git stash -a
# Список stash’ей
git stash list
# Применить и удалить
git stash pop
# Применить без удаления
git stash apply
# Применить конкретный stash
git stash apply stash@{2}
# Удалить stash
git stash drop stash@{0}
# Очистить все stash’и
git stash clear
Workflow со stash
# Работаете над фичей — приходит срочный баг
git stash save "feature: in progress"
# Исправьте баг в main
git checkout main
git checkout -b hotfix/urgent
# ... исправьте баг ...
git commit -m "fix: urgent bug"
git checkout main
git merge hotfix/urgent
# Вернитесь к фиче
git checkout feature/branch
git stash pop
Сравнение и ревью
Команды diff
# Рабочая директория vs индекс
git diff
# Индекс vs последний commit
git diff --staged
git diff --cached
# Между commit’ами
git diff abc123..def456
# Между ветками
git diff main..feature/branch
# Конкретный файл
git diff HEAD~3 -- path/to/file.txt
# Только сводка
git diff --stat
Сравнение веток
# Commit’ы в feature, которых нет в main
git log main..feature/branch
# Commit’ы, которые есть в одной, но не в обеих
git log main...feature/branch
# Какая ветка содержит commit
git branch --contains abc123
Восстановление после ошибок
Отмена изменений
# Отбросить изменения в рабочей директории
git checkout -- file.txt
git restore file.txt # Git 2.23+
# Убрать файл из индекса
git reset HEAD file.txt
git restore --staged file.txt # Git 2.23+
# Отменить последний commit (сохранить изменения)
git reset --soft HEAD~1
# Отменить последний commit (отбросить изменения)
git reset --hard HEAD~1
# Revert commit (создаёт новый commit)
git revert abc123
Восстановление удалённых веток
# Найдите commit
git reflog
# Воссоздайте ветку
git checkout -b recovered-branch abc123
Восстановление потерянных commit’ов
# Найдите в reflog
git reflog
# Восстановите через cherry-pick или reset
git cherry-pick abc123
# или
git reset --hard abc123
Git hooks
Pre-commit hook
# .git/hooks/pre-commit
#!/bin/sh
# Запустить линтер
npm run lint
if [ $? -ne 0 ]; then
echo "Lint failed. Commit aborted."
exit 1
fi
# Запустить тесты
npm test
if [ $? -ne 0 ]; then
echo "Tests failed. Commit aborted."
exit 1
fi
Commit-msg hook
# .git/hooks/commit-msg
#!/bin/sh
# Обеспечить соблюдение conventional commits
commit_regex='^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{1,50}'
if ! grep -qE "$commit_regex" "$1"; then
echo "Invalid commit message format."
echo "Example: feat(auth): add login functionality"
exit 1
fi
Работа с удалёнными репозиториями
Настройка SSH-ключа
# Сгенерировать SSH-ключ
ssh-keygen -t ed25519 -C "[email protected]"
# Запустить SSH agent
eval "$(ssh-agent -s)"
# Добавить ключ в agent
ssh-add ~/.ssh/id_ed25519
# Скопировать публичный ключ
cat ~/.ssh/id_ed25519.pub
# Добавить в настройки GitHub/GitLab
Несколько SSH-ключей
# ~/.ssh/config
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/github_key
Host gitlab.company.com
HostName gitlab.company.com
User git
IdentityFile ~/.ssh/gitlab_key
Удалить файлы из repo, но оставить локально
# Удалить из repo, оставить файл локально
git rm --cached sensitive-file.txt
echo "sensitive-file.txt" >> .gitignore
git commit -m "Remove sensitive file from tracking"
# Удалить игнорируемые файлы из repo
git rm -r --cached .
git add .
git commit -m "Remove files listed in .gitignore"
Уплотнить репозиторий
# Удалить неиспользуемые объекты
git gc --prune=now --aggressive
# Проверить размер репозитория
git count-objects -vH
Исправить проблемы с кодировкой при merge
# Для файлов со смешанными кодировками
git config --global merge.renormalize true
# Или вручную исправить конкретный файл
git checkout --ours problematic-file.txt
iconv -f WINDOWS-1252 -t UTF-8 problematic-file.txt > temp.txt
mv temp.txt problematic-file.txt
git add problematic-file.txt
git commit
Конфигурация
Полезные alias’ы
# Добавить в ~/.gitconfig
[alias]
st = status -sb
co = checkout
br = branch
ci = commit
lg = log --oneline --graph --decorate -20
lga = log --oneline --graph --decorate --all
last = log -1 HEAD --stat
unstage = reset HEAD --
amend = commit --amend --no-edit
undo = reset --soft HEAD~1
wip = !git add -A && git commit -m 'WIP'
cleanup = !git branch --merged | grep -v main | xargs git branch -d
# Показать имя текущей ветки
current = rev-parse --abbrev-ref HEAD
# Показать файлы, изменённые в последнем commit
changed = diff-tree --no-commit-id --name-only -r HEAD
# Список веток, отсортированный по последнему commit
recent = for-each-ref --sort=-committerdate refs/heads --format='%(committerdate:short) %(refname:short)'
Глобальная конфигурация
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
git config --global init.defaultBranch main
git config --global pull.rebase true
git config --global core.editor "vim"
git config --global merge.tool vimdiff
# Обработка переводов строк
git config --global core.autocrlf input # Linux/Mac
git config --global core.autocrlf true # Windows
# Более качественный алгоритм diff
git config --global diff.algorithm histogram
# Показывать неотслеживаемые директории
git config --global status.showUntrackedFiles all
Продвинутые workflows
Интерактивный rebase для чистой истории
Приведите историю в порядок до merge в main:
# Отредактировать последние 5 commit’ов
git rebase -i HEAD~5
# Доступные действия:
# - Squash: объединить commit’ы "WIP" в "Feature X"
# - Reword: исправить опечатку в сообщениях commit’ов
# - Drop: удалить случайные commit’ы
# - Edit: остановиться, чтобы изменить commit
Совет для senior: Относитесь к истории Git как к продукту. Чистая история (линейная, атомарные commit’ы) позволяет откатывать конкретные фичи, не откатывая весь релиз.
Поиск багов с помощью bisect и бинарного поиска
Когда появился баг?
- Ручной поиск: log n шагов
git bisect: Бинарный поиск (O(log n))
git bisect start
git bisect bad HEAD
git bisect good v1.0
# Автоматизируйте тестирование!
git bisect run npm test
Git выполнит checkout среднего commit’а, запустит тест и автоматически сузит диапазон, пока не найдёт точный commit, который внёс баг.
Submodules vs. Monorepo
Submodules: Указатели на конкретные commit’ы других repo.
- Боль: Забыли обновить указатель? Сборка ломается.
- Взгляд senior: Избегайте submodules, если в них нет строгой необходимости. Предпочитайте monorepo (Nx, Turborepo) или package managers (npm private registry).
# Если уж вам необходимо использовать submodules
git submodule update --init --recursive
git submodule foreach git pull origin main
Заключение
Освоение Git workflows улучшает командное взаимодействие и качество кода. Используйте feature-ветки для изоляции, осмысленные commit’ы для истории и rebase для чистых merge. Знайте варианты восстановления — reflog ваш лучший друг, когда что-то пошло не так. Помните: чистая история Git — это документация; сделайте так, чтобы она ясно рассказывала, как развивался ваш код.