Как организовать работу с системами контроля версий для разработки нескольких проектов с общей основой?
1,00
р.
р.
Стоит следующая задача: мне надо создать хранилище, где будут разные файлы скриптов (например, 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 основа И для наглядности, перерисовал: