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

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 и короткоживущие рабочие ветки.

Основные правила:

  1. ветка main всегда должна оставаться рабочей;
  2. новая задача выполняется в отдельной ветке;
  3. изменения отправляются на сервер;
  4. создаётся Pull Request;
  5. выполняются тесты и code review;
  6. после одобрения изменения объединяются с main;
  7. рабочая ветка удаляется.

Начало работы

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

Недостатки GitHub Flow


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

Стратегия особенно хорошо работает, если в проекте есть:

Преимущества trunk-based development

Недостатки trunk-based development


Сравнение стратегий

Характеристика GitFlow GitHub Flow Trunk-based
Основные постоянные ветки main, develop main main или trunk
Время жизни рабочих веток Среднее или длительное Короткое Очень короткое
Отдельная release-ветка Да Обычно нет Обычно нет
Отдельная hotfix-ветка Да Необязательно Необязательно
Частота интеграции Ниже Высокая Очень высокая
Сложность процесса Высокая Средняя Низкая по структуре, высокая по требованиям
Поддержка плановых релизов Хорошая Возможна Возможна через автоматизацию
Требования к CI Желательны Высокие Очень высокие

Общее практическое правило:

Редкие плановые релизы и несколько версий → GitFlow
Обычная разработка через Pull Request → GitHub Flow
Частая интеграция и зрелый CI/CD → trunk-based

Pull Request и Merge Request

Pull Request (PR) — запрос на объединение изменений одной ветки с другой на GitHub.

Merge Request (MR) — аналогичный механизм на GitLab.

Несмотря на различие названий, их основная задача одинакова:

Подготовка ветки

Перед началом новой задачи:

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 — не только поиск синтаксических ошибок. Проверяющий оценивает корректность решения, понятность кода, влияние на другие части проекта и наличие тестов.

Что проверяет автор перед отправкой

Автору полезно самостоятельно проверить:

Локальная проверка:

git status
git diff main...HEAD
git log --oneline main..HEAD

main...HEAD показывает изменения рабочей ветки относительно общего предка с main.

Что проверяет reviewer

При проверке обычно оцениваются:

Типы комментариев

Комментарии удобно разделять по важности:

blocker — без исправления объединять нельзя
suggestion — рекомендуемое улучшение
question — вопрос о выбранном решении
nit — небольшое необязательное замечание

Примеры:

Blocker: здесь возможен доступ к несуществующему элементу массива.
Suggestion: эту проверку можно вынести в отдельную функцию.
Question: почему используется последовательный запрос вместо параллельного?
Nit: можно выбрать более точное имя переменной.

Ответ автора

Автор может:

После исправлений:

git add .
git commit -m "Учтены замечания code review"
git push

Pull Request обновится автоматически.

Одобрение

После проверки reviewer может:

В репозитории могут быть настроены правила:


Способы объединения Pull Request

Платформы обычно предлагают три основных варианта:

Merge commit
Squash and merge
Rebase and merge

Merge 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 не может автоматически определить, как объединить изменения.

Типичный случай:

Конфликт также может появиться, если:


Конфликт при 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.


Порядок разрешения конфликтов

Практический порядок:

  1. выполнить git status;
  2. открыть каждый конфликтующий файл;
  3. найти маркеры конфликта;
  4. понять назначение обеих версий;
  5. сформировать правильный итоговый код;
  6. удалить маркеры;
  7. запустить тесты и сборку;
  8. добавить исправленные файлы через git add;
  9. завершить операцию;
  10. отправить изменения.

Команды:

git status
git diff
git add path/to/conflicted-file
git commit
git push

git 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

Если нужны изменения из обеих версий, файл придётся восстановить или объединить подходящим внешним инструментом.


Как уменьшить количество конфликтов

Полностью исключить конфликты нельзя, но их количество можно сократить.

Полезные правила:

Обновление рабочей ветки через merge:

git switch feature/profile
git fetch origin
git merge origin/main

Обновление через rebase:

git switch feature/profile
git fetch origin
git rebase origin/main

Merge и rebase

merge и rebase позволяют объединить изменения из разных линий разработки, но формируют разную историю.

Исходная история:

A──B──C  main
    \
     D──E  feature

Объединение через merge

Перейти в рабочую ветку и получить изменения main:

git switch feature
git merge main

Результат:

A──B──C────M  feature
    \      /
     D────E

M — merge-коммит.

Коммиты D и E не изменяются. Их идентификаторы сохраняются.

Преимущества merge

Недостатки merge


Перенос через rebase

Команда:

git switch feature
git rebase main

Git находит коммиты рабочей ветки и создаёт их заново поверх последнего коммита main.

Результат:

A──B──C──D'──E'  feature

Исходные D и E заменяются новыми коммитами D' и E'.

Преимущества rebase

Недостатки 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
Собственная рабочая ветка → допустим rebase

merge рекомендуется, если:

rebase удобен, если:

Не следует выполнять 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    feature

E' содержит те же изменения, но является новым коммитом с другим идентификатором.

Пример

Посмотреть историю:

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

Команда полезна, если:

Когда не использовать 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 Учтено замечание review

fixup добавляет изменения к предыдущему коммиту и удаляет собственное сообщение.

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.

Форк используется, если:

Схема:

Исходный репозиторий
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 push

merge безопаснее для общей ветки, а 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.


Командные правила

Перед началом работы команда должна договориться:

Пример соглашения:

Основная ветка: 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.
Запускать тесты после разрешения конфликтов.
Не перемещать опубликованные релизные теги.