Приборка складності проєкту — Сага¶
Версіонування середовища розробки без засмічення основного репозиторію
З розвитком проєктів, особливо баз знань чи сайтів документації, що використовують кілька інструментів, таких як MkDocs, Obsidian, власні скрипти та спеціалізовані IDE, як-от Cursor, складність природно зростає. Інтеграція цих інструментів створює потужні робочі процеси, але також ставить нове завдання: керування зростаючою кількістю конфігураційних файлів, чернеток, скриптів та планів, що підтримують основний проєкт.
Проблема: коли .gitignore недостатньо¶
Нещодавно я досяг болісної позначки, з якою стикаються багато розробників: втрата кількох годин роботи. Винуватець? Файли, критично важливі для мого робочого процесу розробки, не були під контролем версій.
Як і багато хто, я хотів зберегти свій публічний репозиторій на GitHub чистим. Для цього проєкту це означало комітити лише основний контент Markdown та необхідні файли MkDocs для збірки вебсайту. Усе інше – конфігурація мого сховища Obsidian, налаштування Cursor, чернетки скриптів перекладу, нотатки з планування завдань – було старанно перелічено в .gitignore. Це зберігало основний репозиторій охайним, але залишало мою життєво важливу інфраструктуру розробки незахищеною.
Цей тривожний дзвіночок пролунав, на щастя, відносно рано. Під час роботи над інтеграцією інструментів перекладу та планування робочого процесу за допомогою нотаток у структурі проєкту, нещасний випадок перезаписав значну частину роботи з планування. Це було розчаруванням, але цінним уроком, засвоєним до того, як ставки стали вищими.
Пошук рішення: невдалі спроби¶
Мої початкові ідеї оберталися навколо більш хитрого використання самого Git, але я натрапив на перешкоди.
Спроба 1: Вкладені репозиторії — жах перемикання гілок¶
Першою думкою було дослідити способи мати кілька історій Git в одній директорії проєкту, можливо, використовуючи вкладені репозиторії. Ідея полягала в тому, щоб мати "dev" репозиторій верхнього рівня, який відстежує усе (налаштування IDE, чернетки, файли внутрішнього репозиторію), тоді як внутрішній "public" репозиторій містив лише чисті, готові до розгортання файли проєкту. Зовнішній репозиторій ігнорував би директорію .git внутрішнього репозиторію.
Теоретично, це виглядало як акуратний багатошаровий підхід. Однак, коли я спробував це налаштувати, я дуже швидко зрозумів, що це не працює. По-перше, Git насправді не підтримує вкладені репозиторії, принаймні не так, як я це уявляв. І це має сенс. Є застереження, про яке я не подумав: припустимо, я працюю у внутрішньому репозиторії (docs-nica) і перемикаюся на іншу гілку. Тепер усі файли в цій папці змінюються (щоб відобразити гілку), але зовнішній репозиторій (docs-nica-dev) залишається на своїй основній гілці. Зовнішній репозиторій тепер бачить усі ці зміни файлів і вважає, що це зміни до його основної гілки... Чітко видно, чому це проблема. Гаразд, цей підхід не спрацював.
Спроба 2: Окремі репозиторії + Git-хуки — катастрофа копіювання¶
Назад до креслярської дошки. Наступною ідеєю було мати два повністю окремі репозиторії. "Dev" репозиторій, який містить усе, що мені потрібно (скрипти, нотатки, конфігурації, а також основні файли проєкту). І "public" репозиторій, який містить лише контент Markdown та налаштування MkDocs – лише голі основи, так, як це призначено для розгортання.
Але тут виникає проблема: якщо ми щось змінюємо в "public" репозиторії (можливо, швидке виправлення безпосередньо там, або отримання змін від співавторів), як "dev" репозиторій дізнається про це? І, що більш поширено, як зміни в "dev" відображаються в "public"? Нам потрібен якийсь спосіб їх зв'язати.
Першою ідеєю було використання GitHub-хуків (або локальних Git-хуків). Вони дозволяють визначати команди для виконання після певних дій Git, як-от коміт. Я налаштував хук, який після коміту в "dev" репозиторії просто копіював би відповідні файли (папку docs/, mkdocs.yml тощо) до директорії "public" репозиторію.
На перший погляд це здавалося працюючим, але цей підхід мав дві основні проблеми:
- Засмічена історія: Хук копіював усі відповідні файли при кожному коміті. Це означало, що "public" репозиторій завжди вважав, що весь його контент змінився. Хоча технічно це нічого не ламало, історія комітів ставала менш корисною, показуючи сотні (або тисячі) змінених файлів у кожному коміті, що робило неможливим миттєве визначення того, які зміни вмісту файлів насправді відбулися.
- Сліпота до видалень: Скрипт просто копіював файли. Якщо я видаляв файл або папку в "dev" репозиторії, ця зміна не відображалася б у "public" репозиторії. Старий файл просто залишався б там.
Чорт забирай, я вже витратив години на це – і все ще немає робочого рішення.
Прорив: окремі репозиторії + синхронізація файлів¶
Потім я згадав про програмне забезпечення з відкритим кодом, яке я тестував давно для синхронізації локальних папок: FreeFileSync. Хоча шкода додавати ще один набір інструментів/програм до стеку, це фактично досягло саме того, чого я хотів.
Налаштування тепер включає:
- Два окремі Git-репозиторії:
docs-nica-dev(що містить усе) таdocs-nica(чиста, публічна версія). - FreeFileSync: Використовується для визначення правил синхронізації конкретних папок (як-от
docs/, файли теми,mkdocs.yml) між двома розташуваннями репозиторіїв. Він може обробляти двосторонню синхронізацію, дзеркалювання та, що найважливіше, коректно поширювати видалення. - RealTimeSync (частина FreeFileSync): Використовується для моніторингу визначених папок на наявність змін та автоматичного запуску синхронізації на основі правил FreeFileSync.
Ця комбінація нарешті ефективно долає розрив між двома репозиторіями. Зміни, внесені в основні папки контенту "dev" репозиторію, дзеркалюються до "public" репозиторію, і навпаки, якщо потрібно (хоча мій основний потік – dev -> public). Видалення обробляються коректно, і оскільки він синхронізує лише змінені файли, історія комітів у "public" репозиторії точно відображає фактичні модифікації.
Залишковий недолік: час синхронізації проти часу коміту¶
Однак, є ще один мінус. Коли я зміню файл у "dev" репозиторії, і RealTimeSync працює, ці зміни синхронізуються до директорії "public" репозиторію негайно, навіть якщо вони ще не за комитетані в "dev" репозиторії. Рішення для синхронізації відокремлене від Git.
Це не надто велика проблема, але вона вимагає трохи більшої обережності під час фактичного комітування та надсилання змін. По суті, коли я працюю з "dev" репозиторієм, мені потрібно переконатися, що я за комитетав усе там перед тим, як переключити увагу на "public" репозиторій для комітування та надсилання. Крім того, це зміцнює звичку дійсно переглядати зміни, підготовлені до коміту в "public" репозиторії, перш ніж фактично комітувати та надсилати, просто щоб переконатися, що стан саме такий, який я маю на увазі.
Для кого це? (Важливе уточнення)¶
Зачекайте, перш ніж ви подумаєте, що все це налаштування є обов'язковим лише для використання вікі, дозвольте мені уточнити. Уся ця складність? Вона не потрібна, якщо ви просто хочете працювати з основним контентом. Основний вхідний пункт залишається надзвичайно простим: клонуйте публічний репозиторій docs-nica (який містить лише файли Markdown та налаштування MkDocs) і використовуйте будь-які інструменти, які ви віддаєте перевагу. Ось і все.
Тож, чому я пройшов через усі ці труднощі? Це досить складне налаштування розробки служить двом основним цілям для мене:
- Мій особистий захисний сітка: Це критичний контроль версій для усіх моїх розробницьких дрібниць – конфігурацій, напівзавершених скриптів, нотаток з планування – речей, які я не можу дозволити собі втратити знову.
- Обмін моїм точним робочим процесом (опціонально): Якщо хтось хоче відтворити моє конкретне середовище, він може клонувати репозиторій
docs-nica-dev. Він отримає моє повне налаштування Obsidian (плагіни, налаштування, закладки, пошук, усе!), потенційно налаштування Cursor та будь-які інші інтегровані інструменти, які я налаштував. Це спосіб поділитися готовим базовим налаштуванням.
Але фундаментальна ідея не змінилася: ви абсолютно можете взяти лише публічний репозиторій і побудувати навколо нього власний робочий процес за допомогою улюблених інструментів. Цей складний танець стосується керування моїм хаосом розробки та пропонує план для тих, хто його хоче.
Висновок: важко здобуте рішення¶
Загалом, я радий, що знайшов рішення проблеми зараз – навіть якщо це коштувало мені приблизно два дні спроб, помилок та розчарувань. Але правильне налаштування цього робочого процесу було критично важливим для уникнення подальших проблем у майбутньому, забезпечуючи як чистий публічний репозиторій, так і повністю контрольоване середовище розробки.
Чи є це налаштування ідеальним? Воно вимагає керування двома репозиторіями та зовнішнім інструментом синхронізації, плюс свідомий робочий процес для комітування. Однак, воно безпосередньо вирішує критичну проблему версіонування усього, необхідного для складного процесу розробки, не компрометуючи чистоту основного репозиторію проєкту або не борючись з обмеженнями Git щодо вкладених структур. Для проєктів, які переростають прості стратегії .gitignore, цей підхід пропонує прагматичний шлях вперед, забезпечуючи безпеку та структуру для неминучої, брудної реальності роботи з розробки.