Repozytorium przekazane w minutę, domena zablokowana na 60 dni. Trzy warstwy projektu, nie jedna
Transfer repozytorium i projektu na platformie to jedna warstwa z czterech. Co nie jedzie z kodem: zmienne z vercel.json, domena główna i 60 dni blokady.
Transfer repozytorium na GitHubie kończy się w kilka sekund i nic po nim nie pęka: wszystkie linki do starej lokalizacji są automatycznie przekierowywane na nową, historia commitów zostaje nietknięta. Dzień później klient pisze, że nie wchodzi w ustawienia strony. Deploy nadal leci z konta wykonawcy, zmienna z kluczem do API płatności jest w panelu, do którego klient nie ma dostępu, a w whois domeny jako abonent widnieje agencja.
Kod to najmniejsza i najłatwiejsza do przeniesienia część projektu. Pozostałe warstwy mają osobnych właścicieli, osobne procedury i — w przeciwieństwie do repozytorium — terminy, których nie da się skrócić.
Repozytorium, platforma, rejestrator: trzy właściciele, trzy procedury
Projekt strony oddanej klientowi stoi na czterech grupach zasobów i tylko pierwsza jedzie razem z kodem:
- Repozytorium — kod, historia, workflowy CI, sekrety Actions, klucze deploy, webhooki.
- Platforma — projekt na Vercelu, Netlify albo własnym serwerze: zmienne środowiskowe wpisane w panelu, podpięcie repozytorium, cron, integracje, logi.
- Rejestrator domeny — abonent w whois, kod autoryzacyjny, strefa DNS, blokady transferu.
- Usługi zewnętrzne — konto analityczne, dostawca poczty transakcyjnej, bramka płatności, klucze API, konto w CDN-ie.
Przekazanie, które obejmuje tylko pierwszy punkt, wygląda na zakończone i nie jest. Klient ma kod, którego nie umie wdrożyć, pod domeną, której nie kontroluje. Poniżej trzy pierwsze warstwy po kolei, z dokumentacją w ręku.
GitHub przenosi sekrety, ale nazwę repozytorium potrafi wycofać na zawsze
Transfer repozytorium przenosi więcej, niż się zwykle zakłada. Razem z kodem jadą issues, pull requesty, wiki, gwiazdki i obserwujący, a jeśli repozytorium korzysta z Git LFS, obiekty LFS są przenoszone automatycznie. Webhooki, usługi, sekrety i klucze deploy, jak podaje dokumentacja, „pozostają powiązane po zakończeniu transferu”. Do przeprowadzenia operacji potrzebujesz uprawnień administratora repozytorium, a konto docelowe nie może mieć repozytorium o tej samej nazwie ani forka w tej samej sieci.
Trzy rzeczy w tej samej dokumentacji są nieodwracalne albo kosztowne i warto je sprawdzić przed, nie po:
Wycofanie pary właściciel/nazwa
Jeśli repozytorium zawiera akcję wystawioną na GitHub Marketplace albo miało w tygodniu poprzedzającym transfer ponad 100 klonów lub ponad 100 uruchomień GitHub Actions, GitHub trwale wycofuje kombinację nazwy właściciela i nazwy repozytorium. Starego adresu nie użyjesz powtórnie — ani Ty, ani klient. Dla projektu klienckiego z aktywnym CI próg stu uruchomień tygodniowo jest realny: cztery pushe dziennie przy trzech workflowach to już 84.
Liczby da się zmierzyć przed transferem. Endpoint ruchu zwraca dane z ostatnich 14 dni i wymaga uprawnień zapisu, więc trzeba zsumować siedem ostatnich dni:
# klony dzień po dniu, suma siedmiu ostatnich
gh api repos/KLIENT/strona/traffic/clones --jq \
'[.clones[-7:][].count] | add'
# uruchomienia Actions od zadanej daty
gh api -X GET repos/KLIENT/strona/actions/runs \
-f created='>=2026-10-15' --jq '.total_count'
Jeśli pierwsza komenda zwraca 143, a druga 210, nazwa zostanie wycofana i nie ma sensu obiecywać klientowi, że „w razie czego wrócimy do starego adresu”.
Przekierowania, które sam sobie usuniesz
Przekierowania ze starego adresu działają dopóty, dopóki nikt nie utworzy w starej lokalizacji nowego repozytorium albo forka — wtedy, zgodnie z dokumentacją, przekierowania do przeniesionego repozytorium są trwale usuwane. Odruch „zrobię sobie kopię pod starą nazwą, na wypadek gdyby” kasuje działające przekierowania klienta. Lokalne klony i tak trzeba przepiąć na nowy adres, bo dokumentacja zaleca to wprost.
Prywatne repozytorium na koncie darmowym
Prywatne repozytorium przeniesione na konto albo do organizacji w planie GitHub Free traci dostęp do funkcji takich jak chronione gałęzie i GitHub Pages. Jeśli proces odbioru klienta zakłada, że na main nie da się wypchnąć bez review, po transferze to zabezpieczenie przestaje istnieć. Osobno: GitHub nie przekierowuje stron GitHub Pages powiązanych z repozytorium, a przy przejściu z organizacji na konto osobiste współpracownicy z prawami tylko do odczytu nie są przenoszeni.
Vercel kopiuje zmienne z panelu i pomija te z vercel.json
Transfer projektu między zespołami na Vercelu obejmuje wdrożenia, konfigurację projektu, domeny i aliasy, buildy, podpięcie repozytorium, ustawienia bezpieczeństwa, cron joby, Web Analytics i Speed Insights. Zmienne środowiskowe są kopiowane do zespołu docelowego z jednym wyjątkiem: poza tymi zdefiniowanymi w sekcjach env i build.env pliku vercel.json. Te trzeba przenieść do zmiennych w ustawieniach projektu albo skonfigurować ponownie po transferze.
Dlatego pierwszym krokiem jest zestawienie dwóch list i porównanie ich ze sobą:
# zmienne, które transfer skopiuje
vercel env ls production
# zmienne, które transfer pominie
grep -nE '"(env|build)"' vercel.json
Jeśli druga komenda zwraca cokolwiek, build po transferze przejdzie, a aplikacja wywali się w runtime na pierwszym żądaniu do zewnętrznego API. Ta sama dokumentacja wymienia dalej, czego transfer nie obejmuje: integracje trzeba dodać ponownie, Global Configs i Vercel Blob mają osobny mechanizm przenoszenia, dane Monitoringu, logi runtime i build oraz własne log drainy nie są przenoszone, a użycie jest zerowane. Sekcja Active Branches w nowym projekcie będzie pusta. Secure Compute i statyczne IP trzeba odłączyć przed transferem i skonfigurować na nowo w zespole docelowym.
Dwa warunki organizacyjne łatwo przeoczyć w kalendarzu. Musisz być właścicielem zespołu, z którego przenosisz, i członkiem zespołu, do którego przenosisz — czyli klient musi Cię najpierw zaprosić. Zespół docelowy musi mieć poprawną metodę płatności, inaczej usługa zostanie przerwana. Sam transfer trwa od 10 sekund do 10 minut, a w tym czasie nie można tworzyć nowych wdrożeń, edytować ustawień projektu ani go usunąć.
Subdomena jedzie, domena główna zostaje na koncie wykonawcy
To jest pułapka, która po cichu zostawia kontrolę po stronie agencji. Zachowanie zależy od tego, jakiej domeny używa projekt:
- projekt na
example.com— domena jest przenoszona do zespołu docelowego, który staje się jej głównym właścicielem i jest za nią rozliczany, jeśli była kupiona przez Vercela; - projekt na
blog.example.com— subdomena jest delegowana do zespołu docelowego, ale domena głównaexample.comzostaje w zespole źródłowym, który pozostaje jej głównym właścicielem; - projekt na domenie wieloznacznej
*.example.com— tak samo: wildcard delegowany, korzeń zostaje.
Klient, który odebrał projekt stojący na subdomenie, ma delegację, nie własność. Wykonawca dalej odpowiada za rozliczenie domeny głównej i dalej może zmienić jej konfigurację. Jeśli domena w ogóle nie była kupiona przez platformę, warstwa platformy nie ma tu nic do powiedzenia i rozstrzyga rejestrator.
Change of Registrant włącza blokadę na 60 dni, z której rezygnuje się przed zmianą
Przy domenach gTLD obowiązuje Transfer Policy ICANN i ona ustawia terminy, nie rejestrator i nie umowa z klientem. Istotne są cztery zapisy. Rejestrator może odmówić transferu zgłoszonego w ciągu 60 dni od daty utworzenia domeny widocznej w rekordzie whois rejestru (I.A.3.7.5) oraz w ciągu 60 dni od poprzedniego transferu (I.A.3.7.6). Po zmianie abonenta rejestrator musi nałożyć 60-dniową blokadę transferu między rejestratorami (II.C.2), choć może pozwolić abonentowi zrezygnować z niej — i jeśli abonent tego nie zrobił wcześniej, odmowa transferu jest obowiązkowa (I.A.3.8.5).
Kolejność zdarzeń decyduje więc o tym, czy klient czeka dwa miesiące. Zmiana abonenta u tego samego rejestratora bez wcześniejszej rezygnacji z blokady zamyka drogę do przeniesienia domeny do rejestratora klienta na 60 dni. Odwrotna kolejność — najpierw transfer między rejestratorami, potem zmiana abonenta — też uruchamia blokadę, tylko na kolejny transfer, który zwykle nie jest już potrzebny.
Polityka daje przy tym abonentowi twarde uprawnienia: rejestrator musi przekazać mu unikalny kod „AuthInfo” (I.A.5.2), unikalny per domena (I.A.5.5), i nie może odmówić zdjęcia statusu clientTransferProhibited ani wydania kodu (I.A.5.4). Status sprawdzisz sam, bez pytania kogokolwiek — kody statusu domeny widać w zapytaniu whois, a clientTransferProhibited każe rejestrowi odrzucać żądania transferu:
whois example.com | grep -iE 'status|creat|expir|registrant'
# clientTransferProhibited -> transfer wychodzący zablokowany
# Creation Date mniej niż 60 dni temu -> transfer może zostać odrzucony
Przy domenach krajowych, w tym .pl, ta polityka nie obowiązuje i terminy ustala rejestr krajowy — sprawdź regulamin swojego rejestratora, zamiast zakładać te same 60 dni.
Przeniesiony sekret to nie zrotowany sekret
Zdanie z dokumentacji GitHuba o sekretach, które „pozostają powiązane po zakończeniu transferu”, czyta się jak dobra wiadomość i jest problemem. Działające po transferze sekrety to te same sekrety, które widział i których używał zespół wykonawcy. Do tego po transferze pierwotny właściciel zostaje dodany jako współpracownik repozytorium, a dotychczasowi współpracownicy zostają na swoich miejscach. Z punktu widzenia klienta odbiór kończy się tym, że agencja ma commit access i ważne tokeny.
Rotacja po stronie klienta, nie wykonawcy, obejmuje kolejno: tokeny i klucze API we wszystkich usługach zewnętrznych, sekrety i zmienne Actions, klucze deploy, hasła do baz, webhooki wskazujące na endpointy wykonawcy, instalacje aplikacji GitHub i integracje OAuth, a na końcu listę współpracowników. Przy okazji warto sprawdzić, czy token, który dostał klient, nie ma uprawnień szerszych niż potrzebne do jednego zadania — to ten sam błąd projektowy, który opisuje tekst o tym, jak agent sięgający do CRM przez MCP widzi za dużo danych.
Osobna rzecz: skan historii repozytorium. Jeśli w którymś commicie wylądował plik .env, usunięcie go z HEAD niczego nie zmienia — sekret zostaje w historii, która właśnie przeszła na konto klienta razem z commitami. Skaner sekretów przepuszczony po całej historii przed transferem jest tańszy niż rotacja wszystkiego po fakcie.
Protokół odbioru: tabela właścicieli i jedna data
Zestawienie poniżej zbiera to, co transfer robi sam, i to, co zostaje do zrobienia ręcznie. Tabela jest jednocześnie listą pozycji protokołu odbioru — każdy wiersz ma mieć właściciela i datę.
| Zasób | Co robi transfer | Co zostaje ręcznie | Jak sprawdzić |
|---|---|---|---|
| Repozytorium | issues, PR-y, wiki, gwiazdki, obserwujący, LFS, przekierowania starych adresów | przepięcie lokalnych klonów, usunięcie pierwotnego właściciela ze współpracowników | git remote -v, lista współpracowników |
| Nazwa repozytorium | może zostać trwale wycofana powyżej 100 klonów lub 100 uruchomień Actions w tygodniu | decyzja przed transferem, po nim nieodwracalna | endpoint traffic/clones, licznik runów |
| Sekrety i klucze deploy | pozostają powiązane i działają | rotacja wszystkiego po stronie klienta | gh secret list, lista kluczy deploy |
| Zmienne środowiskowe | kopiowane z panelu | zmienne z env i build.env w vercel.json |
vercel env ls plus grep w vercel.json |
| Integracje, logi, Blob | nie są przenoszone, użycie zerowane | dodanie integracji na nowo, osobny transfer store’ów | lista integracji w zespole docelowym |
| Domena główna | przenoszona, gdy projekt używa jej bezpośrednio | przy subdomenie korzeń zostaje u wykonawcy | panel domen, whois |
| Abonent domeny | nic — to osobny proces u rejestratora | zmiana abonenta, kod AuthInfo, rezygnacja z blokady 60 dni przed zmianą | whois: status i daty |
| Chronione gałęzie | znikają przy przejściu prywatnego repo na plan Free | plan konta docelowego ustalony przed transferem | ustawienia gałęzi po transferze |
Kolejność też ma znaczenie i wynika z zależności, nie z wygody: najpierw pomiar klonów i runów oraz skan historii, potem rezygnacja z blokady transferu u rejestratora, potem zaproszenie od klienta do zespołu docelowego i poprawna metoda płatności, potem transfer platformy, potem transfer repozytorium, na końcu rotacja sekretów i usunięcie starych dostępów. Zmiana abonenta domeny idzie na sam koniec albo na sam początek, zależnie od tego, czy domena ma zmienić rejestratora. Warstwa organizacyjna tego odbioru działa jak każde inne oddanie zadania z rąk do rąk i potrzebuje spisanej listy kontrolnej przed przekazaniem, bo inaczej wraca do Ciebie telefonem po trzech tygodniach.
Ten protokół jest pracą, której nikt nie wycenił, bo w ofercie było „wykonanie strony”. Dwa dni koordynacji między trzema panelami i rejestratorem to pozycja w umowie, nie gest dobrej woli — a jeśli po przekazaniu zostaje utrzymanie, to naturalny moment, żeby rozmawiać o przejściu z pojedynczych projektów na rozliczenie abonamentowe.
Zacznij od jednej komendy, zanim cokolwiek podpiszesz: whois na domenie klienta. Jeśli w rekordzie widać clientTransferProhibited albo datę utworzenia młodszą niż 60 dni, termin przekazania domeny nie jest Twoją decyzją i trzeba to powiedzieć klientowi dzisiaj, a nie w dniu odbioru. Repozytorium i projekt na platformie przeniesiesz w kwadrans — i te dwie rzeczy, w razie pomyłki, da się przenieść jeszcze raz.