Opanowanie złożoności projektu – saga¶
Zarządzanie wersjami środowiska deweloperskiego bez zanieczyszczania głównego repozytorium
W miarę rozwoju projektów, zwłaszcza baz wiedzy lub stron dokumentacyjnych wykorzystujących wiele narzędzi, takich jak MkDocs, Obsidian, niestandardowe skrypty i specjalistyczne IDE, jak Cursor, złożoność naturalnie rośnie. Integracja tych narzędzi tworzy potężne przepływy pracy, ale wprowadza również nowe wyzwanie: zarządzanie rosnącą liczbą plików konfiguracyjnych, wersji roboczych, skryptów i dokumentów planistycznych, które wspierają główny projekt.
Problem: Gdy .gitignore to za mało¶
Niedawno napotkałem bolesny kamień milowy, z którym styka się wielu programistów: utratę kilku godzin pracy. Przyczyna? Pliki kluczowe dla mojego przepływu pracy deweloperskiej nie były objęte kontrolą wersji.
Jak wielu, chciałem utrzymać moje publiczne repozytorium na GitHubie w czystości. W przypadku tego projektu oznaczało to zatwierdzanie tylko podstawowej zawartości Markdown i niezbędnych plików MkDocs do budowy strony internetowej. Wszystko inne – konfiguracja mojego sejfu Obsidian, ustawienia Cursor, robocze skrypty tłumaczeniowe, notatki z planowania zadań – było skrupulatnie wymienione w .gitignore. To utrzymywało główne repozytorium w porządku, ale pozostawiło moją kluczową infrastrukturę deweloperską bez ochrony.
Ten sygnał ostrzegawczy pojawił się na szczęście stosunkowo wcześnie. Podczas pracy nad integracją narzędzi tłumaczeniowych i planowaniem przepływu pracy za pomocą notatek w strukturze mojego projektu, niefortunny wypadek nadpisał znaczną część pracy planistycznej. Frustrujące, tak, ale cenna lekcja wyciągnięta, zanim stawka wzrosła.
Poszukiwanie rozwiązania: nieudane próby¶
Moje początkowe pomysły krążyły wokół sprytniejszego wykorzystania samego Gita, ale napotkałem przeszkody.
Próba 1: Zagnieżdżone repozytoria – koszmar przełączania gałęzi¶
Moją pierwszą myślą było zbadanie sposobów na posiadanie wielu historii Git w tym samym katalogu projektu, być może za pomocą zagnieżdżonych repozytoriów. Pomysł polegał na tym, aby repozytorium "dev" na najwyższym poziomie śledziło wszystko (ustawienia IDE, wersje robocze, pliki wewnętrznego repozytorium), podczas gdy wewnętrzne repozytorium "publiczne" zawierało tylko czyste, możliwe do wdrożenia pliki projektu. Zewnętrzne repozytorium ignorowałoby katalog .git wewnętrznego repozytorium.
Teoretycznie brzmiało to jak schludne, warstwowe podejście. Jednak kiedy faktycznie próbowałem to skonfigurować, bardzo szybko zdałem sobie sprawę, że to nie działa. Po pierwsze, Git tak naprawdę nie obsługuje zagnieżdżonych repozytoriów, przynajmniej nie w sposób, w jaki to sobie wyobrażałem. I ma to sens. Jest pewien haczyk, o którym nie pomyślałem: Załóżmy, że pracuję w wewnętrznym repozytorium (docs-nica) i przełączam się na inną gałąź. Teraz wszystkie pliki w tym folderze się zmieniają (aby odzwierciedlić gałąź) – ale zewnętrzne repozytorium (docs-nica-dev) nadal jest na swojej głównej gałęzi. Zewnętrzne repozytorium widzi teraz wszystkie te zmiany plików i myśli, że są to zmiany w jego głównej gałęzi... Jasno widać, dlaczego jest to problem. Okej, więc to podejście nie działało.
Próba 2: Oddzielne repozytoria + haki Git – katastrofa kopiowania¶
Z powrotem do deski kreślarskiej. Moim następnym pomysłem było posiadanie dwóch całkowicie oddzielnych repozytoriów. Jedno dev, które zawiera wszystko, czego potrzebuję (skrypty, notatki, konfiguracje, oraz podstawowe pliki projektu). I jedno public, które zawiera tylko zawartość Markdown i konfigurację MkDocs – tylko absolutne minimum, tak jak jest przeznaczone do wdrożenia.
Ale tu pojawia się haczyk: jeśli coś zmienimy w repozytorium public (może szybka poprawka bezpośrednio tam, lub pobranie zmian od współpracowników), skąd repozytorium dev ma o tym wiedzieć? I co częstsze, jak zmiany w dev odzwierciedlają się w public? Potrzebujemy jakiegoś sposobu, aby je połączyć.
Pierwszym pomysłem było użycie haków GitHub (lub lokalnych haków Git). Pozwalają one na definiowanie poleceń do uruchomienia po pewnych akcjach Git, takich jak zatwierdzenie. Skonfigurowałem hak, który po zatwierdzeniu w repozytorium dev po prostu kopiował odpowiednie pliki (folder docs/, mkdocs.yml itp.) do katalogu repozytorium public.
Na pierwszy rzut oka wydawało się, że działa, ale to podejście miało dwa główne problemy:
- Hałaśliwa historia: Hak kopiował wszystkie odpowiednie pliki przy każdym zatwierdzeniu. Oznaczało to, że repozytorium
publiczawsze myślało, że cała jego zawartość została zmieniona. Chociaż technicznie niczego nie psuło, historia zatwierdzeń stała się mniej użyteczna, pokazując setki (lub tysiące) zmienionych plików przy każdym zatwierdzeniu, co uniemożliwiało natychmiastowe zidentyfikowanie, które zawartości plików faktycznie się zmieniły. - Ślepota na usunięcia: Skrypt po prostu kopiował pliki. Jeśli usunąłem plik lub folder w repozytorium
dev, ta zmiana nie została odzwierciedlona w repozytoriumpublic. Stary plik po prostu tam pozostał.
Cholera, już spędziłem na tym godziny – i nadal brak działającego rozwiązania.
Przełom: Oddzielne repozytoria + synchronizacja plików¶
Wtedy przypomniałem sobie o oprogramowaniu open-source, które testowałem dawno temu do synchronizacji lokalnych folderów: FreeFileSync. Chociaż dodanie kolejnego zestawu narzędzi/oprogramowania do stosu jest niefortunne, faktycznie osiągnęło dokładnie to, czego chciałem.
Konfiguracja obejmuje teraz:
- Dwa oddzielne repozytoria Git:
docs-nica-dev(zawierające wszystko) idocs-nica(czysta, publiczna wersja). - FreeFileSync: Używane do definiowania reguł synchronizacji określonych folderów (takich jak
docs/, pliki motywów,mkdocs.yml) między lokalizacjami obu repozytoriów. Może obsługiwać synchronizację dwukierunkową, lustrzane odbicie i, co kluczowe, prawidłowe propagowanie usunięć. - RealTimeSync (część FreeFileSync): Używane do monitorowania zdefiniowanych folderów pod kątem zmian i automatycznego wyzwalania synchronizacji zgodnie z regułami FreeFileSync.
Ta kombinacja wreszcie skutecznie wypełnia lukę między dwoma repozytoriami. Zmiany wprowadzone w folderach z podstawową zawartością repozytorium dev są odzwierciedlane w repozytorium public, i odwrotnie, jeśli jest to potrzebne (chociaż mój główny przepływ to dev -> public). Usunięcia są obsługiwane poprawnie, a ponieważ synchronizuje tylko zmienione pliki, historia zatwierdzeń w repozytorium public dokładnie odzwierciedla rzeczywiste modyfikacje.
Pozostały haczyk: czas synchronizacji vs. czas zatwierdzenia¶
Jest jednak jeszcze jedna wada. Kiedy zmieniam plik w repozytorium dev, a RealTimeSync działa, te zmiany są synchronizowane do katalogu repozytorium public natychmiast, nawet jeśli nie zostały jeszcze zatwierdzone w repozytorium dev. Rozwiązanie synchronizacji jest odseparowane od Git.
To nie jest wielki problem, ale wymaga nieco większej ostrożności przy faktycznym zatwierdzaniu i wypychaniu zmian. Zasadniczo, kiedy pracuję w repozytorium dev, muszę upewnić się, że zatwierdzę tam wszystko zanim przełączę się na repozytorium public, aby zatwierdzić i wypchnąć. Wzmacnia to również nawyk rzeczywistego przeglądania zmian przygotowanych do zatwierdzenia w repozytorium public przed faktycznym zatwierdzeniem i wypchnięciem, tylko po to, aby upewnić się, że stan jest dokładnie taki, jaki zamierzam.
Dla kogo to jest? (Ważne wyjaśnienie)¶
Chwileczkę, zanim pomyślisz, że cała ta konfiguracja jest obowiązkowa tylko po to, aby korzystać z wiki, pozwól, że wyjaśnię. Cała ta złożoność? Nie jest potrzebna, jeśli chcesz po prostu pracować z podstawową zawartością. Główny punkt wejścia jest nadal super prosty: sklonuj publiczne repozytorium docs-nica (które zawiera tylko pliki Markdown i konfigurację MkDocs) i używaj dowolnych narzędzi, które Ty preferujesz. To wszystko.
Więc dlaczego przeszedłem przez to wszystko? Ta dość skomplikowana konfiguracja deweloperska służy mi dwóm głównym celom:
- Moja osobista siatka bezpieczeństwa: Jest to kluczowa kontrola wersji dla wszystkich moich elementów deweloperskich – konfiguracji, niedokończonych skryptów, notatek planistycznych – rzeczy, których nie mogę sobie pozwolić stracić ponownie.
- Udostępnianie mojego dokładnego przepływu pracy (opcjonalnie): Jeśli ktoś chce odtworzyć moje specyficzne środowisko, może sklonować repozytorium
docs-nica-dev. Otrzyma pełną konfigurację Obsidian (wtyczki, ustawienia, zakładki, wyszukiwania, wszystko!), potencjalnie ustawienia Cursor i wszelkie inne zintegrowane narzędzia, które skonfigurowałem. Jest to sposób na udostępnienie gotowej konfiguracji bazowej.
Ale podstawowa idea się nie zmieniła: zdecydowanie możesz pobrać tylko publiczne repozytorium i zbudować wokół niego własny przepływ pracy z ulubionymi narzędziami. Ten skomplikowany taniec dotyczy zarządzania moim chaosem deweloperskim i oferowania planu dla tych, którzy go chcą.
Wniosek: wypracowane rozwiązanie¶
Ogólnie jestem zadowolony, że znalazłem rozwiązanie problemu teraz – nawet jeśli kosztowało mnie to około dwa dni prób, błędów i frustracji. Ale poprawne ustalenie tego przepływu pracy było kluczowe, aby uniknąć dalszych problemów w przyszłości, zapewniając zarówno czyste repozytorium publiczne, jak i w pełni kontrolowane wersjami środowisko deweloperskie.
Czy ta konfiguracja jest idealna? Wymaga zarządzania dwoma repozytoriami i zewnętrznym narzędziem synchronizacji, plus świadomego przepływu pracy do zatwierdzania. Jednak bezpośrednio rozwiązuje krytyczny problem wersjonowania wszystkiego, co jest niezbędne do złożonego procesu deweloperskiego, bez kompromisów w zakresie czystości głównego repozytorium projektu ani walki z ograniczeniami Git w przypadku zagnieżdżonych struktur. W przypadku projektów, które przerastają proste strategie .gitignore, to podejście oferuje pragmatyczną ścieżkę naprzód, zapewniając bezpieczeństwo i strukturę dla nieuniknionej, nieuporządkowanej rzeczywistości pracy deweloperskiej.