Git в команде
Командная работа с Git строится вокруг веток, удалённого репозитория и проверки изменений перед их объединением с основной версией проекта.
Типичный процесс:
Обновить основную ветку
↓
Создать рабочую ветку
↓
Внести изменения и создать коммиты
↓
Отправить ветку на сервер
↓
Создать Pull Request / Merge Request
↓
Пройти автоматические проверки и code review
↓
Объединить изменения с основной веткой
↓
Удалить рабочую веткуПример:
git switch main
git pull
git switch -c feature/user-profile
# Изменение файлов
git add .
git commit -m "Добавлена страница профиля"
git push -u origin feature/user-profileПосле отправки ветки разработчик создаёт Pull Request на GitHub или Merge Request на GitLab.
Содержание
- Стратегии ветвления
- GitFlow
- GitHub Flow
- Trunk-based development
- Сравнение стратегий
- Pull Request и Merge Request
- Что сделано
- Как проверить
- Дополнительно
- Code review
- Способы объединения Pull Request
- Конфликты слияния
- Конфликт при `merge`
- Порядок разрешения конфликтов
- Как уменьшить количество конфликтов
- Merge и rebase
- Объединение через `merge`
- Перенос через `rebase`
- Конфликт при `rebase`
- Когда использовать merge, а когда rebase
- Интерактивный rebase
- Cherry-pick
- Squash commits
- Squash через интерактивный rebase
- Squash всей ветки через merge
- Squash and merge в Pull Request
- Сравнение merge, rebase, squash и cherry-pick
- Теги
- Просмотр тегов
- Легковесные теги
- Аннотированные теги
- Отправка тегов
- Удаление тега
- Версионирование релизов
- Релизы на GitHub и GitLab
- Добавлено
- Исправлено
- Обновление
- Предварительные версии
- Работа с форками
- `origin` и `upstream`
- Синхронизация форка
- Создание изменений в форке
- Обновление ветки форка перед Pull Request
- Удаление ветки после принятия Pull Request
- Типичный процесс работы в команде
- Типичный процесс создания релиза
- Командные правила
- Полезные команды
- Краткая памятка
Стратегии ветвления
Стратегия ветвления определяет:
- какие ветки используются в проекте;
- сколько времени живут ветки;
- от какой ветки начинается новая задача;
- в какую ветку объединяются изменения;
- как выпускаются релизы;
- как исправляются ошибки в опубликованной версии.
Основные стратегии:
- GitFlow;
- GitHub Flow;
- trunk-based development.
Не существует одной стратегии, подходящей всем проектам. Выбор зависит от размера команды, частоты релизов, зрелости автоматических тестов и процесса развёртывания.
GitFlow
GitFlow — стратегия с несколькими постоянными типами веток и отдельными ветками для функций, релизов и срочных исправлений.
Основные ветки:
main
develop
feature/*
release/*
hotfix/*Ветка main
Содержит опубликованные или готовые к публикации версии проекта.
main: v1.0 → v1.1 → v2.0Коммиты в main обычно соответствуют релизам и отмечаются тегами.
Ветка develop
Содержит изменения для следующего релиза.
Новые функции обычно создаются от develop и после завершения возвращаются в неё.
main
\
developВетки feature/*
Используются для разработки новых возможностей:
git switch develop
git pull
git switch -c feature/user-profileПосле завершения:
git switch develop
git merge --no-ff feature/user-profile
git branch -d feature/user-profileВ командной работе объединение обычно выполняется через Pull Request или Merge Request.
Ветки release/*
Создаются, когда команда начинает готовить новую версию:
git switch develop
git switch -c release/2.0.0В release-ветке обычно выполняются:
- исправление ошибок;
- обновление номера версии;
- подготовка документации;
- финальное тестирование;
- подготовка заметок о выпуске.
Новые крупные функции в release-ветку обычно не добавляются.
После подготовки релиза изменения объединяются с main:
git switch main
git merge --no-ff release/2.0.0
git tag -a v2.0.0 -m "Release 2.0.0"Затем изменения возвращаются в develop:
git switch develop
git merge --no-ff release/2.0.0
git branch -d release/2.0.0Ветки hotfix/*
Используются для срочного исправления ошибки в опубликованной версии.
Hotfix создаётся от main:
git switch main
git pull
git switch -c hotfix/login-errorПосле исправления:
git add .
git commit -m "Исправлена ошибка авторизации"Hotfix объединяется и с main, и с develop, чтобы исправление не потерялось в следующем релизе:
git switch main
git merge --no-ff hotfix/login-error
git tag -a v2.0.1 -m "Release 2.0.1"
git switch develop
git merge --no-ff hotfix/login-errorПосле этого ветку можно удалить:
git branch -d hotfix/login-errorСхема GitFlow
main A──────────────M──────────────R
\ ↑ ↑
develop B──C──D──E──F──G──H────────I
\ ↑ \ ↑
feature X───Y \ /
release J──K─LПреимущества GitFlow
- роли веток строго определены;
- удобно поддерживать несколько опубликованных версий;
- релиз можно тестировать отдельно;
- существует отдельный процесс для срочных исправлений;
- подходит для проектов с плановыми релизами.
Недостатки GitFlow
- большое количество веток;
- сложная история;
- функции могут объединяться долго;
- увеличивается вероятность конфликтов;
- стратегия может быть избыточной для небольших команд;
- хуже подходит для очень частого развёртывания.
GitFlow обычно выбирают для проектов с версиями и отдельными циклами подготовки релизов.
GitHub Flow
GitHub Flow — упрощённая стратегия, в которой есть основная ветка main и короткоживущие рабочие ветки.
Основные правила:
- ветка
mainвсегда должна оставаться рабочей; - новая задача выполняется в отдельной ветке;
- изменения отправляются на сервер;
- создаётся Pull Request;
- выполняются тесты и code review;
- после одобрения изменения объединяются с
main; - рабочая ветка удаляется.
Начало работы
git switch main
git pull
git switch -c feature/searchСоздание коммитов
git add .
git commit -m "Добавлена форма поиска"При необходимости создаются дополнительные коммиты:
git add .
git commit -m "Добавлена проверка поискового запроса"Отправка ветки
git push -u origin feature/searchПосле этого создаётся Pull Request:
base: main ← compare: feature/searchПосле объединения Pull Request
git switch main
git pull
git branch -d feature/searchЕсли удалённая ветка не была удалена автоматически:
git push origin --delete feature/searchСхема GitHub Flow
main A──B──────────────E
\ /
feature C──────────DПреимущества GitHub Flow
- простые правила;
- небольшое количество постоянных веток;
- удобно для частых изменений;
- хорошо сочетается с автоматическими тестами;
- подходит для небольших и средних команд;
- Pull Request становится центром обсуждения изменений.
Недостатки GitHub Flow
- основная ветка должна постоянно оставаться готовой к работе;
- требуется надёжная автоматическая проверка;
- сложнее поддерживать несколько старых версий продукта;
- незавершённые функции приходится скрывать с помощью feature flags.
Trunk-based development
Trunk-based development — стратегия, при которой разработчики часто интегрируют небольшие изменения в одну основную ветку.
Основная ветка может называться:
main
master
trunkРабочие ветки либо не используются, либо существуют очень недолго — обычно от нескольких часов до нескольких дней.
main: A──B──C──D──E──FВариант с короткими ветками:
main A──B────D──E────G
\ / \ /
feature C FРабота через короткую ветку
git switch main
git pull
git switch -c feature/small-validation-fixПосле небольшого изменения:
git add .
git commit -m "Добавлена проверка длины имени"
git push -u origin feature/small-validation-fixСоздаётся небольшой Pull Request, который быстро проверяется и объединяется с main.
Прямые коммиты в trunk
В небольших командах изменения иногда отправляются непосредственно в основную ветку:
git switch main
git pull
git add .
git commit -m "Исправлена подпись кнопки"
git pushДля крупных команд прямые изменения обычно ограничивают. Вместо них используют короткие ветки и обязательные проверки.
Feature flags
Если функция ещё не готова для пользователей, её можно объединить с основной веткой, но скрыть за программным переключателем.
Условный пример:
if (features.newProfilePage) {
showNewProfilePage();
} else {
showOldProfilePage();
}Это позволяет часто объединять изменения, не публикуя незавершённую функцию.
Требования trunk-based development
Стратегия особенно хорошо работает, если в проекте есть:
- автоматические тесты;
- быстрая сборка;
- обязательный code review;
- короткие задачи;
- небольшие Pull Request;
- feature flags;
- автоматическое развёртывание;
- возможность быстро отменить проблемное изменение.
Преимущества trunk-based development
- короткие ветки редко сильно расходятся;
- меньше сложных конфликтов;
- изменения быстро попадают в общую кодовую базу;
- упрощается непрерывная интеграция;
- уменьшается объём одного Pull Request.
Недостатки trunk-based development
- требует качественной автоматизации;
- требует дисциплины от команды;
- крупные задачи необходимо делить на небольшие части;
- незавершённые функции приходится скрывать;
- ошибка может быстро попасть в основную ветку, если проверки недостаточны.
Сравнение стратегий
| Характеристика | GitFlow | GitHub Flow | Trunk-based |
|---|---|---|---|
| Основные постоянные ветки | main, develop |
main |
main или trunk |
| Время жизни рабочих веток | Среднее или длительное | Короткое | Очень короткое |
| Отдельная release-ветка | Да | Обычно нет | Обычно нет |
| Отдельная hotfix-ветка | Да | Необязательно | Необязательно |
| Частота интеграции | Ниже | Высокая | Очень высокая |
| Сложность процесса | Высокая | Средняя | Низкая по структуре, высокая по требованиям |
| Поддержка плановых релизов | Хорошая | Возможна | Возможна через автоматизацию |
| Требования к CI | Желательны | Высокие | Очень высокие |
Общее практическое правило:
Редкие плановые релизы и несколько версий → GitFlow
Обычная разработка через Pull Request → GitHub Flow
Частая интеграция и зрелый CI/CD → trunk-basedPull Request и Merge Request
Pull Request (PR) — запрос на объединение изменений одной ветки с другой на GitHub.
Merge Request (MR) — аналогичный механизм на GitLab.
Несмотря на различие названий, их основная задача одинакова:
- показать изменения;
- запустить автоматические проверки;
- обсудить решение;
- провести code review;
- получить одобрение;
- объединить ветки.
Подготовка ветки
Перед началом новой задачи:
git switch main
git pull
git switch -c feature/password-resetПосле внесения изменений:
git status
git diff
git add .
git commit -m "Добавлено восстановление пароля"
git push -u origin feature/password-resetНаправление Pull Request
При создании PR или MR выбираются две ветки:
base / target: main
compare / source: feature/password-resetИзменения перемещаются:
feature/password-reset → mainОшибочный выбор направления может показать большое количество посторонних изменений.
Заголовок
Заголовок должен кратко описывать результат:
Добавлено восстановление пароляДругие примеры:
Исправлено переполнение карточки товара
Обновлена инструкция по установке
Добавлена фильтрация заказов по статусуОписание
Пример:
## Что сделано
Добавлена форма восстановления пароля.
Реализована проверка адреса электронной почты.
Добавлено сообщение об успешной отправке.
## Как проверить
1. Открыть страницу входа.
2. Нажать «Забыли пароль?».
3. Ввести корректный адрес.
4. Проверить сообщение об отправке.
## Дополнительно
Задача: PROJECT-123Описание помогает проверяющему понять цель и способ проверки изменений.
Draft Pull Request
Черновой Pull Request создаётся, если работа ещё не закончена, но разработчик хочет:
- показать направление решения;
- получить раннюю обратную связь;
- запустить проверки;
- обсудить архитектуру;
- сообщить о текущем прогрессе.
Черновой PR не должен объединяться до перевода в состояние готовности.
Размер Pull Request
Небольшой Pull Request проще:
- понять;
- проверить;
- протестировать;
- исправить;
- безопасно объединить;
- при необходимости отменить.
Желательно не смешивать в одном PR независимые изменения, например:
новая функция + массовое форматирование + обновление зависимостейЛучше разделить их на несколько запросов.
Code review
Code review — проверка изменений другим разработчиком перед объединением.
Цель review — не только поиск синтаксических ошибок. Проверяющий оценивает корректность решения, понятность кода, влияние на другие части проекта и наличие тестов.
Что проверяет автор перед отправкой
Автору полезно самостоятельно проверить:
- соответствует ли код задаче;
- нет ли случайно добавленных файлов;
- нет ли ключей, паролей и токенов;
- проходят ли тесты;
- запускается ли сборка;
- нет ли отладочного вывода;
- обновлена ли документация;
- понятны ли названия;
- достаточно ли описан Pull Request.
Локальная проверка:
git status
git diff main...HEAD
git log --oneline main..HEADmain...HEAD показывает изменения рабочей ветки относительно общего предка с main.
Что проверяет reviewer
При проверке обычно оцениваются:
- правильность поведения;
- обработка пограничных случаев;
- читаемость;
- соответствие стилю проекта;
- отсутствие дублирования;
- безопасность;
- производительность;
- обратная совместимость;
- качество тестов;
- понятность документации.
Типы комментариев
Комментарии удобно разделять по важности:
blocker — без исправления объединять нельзя
suggestion — рекомендуемое улучшение
question — вопрос о выбранном решении
nit — небольшое необязательное замечаниеПримеры:
Blocker: здесь возможен доступ к несуществующему элементу массива.Suggestion: эту проверку можно вынести в отдельную функцию.Question: почему используется последовательный запрос вместо параллельного?Nit: можно выбрать более точное имя переменной.Ответ автора
Автор может:
- исправить код;
- объяснить принятое решение;
- предложить альтернативу;
- попросить уточнение;
- создать отдельную задачу, если улучшение выходит за рамки текущего PR.
После исправлений:
git add .
git commit -m "Учтены замечания code review"
git pushPull Request обновится автоматически.
Одобрение
После проверки reviewer может:
- одобрить изменения;
- оставить комментарии;
- запросить обязательные исправления.
В репозитории могут быть настроены правила:
- минимум одно или два одобрения;
- обязательное прохождение тестов;
- запрет прямого
pushвmain; - обязательное обновление ветки;
- обязательная проверка определённым владельцем кода.
Способы объединения Pull Request
Платформы обычно предлагают три основных варианта:
Merge commit
Squash and merge
Rebase and mergeMerge commit
Все коммиты рабочей ветки сохраняются, а в основной ветке создаётся отдельный merge-коммит.
До объединения:
A──B────────E main
\ /
C──D─── featureПосле объединения история сохраняет структуру веток.
Преимущество — видна реальная история разработки. Недостаток — при большом количестве веток история становится сложнее.
Squash and merge
Все коммиты Pull Request объединяются в один новый коммит:
A──B──S mainЗдесь S содержит итоговые изменения коммитов C и D.
Преимущество — компактная линейная история. Недостаток — отдельные коммиты рабочей ветки не сохраняются в основной истории.
Rebase and merge
Коммиты рабочей ветки последовательно переносятся на вершину основной ветки:
A──B──C'──D' mainИстория остаётся линейной, а отдельные коммиты сохраняются. Их идентификаторы изменяются, потому что создаются новые коммиты.
Конфликты слияния
Конфликт слияния возникает, когда Git не может автоматически определить, как объединить изменения.
Типичный случай:
- один разработчик изменил строку в
main; - другой разработчик изменил ту же строку в своей ветке;
- ветки объединяются.
Конфликт также может появиться, если:
- один разработчик удалил файл, а другой изменил его;
- файл был по-разному переименован;
- изменились соседние участки текста;
- выполняется
merge,rebase,cherry-pickилиrevert.
Конфликт при merge
Обновить основную ветку:
git switch main
git pullПерейти в рабочую ветку и объединить main с ней:
git switch feature/profile
git merge mainЕсли Git обнаружит конфликт:
CONFLICT (content): Merge conflict in src/profile.js
Automatic merge failed; fix conflicts and then commit the result.Проверить состояние:
git statusПример конфликтующего файла:
<<<<<<< HEAD
const title = "Профиль пользователя";
=======
const title = "Личный кабинет";
>>>>>>> mainМаркеры означают:
<<<<<<< HEAD
текущая версия
=======
другая версия
>>>>>>> имя-веткиНеобходимо вручную оставить правильный результат, например:
const title = "Личный кабинет пользователя";После исправления маркеры конфликта должны быть полностью удалены.
Добавить исправленный файл:
git add src/profile.jsПосле разрешения всех конфликтов:
git commitИли:
git commit -m "Разрешены конфликты с веткой main"Проверить историю:
git log --oneline --graph --decorate --allОтправить результат:
git pushОтмена слияния
Если слияние не нужно продолжать:
git merge --abortКоманда пытается вернуть состояние, существовавшее до git merge.
Порядок разрешения конфликтов
Практический порядок:
- выполнить
git status; - открыть каждый конфликтующий файл;
- найти маркеры конфликта;
- понять назначение обеих версий;
- сформировать правильный итоговый код;
- удалить маркеры;
- запустить тесты и сборку;
- добавить исправленные файлы через
git add; - завершить операцию;
- отправить изменения.
Команды:
git status
git diff
git add path/to/conflicted-file
git commit
git pushgit status показывает, какая операция выполняется и какой командой её нужно продолжить.
Выбор одной версии файла
Во время обычного merge можно выбрать текущую версию:
git checkout --ours path/to/fileИли версию подключаемой ветки:
git checkout --theirs path/to/fileСовременный вариант:
git restore --ours path/to/file
git restore --theirs path/to/fileПосле выбора:
git add path/to/fileСледует учитывать, что при rebase смысл ours и theirs может восприниматься непривычно, поскольку Git переносит коммиты на новую основу. Поэтому перед выбором всей версии файла необходимо проверить содержимое.
Конфликт бинарных файлов
Для бинарного файла, например изображения, Git не может объединить содержимое построчно.
Нужно выбрать одну из версий:
git checkout --ours image.pngили:
git checkout --theirs image.pngЗатем:
git add image.pngЕсли нужны изменения из обеих версий, файл придётся восстановить или объединить подходящим внешним инструментом.
Как уменьшить количество конфликтов
Полностью исключить конфликты нельзя, но их количество можно сократить.
Полезные правила:
- регулярно обновлять рабочую ветку;
- создавать небольшие Pull Request;
- не держать ветки открытыми слишком долго;
- заранее распределять работу по файлам и модулям;
- не смешивать функциональные изменения с массовым форматированием;
- не переименовывать множество файлов без необходимости;
- быстро объединять готовые изменения;
- согласовывать крупные изменения структуры проекта.
Обновление рабочей ветки через merge:
git switch feature/profile
git fetch origin
git merge origin/mainОбновление через rebase:
git switch feature/profile
git fetch origin
git rebase origin/mainMerge и rebase
merge и rebase позволяют объединить изменения из разных линий разработки, но формируют разную историю.
Исходная история:
A──B──C main
\
D──E featureОбъединение через merge
Перейти в рабочую ветку и получить изменения main:
git switch feature
git merge mainРезультат:
A──B──C────M feature
\ /
D────EM — merge-коммит.
Коммиты D и E не изменяются. Их идентификаторы сохраняются.
Преимущества merge
- не переписывает существующие коммиты;
- безопасен для опубликованных веток;
- сохраняет реальную структуру разработки;
- явно показывает момент объединения веток.
Недостатки merge
- создаёт дополнительные merge-коммиты;
- история может стать сложной;
- большое количество параллельных веток затрудняет чтение
git log.
Перенос через rebase
Команда:
git switch feature
git rebase mainGit находит коммиты рабочей ветки и создаёт их заново поверх последнего коммита main.
Результат:
A──B──C──D'──E' featureИсходные D и E заменяются новыми коммитами D' и E'.
Преимущества rebase
- линейная история;
- меньше merge-коммитов;
- проще просматривать последовательность изменений;
- рабочую ветку можно подготовить к чистому fast-forward merge.
Недостатки rebase
- переписывает историю;
- изменяет идентификаторы коммитов;
- конфликты могут разрешаться отдельно для каждого переносимого коммита;
- опасен для общей ветки, которой уже пользуются другие разработчики.
Конфликт при rebase
Запуск:
git switch feature/profile
git fetch origin
git rebase origin/mainЕсли возник конфликт:
git statusИсправить файлы и добавить их:
git add src/profile.jsПродолжить перенос:
git rebase --continueЕсли следующий переносимый коммит также конфликтует, процесс повторяется:
# Исправить конфликт
git add .
git rebase --continueПропустить проблемный коммит:
git rebase --skipЭта команда полностью исключает текущий коммит. Использовать её следует только в том случае, если его изменения действительно больше не нужны.
Отменить весь rebase:
git rebase --abortПосле успешного rebase опубликованной рабочей ветки обычный push может быть отклонён, потому что история изменилась:
git push --force-with-lease--force-with-lease безопаснее, чем --force: команда проверяет, что удалённая ветка не получила неизвестные локальному репозиторию изменения.
Когда использовать merge, а когда rebase
Практическое правило:
Общая опубликованная ветка → merge
Собственная рабочая ветка → допустим rebasemerge рекомендуется, если:
- веткой пользуются несколько разработчиков;
- важно сохранить структуру ветвления;
- история уже опубликована;
- команда избегает переписывания коммитов.
rebase удобен, если:
- ветка принадлежит одному разработчику;
- нужно обновить её относительно
main; - требуется линейная история;
- команда разрешает переписывание рабочих веток.
Не следует выполнять rebase общей ветки без согласования:
git switch main
git rebase featureОсобенно опасно переписывать main, develop или другую ветку, которую уже получили участники команды.
Интерактивный rebase
Интерактивный rebase позволяет редактировать локальную историю:
git rebase -i HEAD~4Откроется список последних четырёх коммитов:
pick a1b2c3d Добавлена форма
pick b2c3d4e Исправлена кнопка
pick c3d4e5f Исправлена опечатка
pick d4e5f6a Добавлены тестыДоступные действия:
| Команда | Назначение |
|---|---|
pick |
Оставить коммит |
reword |
Изменить сообщение |
edit |
Остановиться для изменения коммита |
squash |
Объединить с предыдущим и отредактировать сообщение |
fixup |
Объединить с предыдущим и отбросить текущее сообщение |
drop |
Удалить коммит |
Интерактивный rebase переписывает историю. Его лучше использовать до объединения Pull Request и только для собственной рабочей ветки.
Cherry-pick
Cherry-pick переносит один выбранный коммит в текущую ветку.
Исходная история:
A──B──C main
\
D──E featureЕсли в main нужен только коммит E:
git switch main
git cherry-pick <hash-коммита-E>Результат:
A──B──C──E' main
\
D──E featureE' содержит те же изменения, но является новым коммитом с другим идентификатором.
Пример
Посмотреть историю:
git log --oneline --allВыбрать коммит:
7a92bd1 Исправлена проверка электронной почтыПеренести его:
git switch main
git cherry-pick 7a92bd1Перенос нескольких коммитов
Перечислить коммиты:
git cherry-pick 7a92bd1 3f827caПеренести диапазон, не включая первый указанный коммит:
git cherry-pick A..BПеренести диапазон, включая A:
git cherry-pick A^..BКонфликт при cherry-pick
Если возник конфликт:
git statusИсправить файлы:
git add .
git cherry-pick --continueОтменить операцию:
git cherry-pick --abortПропустить текущий коммит:
git cherry-pick --skipКогда использовать cherry-pick
Команда полезна, если:
- исправление случайно создано не в той ветке;
- один небольшой коммит нужно перенести в release-ветку;
- hotfix нужно применить к нескольким поддерживаемым версиям;
- из большой ветки требуется только одно независимое изменение.
Когда не использовать cherry-pick
Не стоит переносить через cherry-pick всю ветку из большого количества связанных коммитов. Для этого обычно лучше использовать merge или rebase.
Частое применение cherry-pick создаёт дублирующиеся изменения с разными хешами, из-за чего история становится сложнее.
Squash commits
Squash — объединение нескольких коммитов в один.
Рабочая ветка может содержать промежуточные коммиты:
A Добавлена форма входа
B Исправлена опечатка
C Исправлен отступ
D Учтено замечание reviewПосле squash:
S Добавлена форма входаИтоговый коммит содержит изменения всех четырёх коммитов.
Squash через интерактивный rebase
Объединить последние четыре коммита:
git rebase -i HEAD~4Откроется список:
pick a1b2c3d Добавлена форма входа
pick b2c3d4e Исправлена опечатка
pick c3d4e5f Исправлен отступ
pick d4e5f6a Учтено замечание reviewИзменить команды:
pick a1b2c3d Добавлена форма входа
fixup b2c3d4e Исправлена опечатка
fixup c3d4e5f Исправлен отступ
squash d4e5f6a Учтено замечание reviewfixup добавляет изменения к предыдущему коммиту и удаляет собственное сообщение.
squash добавляет изменения к предыдущему коммиту и предлагает отредактировать итоговое сообщение.
После переписывания опубликованной рабочей ветки:
git push --force-with-leaseНе следует выполнять squash общей ветки, если другие разработчики уже создали работу на основе её коммитов.
Squash всей ветки через merge
Перейти в принимающую ветку:
git switch mainПодготовить объединённые изменения:
git merge --squash feature/loginКоманда помещает итоговые изменения рабочей ветки в индекс, но не создаёт коммит автоматически.
Создать коммит:
git commit -m "Добавлена форма входа"История рабочей ветки не переносится в main как отдельные коммиты.
Важно: git merge --squash не создаёт обычную merge-связь между ветками. Git не отмечает ветку как объединённую стандартным merge-коммитом.
Squash and merge в Pull Request
На GitHub или GitLab можно выбрать вариант:
Squash and mergeПлатформа объединит все коммиты Pull Request в один коммит основной ветки.
Это удобно, если в рабочих ветках разрешены промежуточные коммиты:
WIP
Исправлен тест
Исправлено после review
Ещё одно исправлениеПри этом в main останется один содержательный коммит:
Добавлено восстановление пароляСравнение merge, rebase, squash и cherry-pick
| Операция | Назначение | Переписывает коммиты | Результат |
|---|---|---|---|
merge |
Объединить ветки | Нет | История веток сохраняется |
rebase |
Перенести коммиты на новую основу | Да | Линейная история |
squash |
Объединить несколько коммитов | Да или создаёт новый итоговый коммит | Один коммит вместо нескольких |
cherry-pick |
Перенести отдельный коммит | Создаёт копию коммита | Выбранное изменение появляется в другой ветке |
Теги
Тег — постоянная метка, указывающая на определённый коммит.
Теги обычно используются для обозначения версий:
v1.0.0
v1.1.0
v2.0.0В отличие от ветки, тег обычно не перемещается при создании новых коммитов.
A──B──C──D main
↑
v1.0.0Просмотр тегов
Показать все теги:
git tagПоиск по шаблону:
git tag -l "v1.*"Показать информацию:
git show v1.0.0Легковесные теги
Легковесный тег — простая ссылка на коммит:
git tag v1.0.0Он не содержит отдельного сообщения и данных автора тега.
Аннотированные теги
Аннотированный тег хранит:
- имя автора;
- дату;
- сообщение;
- ссылку на коммит.
Создание:
git tag -a v1.0.0 -m "Release 1.0.0"Для релизов обычно предпочтительнее использовать аннотированные теги.
Создать тег для конкретного коммита:
git tag -a v1.0.0 7a92bd1 -m "Release 1.0.0"Отправка тегов
Обычный git push не всегда отправляет локальные теги автоматически.
Отправить один тег:
git push origin v1.0.0Отправить все локальные теги:
git push origin --tagsУдаление тега
Удалить локальный тег:
git tag -d v1.0.0Удалить тег из удалённого репозитория:
git push origin --delete v1.0.0Не рекомендуется перемещать уже опубликованный тег на другой коммит. Участники команды могут сохранить старую версию этого тега, и в разных репозиториях одно имя будет указывать на разные коммиты.
Если релиз ошибочен, обычно лучше создать новую исправленную версию:
v1.0.0 → v1.0.1Версионирование релизов
Часто используется формат Semantic Versioning:
MAJOR.MINOR.PATCHПример:
2.4.1Значения:
| Часть | Когда изменяется |
|---|---|
MAJOR |
Добавлены несовместимые изменения |
MINOR |
Добавлена совместимая функциональность |
PATCH |
Добавлены совместимые исправления |
Примеры:
1.4.2 → 1.4.3 исправление ошибки
1.4.3 → 1.5.0 новая совместимая функция
1.5.0 → 2.0.0 несовместимое изменениеПрефикс v является распространённым соглашением:
v1.0.0
v1.2.0
v2.0.0Релизы на GitHub и GitLab
Release — опубликованная версия проекта, обычно связанная с Git-тегом.
Релиз может содержать:
- название версии;
- описание изменений;
- дату публикации;
- исходный код;
- собранные файлы;
- инструкции по обновлению;
- список исправлений;
- известные ограничения.
Типичный процесс:
git switch main
git pull
git tag -a v1.2.0 -m "Release 1.2.0"
git push origin v1.2.0После отправки тега на GitHub или GitLab создаётся Release и заполняются заметки.
Пример заметок:
# Версия 1.2.0
## Добавлено
- Фильтрация заказов по статусу.
- Экспорт отчёта в CSV.
- Настройка часового пояса.
## Исправлено
- Ошибка пагинации.
- Некорректное отображение длинных имён.
## Обновление
Установите зависимости и выполните сборку:
```bash
npm install
npm run build
---
## Предварительные версии
Для тестовых выпусков используются обозначения:
```text
v2.0.0-alpha.1
v2.0.0-beta.1
v2.0.0-rc.1Обычно они означают:
| Обозначение | Назначение |
|---|---|
alpha |
Ранняя нестабильная версия |
beta |
Версия для расширенного тестирования |
rc |
Кандидат на выпуск |
Пример последовательности:
v2.0.0-alpha.1
v2.0.0-beta.1
v2.0.0-rc.1
v2.0.0Работа с форками
Fork — копия чужого репозитория, созданная в учётной записи пользователя на GitHub или GitLab.
Форк используется, если:
- нет права отправлять ветки в исходный репозиторий;
- разработчик участвует в открытом проекте;
- нужна независимая копия проекта;
- изменения должны отправляться через Pull Request из собственного репозитория.
Схема:
Исходный репозиторий
organization/project
↓ fork
Личный репозиторий
user/project
↓ clone
Локальный репозиторийorigin и upstream
При работе с форком обычно используются два удалённых репозитория:
origin → личный форк
upstream → исходный репозиторийКлонирование форка
Сначала форк создаётся через веб-интерфейс GitHub или GitLab.
Затем клонируется личная копия:
git clone https://github.com/user/project.git
cd projectПроверить remotes:
git remote -vОбычно будет настроен только origin:
origin https://github.com/user/project.git (fetch)
origin https://github.com/user/project.git (push)Добавить исходный репозиторий:
git remote add upstream https://github.com/organization/project.gitПроверить:
git remote -vРезультат:
origin https://github.com/user/project.git
upstream https://github.com/organization/project.gitСинхронизация форка
Получить изменения исходного проекта:
git fetch upstreamОбновить локальную основную ветку через merge:
git switch main
git merge upstream/mainОтправить обновления в свой форк:
git push origin mainПолная последовательность:
git fetch upstream
git switch main
git merge upstream/main
git push origin mainСинхронизация через rebase
Если локальная ветка main не содержит собственных уникальных коммитов:
git fetch upstream
git switch main
git rebase upstream/main
git push origin mainЕщё более строгий вариант — сделать локальную main точной копией upstream/main:
git fetch upstream
git switch main
git reset --hard upstream/main
git push --force-with-lease origin mainЭтот вариант удалит собственные коммиты из main, поэтому его следует использовать только при уверенности, что личные изменения хранятся в отдельных ветках.
Создание изменений в форке
Сначала обновить main:
git fetch upstream
git switch main
git merge upstream/main
git push origin mainСоздать рабочую ветку:
git switch -c feature/improve-readmeВнести изменения и создать коммит:
git add README.md
git commit -m "Уточнена инструкция по установке"Отправить ветку в личный форк:
git push -u origin feature/improve-readmeЗатем создаётся Pull Request:
organization/project:main
↑
user/project:feature/improve-readmeТо есть ветка личного форка предлагает изменения основной ветке исходного репозитория.
Обновление ветки форка перед Pull Request
Если исходный проект изменился:
git fetch upstream
git switch feature/improve-readmeОбновить рабочую ветку через rebase:
git rebase upstream/mainПри конфликтах:
git status
# Исправить файлы
git add .
git rebase --continueПосле успешного rebase:
git push --force-with-leaseАльтернативный вариант через merge:
git merge upstream/main
git pushmerge безопаснее для общей ветки, а rebase создаёт более линейную историю.
Удаление ветки после принятия Pull Request
Удалить локальную ветку:
git switch main
git branch -d feature/improve-readmeУдалить ветку из личного форка:
git push origin --delete feature/improve-readmeОбновить main:
git fetch upstream
git merge upstream/main
git push origin mainТипичный процесс работы в команде
Обновить основную ветку:
git switch main
git pullСоздать рабочую ветку:
git switch -c feature/order-filterВнести изменения:
git status
git diff
git add .
git diff --staged
git commit -m "Добавлена фильтрация заказов"Отправить ветку:
git push -u origin feature/order-filterСоздать Pull Request или Merge Request.
Во время review внести исправления:
git add .
git commit -m "Учтены замечания code review"
git pushЕсли main обновилась, синхронизировать ветку:
git fetch origin
git rebase origin/main
git push --force-with-leaseИли без переписывания истории:
git fetch origin
git merge origin/main
git pushПосле объединения:
git switch main
git pull
git branch -d feature/order-filterТипичный процесс создания релиза
Обновить основную ветку:
git switch main
git pullПроверить историю:
git log --oneline --decorateЗапустить тесты и сборку:
npm test
npm run buildСоздать аннотированный тег:
git tag -a v1.4.0 -m "Release 1.4.0"Проверить тег:
git show v1.4.0Отправить его:
git push origin v1.4.0После этого на GitHub или GitLab можно создать Release, связанный с v1.4.0.
Командные правила
Перед началом работы команда должна договориться:
- какая стратегия ветвления используется;
- как называются ветки;
- куда создаются Pull Request;
- разрешён ли rebase;
- какой способ merge используется;
- нужно ли выполнять squash;
- сколько одобрений требуется;
- какие проверки обязательны;
- кто создаёт теги;
- кто публикует релизы;
- можно ли использовать force push.
Пример соглашения:
Основная ветка: main
Стратегия: GitHub Flow
Название веток: feature/*, fix/*, docs/*
Объединение PR: Squash and merge
Минимум одобрений: 1
Тесты: обязательны
Прямой push в main: запрещён
Force push в main: запрещён
Force push в личную feature-ветку: разрешён через --force-with-lease
Релизные теги создаёт ответственный за выпускПолезные команды
| Команда | Назначение |
|---|---|
git fetch origin |
Получить изменения основного remote |
git fetch upstream |
Получить изменения исходного репозитория форка |
git merge branch |
Объединить ветку с текущей |
git merge --abort |
Отменить незавершённый merge |
git rebase main |
Перенести текущую ветку поверх main |
git rebase --continue |
Продолжить rebase после разрешения конфликта |
git rebase --abort |
Отменить rebase |
git rebase -i HEAD~N |
Отредактировать последние N коммитов |
git cherry-pick HASH |
Перенести выбранный коммит |
git cherry-pick --continue |
Продолжить cherry-pick |
git cherry-pick --abort |
Отменить cherry-pick |
git merge --squash branch |
Подготовить один итоговый коммит из ветки |
git push --force-with-lease |
Безопаснее принудительно обновить ветку |
git tag |
Показать теги |
git tag -a TAG -m "Message" |
Создать аннотированный тег |
git push origin TAG |
Отправить тег |
git remote add upstream URL |
Добавить исходный репозиторий форка |
git remote -v |
Показать удалённые репозитории |
git log --graph --oneline --all |
Показать граф истории |
Краткая памятка
Начать задачу:
git switch main
git pull
git switch -c feature/task-nameСохранить и отправить изменения:
git add .
git commit -m "Краткое описание изменения"
git push -u origin feature/task-nameОбновить рабочую ветку через merge:
git fetch origin
git merge origin/mainОбновить рабочую ветку через rebase:
git fetch origin
git rebase origin/main
git push --force-with-leaseРазрешить конфликт merge:
git status
# Исправить файлы
git add .
git commitРазрешить конфликт rebase:
git status
# Исправить файлы
git add .
git rebase --continueПеренести отдельный коммит:
git cherry-pick HASHОбъединить последние коммиты:
git rebase -i HEAD~NСоздать релизный тег:
git tag -a v1.0.0 -m "Release 1.0.0"
git push origin v1.0.0Настроить форк:
git remote add upstream URL_ИСХОДНОГО_РЕПОЗИТОРИЯ
git fetch upstreamГлавные правила безопасной командной работы:
Не переписывать общую историю без согласования.
Не использовать git push --force для защищённых веток.
Для собственной ветки предпочитать --force-with-lease.
Регулярно обновлять рабочую ветку.
Создавать небольшие Pull Request.
Проверять diff перед коммитом и перед review.
Запускать тесты после разрешения конфликтов.
Не перемещать опубликованные релизные теги.