Стоит следующая задача: мне надо создать хранилище, где будут разные файлы скриптов (например, A). Также будет хранилище, где будет стандартный набор файлов для начала программирования сайта (например, B). Когда я создаю новый проект — создается новое хранилище (например, C).
Теперь мне нужно в С перенести стандартный набор из хранилища В. Потом мне нужно из А перенести 2 скрипта в С. После этого я вижу, что в стандартных файлах (которые хранятся в В) есть ошибка. Я её исправляю и хочу залить как на В, так и на С. И так далее. То есть мне надо с ними 3-мя работать одновременно.
Уже пробовал git и svn, ничего не получилось. Решение через git submodule не подходит, т.к. общие файлы нужно редактировать в конкретных проектах, и при этом иметь возможность подтягивать изменения в этих же файлах из основного набора.
В какой системе контроля версий и каким образом можно организовать хранилища для решения этой задачи?
Ответ
Важно: если для вашего языка есть хорошая система управления зависимостями, то приведённое здесь решение лучше не использовать. Потому что если она есть, гораздо проще сделать из основы отдельную библиотеку и устанавливать её, как зависимость. В Node.js — NPM-пакет, в Ruby — gem, в PHP — пакет Composer, в Rust — crate, и т. д.
А то получится избыточность и могут добавиться хлопоты при обновлениях, которых можно избежать, изначально не используя систему контроля версий не по назначению.
git может такое.
Вообще у меня впечатление, что git может всё. Правда, механизм работы не слишком простой, нужно понимать, как он при этом будет работать.
Поскольку git по природе своей распределённый, я сэмулирую ваш порядок работы в одном локальном репозитории на нескольких несвязанных ветках: a, b и master. Изменения в этих ветках могут запросто появляться из других репозториев (разные ветки могут следить за разными серверами!), но при использовании такой методики у вас локально должен быть репозиторий, в котором есть все три.
Поехали по пунктам:
Положим, что git init вы сделали, а С (сам проект) лежит в ветке master (что совершенно необязательно).
создать хранилище, где будут разные файлы скриптов (например, A)
Делаем "несвязанную ветку":
git checkout --orphan a
Зачищаем папку и индекс, чтобы начать с чистого листа:
git reset && git clean -f
Делаем коммит с фигнёй:
echo 'скрипт' | tee script_a_1 script_a_2
git add .
git commit # Тут вас попросят ввести сообщение для коммита
хранилище, где будет стандартный набор файлов для начала программирования сайта (например, B)
То же самое.
git checkout --orphan b
git reset && git clean -f
echo 'скрипт' | tee script_b_1 script_b_2
git add .
git commit # Сообщение для коммита
Когда я создаю новый проект - создается новое хранилище (например, C).
Будем считать, что это ветка master. И в настоящий момент она должна быть пуста, для git это означает, что она не существует, поэтому придётся делать её заново:
git checkout --orphan master
git reset && git clean -f
Теперь мне нужно в С перенести стандартный набор с хранилища В.
Мёрдж:
git merge b
При этом произойдёт fast-forward до b, master будет совпадать с веткой b. Это нормально. Ведь на этом этапе состояния файловой системы проекта совпадают, верно?
Потом мне нужно с А перенести 2 скрипта в С.
Мёрдж с a, но на сей раз с "тормозами", чтобы прямо перед коммитом git остановился:
git merge --no-commit --no-ff a
Зачем? Затем, что вам не все файлы нужны. На этом этапе вы можете убрать из индекса ненужные вам файлы из индекса с помощью reset, зачистить оставшееся и закоммитить результат:
git reset script_a_2
git clean -f
git commit
Теперь немного "поработаем", для вида:
echo work > work
git add work
git commit
в стандартных файлах (которые хранятся в В) есть ошибка. Я ей исправляю и хочу залить как на В...
Поскольку у вас (семантически) master основан на b, а не наоборот, ошибку вам надо починить именно в b, чтобы потом изменения "растеклись" (не автоматически!) по тем, кто ею пользуется. Идём в ветку b и чиним:
git checkout b # clean уже не нужен, т. к. ветка не пустая
echo script > script_b_1 # Ну, допустим, что кириллица не переварилась. Мало ли.
git add script_b_1
git commit
На этом этапе, если репозитории с b и master всё-таки разные, должен быть git push ветки b в соответствующий репозиторий, а в репозитории проекта нужно сделать git pull --ff-only (--ff-only разрешает только перемотку ветки — чтобы ваши изменения не "затекли" в b) в ветке, которая за тем репозиторием следит. Это уже отдельная тема, если интересно, расскажу и об этом.
...так и на С.
Переходим в ветку с проектом:
git checkout master
И делаем мердж ветки b в проект.
git merge b
Готово. Да, вот так просто!
После проделывания вышеописанных манипуляций, я получил в master следующую схему из коммитов (git log --graph):
* commit 2e9219cb2922f70382a8f069fdc917bdbfccd4b8
|\ Merge: 2cc463a 1fc0b61
| | Author: Имя <адрес>
| | Date: Sun Dec 27 14:46:12 2015 +0300
| |
| | мердж фикса
| |
| * commit 1fc0b61c1017acf4b4ef1941e1cdcb01a7e86be4
| | Author: Имя <адрес>
| | Date: Sun Dec 27 14:41:23 2015 +0300
| |
| | фикс основы
| |
* | commit 2cc463ae97500bff4a304990aa4e42159da96fe9
| | Author: Имя <адрес>
| | Date: Sun Dec 27 14:38:37 2015 +0300
| |
| | работа
| |
* | commit cfa122c954f77b3282f51511f94bc6d97c95d569
|\ \ Merge: 7da066c f9304d8
| |/ Author: Имя <адрес>
|/| Date: Sun Dec 27 14:31:20 2015 +0300
| |
| | мердж с удалением лишних
| |
| * commit f9304d82d89600add270544bec32cd6661a8c150
| Author: Имя <адрес>
| Date: Sun Dec 27 13:46:39 2015 +0300
|
| скриптики
|
* commit 7da066c234216057ff19775a355342ed501fe9a4
Author: Имя <адрес>
Date: Sun Dec 27 13:54:01 2015 +0300
основа
И для наглядности, перерисовал:
Комментариев нет:
Отправить комментарий