Проблема разработки с общим CommonUI
Освежим общий процесс разработки.
- Создаем задачу в Projects на GitHub
- Зная номер задачи создаем ветку feature/X, где X - номер задачи
- Разрабатываем, делая N комитов
- Когда задача завершена - делаем pull request
- Жмем кнопку и сливаем эти изменения в master.
Данная схема имеет смысл только когда напрямую в master комитить нельзя. Так у нас и настроено, чтобы этот flow нельзя было обойти.
Разработка фичи происходит какое-то время - несколько дней, неделю. И как можно заключить из вышеуказанного алгоритма разработки - pull request делается в общем один раз на фичу. Т.е. мы фичу разрабатываем в изоляции от master
ветки.
Что делать, если кто-то залил свои изменения в master
? Казалось бы залил и залил. Но при pull request возникнет ошибка, и git заставит сначала выкачать новые изменения из master
. Поэтому рекомендуется как можно чаще обновлять свою фича ветку из мастера, это избавит от проблем при pull request.
Здесь видим, что master появились чужие изменения. Поэтому чтобы привести свою фича ветку develop
в актуальное состояние выполняем команду:
1
2
$ git checkout master
$ git rebase develop master
После чего все встает на свои места:
Проблема обмена изменениями в Common модулях
Опишем следующую проблему в разработке. Допустим два разработчика разрабатывают 2 разные фичи и их изменения не пересекаются. Но пересечения все-таки скорее всего произойдут в общим модулях, таких как - Common или CommonUI. Иными словами, когда я разрабатываю экран, возможно я создам какой-то красивый UI элемент, который все могут переиспользовать. Но они не смогут им воспользоваться, пока разработчик не закончит разработку всей фичи и не зальет ее в master. А это, как уже говорилось, может произойти через несколько дней, а то и через неделю.
Как можно решить эту проблему ? Первый способ который напрашивается - вынести изменения в CommonUI и Common как отдельные задачи. Тогда и pull request по ним будет оправдан. Но все же, как я считаю, это плохой вариант, мы никогда не знаем когда захотим поправить common компонент, т.е. эти изменения сложно спланировать. И если делать на каждый небольшой чих pull request - это приведет к замедлению разработки и большому количеству лишних действий.
Другой способ, как я считаю, более оптимальный - иметь отдельную ветки для common и commonUI через которые фича ветки будут обмениваться последними изменениями в commonUI не прибегая к ветке master.
Посмотрим на примере. Создадим фейковый проект, с простой структурой папок.
1
2
3
4
5
6
7
8
.
├── Common
│ └── SomeCode.swift
├── Feature1
│ └── Feature1Source.swift
├── Feature2
│ └── Feature2Source.swift
└── Read.ME
Допустим я нахожусь в ветке feature/1
и произвел изменения в файлах Feature1Source.swift
и SomeCode.swift
. Т.е. Часть изменения касается непосредственно моей фичи, а другая общего модуля Common
.
Теперь я хочу чтобы мои изменения в Common
были доступны другим разработчикам, но саму фичу я еще продолжаю разрабатывать и не хочу еще делать pull request. Для этого я делаю комит своих изменений в Common
. Здесь очень ВАЖНО! сделать кормит только изменения в папке Common
.
Проэмулируем работу с файлами через консоль:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# изменения в файле Feature1/Feature1Source.swift
$ echo "some feature1 code" >> Feature1/Feature1Source.swift
# изменения в файле SomeCode.swift
$ echo "some common code" >> Common/SomeCode.swift
# убедиться что в файлах изменения добавились можно командой
$ cat Feature1/Feature1Source.swift
# в результате выведется:
some feature1 code
Далее делаем кормит изменений только в папке Common
1
2
3
4
5
6
7
8
$ git add -- ./Common
$ git commit -m 'My changes to Common' -- ./Common
# в результате выведется:
[feature/1 (root-commit) 4e1d4b0] My changes to Common
1 file changed, 1 insertion(+)
create mode 100644 Common/SomeCode.swift
Отлично, мы видим что в комит попали только изменения SomeCode.swift
, что нам и нужно было.
Далее необходимо закомитить все остальные изменения по фиче:
1
2
$ git add .
$ git commit -m “Feature 1 changes”
Ура! Все наши изменения закомичены.
Далее необходимо сделать небольшое отступление и объяснить что такое cherry pick.
Cherry pick
Если простыми словами - cherry pick это способность взять отдельный комит и скопировать его в другую ветку. А это как раз то, что нам нужно - взять изменения модуля Common
и перенести их в общую ветку для обмена ими в обход master
ветки.
Посмотрим как работает cherry-pick схематично. Допустим у нас есть две ветки:
1
2
3
a - b - c - d Main
\
e - f - g Feature
И мы хотим кормит f перенести в ветку Main
. Тогда выполняем две команды
1
2
$ git checkout main
$ git cherry-pick f
В результате получаем следующую картину:
1
2
3
a - b - c - d - f Main
\
e - f - g Feature
Применение cherry pick на практике.
Сольём только Common
изменения в ветку common
.
Вернемся к нашему проекту. Первое что нам нужно - это узнать sha код комита, который мы сделали из папки Common. Для этого выполняем команду:
1
$ git log
Получаем приблизительно такой результат:
1
2
3
4
5
6
7
8
9
10
11
12
commit abae47d4524651fea4c08bf47393963a0a1dde47 (HEAD -> feature/1)
Author: Sergio <afirthes@gmail.com>
Date: Wed Sep 14 21:17:23 2022 +0300
Feature 1 changes
commit 4e1d4b0a91cea71aaac23839db4443133c20ab5a (common)
Author: Sergio <afirthes@gmail.com>
Date: Wed Sep 14 21:01:01 2022 +0300
My changes to Common
Там может быть много записей, нас интересует именно наш комит по Common
. Для его поиска можно ориентироваться на ветку feature/1
и комментарий комита.
Далее запоминаем sha комита - 4e1d4b0a91cea71aaac23839db4443133c20ab5a
. На самом деле достаточно запомнить первые несколько символов, вероятность что они повторяются довольно мала.
И делаем следующее:
1
2
$ git checkout common
$ git cherry-pick 4e1d4b0
Если все прошло успешно - с помощью git log
- мы увидем в списке наш коммит с соотвествующим кодом. Задача выполнена - мы слили в ветку common
все изменения касающиеся папки Common
, а все другие изменения оставили в feature/1
ветке.
Осталось только разобраться как забирать в свою фича ветку изменения из common ветки.
Подтягивание в свою ветку изменений из common.
Итак, допустим я разрабатываю фичу 2
в ветке feature/2
и мне нужно подгрузиь изменения из common
. Тогда делаю просто:
1
2
$ git checkout feature/2
$ git rebase feature/2 common
Всё. Мы подтянули изменения в папке Common из ветки feature/1
в ветку feature/2
, используя промежуточную ветку common. Теперь я могу использовать общие компоненты своего коллеги, даже несмотря на то, что их пока нет в master
.
Не забываем что ветки нужно как можно чаще push-ить на сервер.
Примерно схему такой работы можно показать так: