Git a GitHub: różnice dla użytkowników VPS
Dowiedz się, czym różni się lokalny system kontroli wersji Git od platformy hostingowej GitHub. Wyjaśniamy, jak poprawnie zarządzać kodem i wdrożeniami na własnym serwerze VPS.
Czym jest GitHub?
GitHub to usługa hostingowa przechowująca repozytoria Git i udostępniająca interfejs webowy do pracy z nimi. Git to program do kontroli wersji, który działa na lokalnym komputerze lub własnym serwerze. GitHub jest produktem firmy zewnętrznej, działającym w oparciu o Git; od 2018 roku właścicielem platformy jest Microsoft. Można korzystać z Git codziennie, nigdy nie otwierając serwisu GitHub. Nie można natomiast korzystać z GitHub bez użycia Git.
To rozróżnienie staje się istotne w momencie posiadania VPS (virtual private server). Git służy do rejestrowania historii zmian w plikach konfiguracyjnych oraz skryptach wdrożeniowych. GitHub stanowi miejsce przechowywania kopii tej historii poza serwerem, a także środowisko do uruchamiania procesów budowania i przeglądów kodu. Niniejszy przewodnik przedstawia proces od utworzenia pustego katalogu do wdrożenia na serwerze, definiując każde nowe pojęcie w momencie jego pierwszego użycia.
Co Git wykonuje samodzielnie
Git jest systemem kontroli wersji: rejestruje stan katalogu w czasie, co pozwala sprawdzić, co, kiedy i dlaczego uległo zmianie. Został stworzony w 2005 roku na potrzeby prac nad jądrem Linux. Jest to system rozproszony, co oznacza, że każda kopia repozytorium przechowuje pełną historię zmian. W architekturze systemu nie przewidziano centralnego serwera. Laptop współpracownika zawiera kopię równie kompletną, co dowolny serwer.
Należy zainstalować oprogramowanie i skonfigurować tożsamość użytkownika. Git odmawia zarejestrowania commita bez podania nazwy oraz adresu e-mail, ponieważ oba te elementy są zapisywane bezpośrednio wewnątrz commita.
sudo apt update && sudo apt install -y git
git --version
git config --global user.name "Your Name"
git config --global user.email "you@example.com"W systemie Ubuntu 24.04 polecenie git --version zwraca git version 2.43.0. Każde wydanie z ostatnich kilku lat zachowuje się w identyczny sposób w odniesieniu do wszystkich poniższych operacji.
Przykład: repozytorium dla plików wdrożeniowych VPS
Repozytorium, często określane skrótem "repo", to katalog monitorowany przez Git. Staje się nim po uruchomieniu git init, co tworzy wewnątrz ukryty folder .git. Ten folder jest repozytorium. Usunięcie .git sprawia, że pozostaje zwykły katalog bez historii zmian.
mkdir vps-deploy && cd vps-deploy
git init -b main
printf '.env\n*.key\n' > .gitignore-b main nadaje pierwszej gałęzi nazwę main. Pominięcie tego parametru spowoduje, że Git wyświetli długą wskazówkę dotyczącą domyślnej nazwy gałęzi. .gitignore zawiera ścieżki, których Git nigdy nie powinien śledzić. Wpisz plik z sekretami do tego pliku już pierwszego dnia, ponieważ plik raz zatwierdzony pozostaje w historii nawet po jego usunięciu, a jego poprawne usunięcie wymaga nadpisania każdego kolejnego commita.
Commity: jednostka historii
Dodaj teraz skrypt i zarejestruj go.
printf '#!/bin/sh\nsudo systemctl restart caddy\n' > restart.sh
git add restart.sh .gitignore
git commit -m "Add restart script and gitignore"
git log --onelinegit add przenosi zmianę do obszaru przygotowawczego (staging area), czyli listy elementów, które trafią do następnego commita. git commit zapisuje tę listę w historii jako jeden wpis. Commit przechowuje migawkę każdego śledzonego pliku, wiadomość, autora, znacznik czasu oraz wskaźnik do poprzedniego commita. git log --oneline wyświetla jedną linię na commit, z których każda zaczyna się od krótkiego hasha, takiego jak a1b2c3d. Ten hash jest nazwą commita i niemal każde polecenie Git go akceptuje.
Pomiń krok git add, a git commit odpowie no changes added to commit (use "git add" and/or "git commit -a"). Nic nie jest uszkodzone. Git informuje, że obszar przygotowawczy jest pusty, więc nie ma czego uwiecznić na migawce. git status to polecenie, które należy uruchomić w razie zagubienia: podaje nazwę bieżącej gałęzi, przygotowane zmiany oraz pliki, które Git widzi, ale których nie śledzi.
Gałęzie: druga linia historii
Gałąź (branch) to ruchomy wskaźnik na commit. main jest gałęzią i w żaden sposób nie wyróżnia się w Git. Tworzenie gałęzi nie generuje kosztów, ponieważ Git zapisuje nowy wskaźnik zamiast kopiować pliki.
git switch -c add-backup
printf '#!/bin/sh\nrestic backup /srv\n' > backup.sh
git add backup.sh
git commit -m "Add nightly backup"
git switch main
lsPo git switch main, backup.sh znika z listy plików. Nic nie zostało usunięte. Plik istnieje w gałęzi add-backup, a main nigdy go nie zawierała, więc Git usunął go z katalogu roboczego podczas przełączania. Jest to sytuacja zaskakująca dla każdego użytkownika. git switch add-backup przywraca plik.
Zdalne repozytoria: gdzie ostatecznie pojawia się GitHub
Wszystko do tej pory działało na jednej maszynie bez dostępu do sieci. Zdalne repozytorium (remote) to nazwany adres URL wskazujący na inną kopię tego samego repozytorium. GitHub przechowuje jedną z takich kopii. Standardowa nazwa głównego zdalnego repozytorium to origin.
Utwórz puste repozytorium za pośrednictwem strony internetowej GitHub, a następnie połącz się z nim. Preferuj tutaj SSH zamiast HTTPS: klucz SSH to plik, nad którym masz kontrolę i który nie wygasa w taki sposób, jak osobisty token dostępu (personal access token).
ssh-keygen -t ed25519 -C "vps-deploy"
cat ~/.ssh/id_ed25519.pub
ssh -T git@github.comWklej wyświetlony klucz publiczny na stronie kluczy SSH w swoim koncie GitHub, a następnie uruchom test ponownie. Działający klucz odpowiada Hi yourname! You've successfully authenticated, but GitHub does not provide shell access.. GitHub nie zapewnia dostępu do powłoki (shell), więc taka odmowa oznacza sukces. git@github.com: Permission denied (publickey). oznacza, że klucz nie został przedstawiony lub nie został zaakceptowany, więc sprawdź, czy wklejono zawartość pliku .pub, a nie klucza prywatnego znajdującego się obok.
git remote add origin git@github.com:yourname/vps-deploy.git
git push -u origin maingit push wysyła Twoje commity do zdalnego repozytorium. -u zapisuje informację, że lokalna gałąź main śledzi zdalną gałąź main, dzięki czemu później wystarczy samo polecenie git push. git clone <url> to operacja odwrotna na nowej maszynie: kopiuje całe repozytorium wraz z jego historią i konfiguruje origin za Ciebie. Zdalne repozytorium HTTPS również działa i korzysta z tego samego protokołu co każda strona internetowa, co pomaga w sieciach blokujących wychodzący port 22. Jeśli to zdanie wymaga wyjaśnienia, z czego faktycznie składa się żądanie HTTP omawia te mechanizmy.
Pull requests, issues i forks: elementy GitHub, a nie Git
Wszystko powyżej dotyczy Git i działa z dowolnym serwerem. Trzy poniższe pojęcia to funkcje GitHub. Inni dostawcy je kopiują, ale sam Git nie posiada o nich wiedzy.
Pull request (PR) to prośba o scalenie jednej gałęzi z drugą, opakowana w stronę przeznaczoną do dyskusji. Wypychasz add-backup, otwierasz PR względem main, a serwis prezentuje różnice commit po commicie. Użytkownicy komentują poszczególne linie. Zautomatyzowane testy zgłaszają wynik pozytywny lub negatywny dla danej gałęzi. Kliknięcie przycisku scalenia powoduje, że GitHub wykonuje operację merge na własnej kopii, a następnie aktualizuje main. Nazwa pochodzi z oryginalnego modelu pracy, w którym prosiło się opiekuna projektu o pobranie (pull) gałęzi do jego repozytorium.
Issue to numerowany wątek dotyczący błędu lub zadania. Znajduje się on w bazie danych GitHub, a nie w Twoim repozytorium, co warto wiedzieć przed wyborem hosta: sklonowanie repozytorium pobiera wszystkie commity, ale żadnego issue. Eksport issue wymaga użycia API.
Fork to własna kopia repozytorium innej osoby, przechowywana po stronie serwera. Masz uprawnienia do zapisu w tej kopii, wypychasz do niej gałąź i otwierasz pull request z własnej kopii do oryginału. W ten sposób możesz wnosić wkład do projektu, którego opiekunowie Cię nie znają. Fork to klon, który istnieje na GitHub i przechowuje informację o swoim pochodzeniu.
Oprogramowanie odczytuje wszystkie trzy elementy za pomocą tego samego API, którego używa człowiek. Agent przeglądu pull requestów uruchomiony na własnym serwerze monitoruje nowe PR, odczytuje różnice i dodaje komentarze do linii. Konwencje takie jak plik AGENTS.md w katalogu głównym repozytorium istnieją, ponieważ repozytorium jest obecnie odczytywane zarówno przez narzędzia, jak i przez ludzi.
Co GitHub faktycznie daje właścicielowi VPS
Zacznij od przechowywania danych poza serwerem. Skrypty wdrożeniowe i playbooki powinny znajdować się w miejscu innym niż serwer, który konfigurują. Przywróć VPS z czystego obrazu, sklonuj repozytorium i uruchom proces. Utrzymuj to repozytorium jako prywatne i nadaj serwerowi deploy key: klucz SSH zarejestrowany dla jednego repozytorium zamiast dla całego konta, ustawiony w trybie tylko do odczytu. Wyciek klucza typu deploy key z uprawnieniami tylko do odczytu naraża tylko jedno repozytorium. Wyciek klucza konta naraża wszystko, do czego masz uprawnienia zapisu.
sudo git clone git@github.com:yourname/vps-deploy.git /srv/vps-deploy
cd /srv/vps-deploy
git pull --ff-only--ff-only odmawia utworzenia merge commit. Na serwerze, który jedynie pobiera zmiany, scalanie jest zawsze błędem, więc ta flaga zamienia niejasną historię w prosty błąd fatal: Not possible to fast-forward, aborting.. Coś zmieniło się na serwerze, co nie powinno było ulec zmianie. Znajdź to przed ponownym wykonaniem polecenia pull.
Sklonuj repozytorium jako root, a następnie uruchom Git jako inny użytkownik, a otrzymasz fatal: detected dubious ownership in repository at '/srv/vps-deploy'. Git odmawia odczytu repozytorium, którego właścicielem jest inny użytkownik, ponieważ wrogi .git/config mógłby wymusić na Git wykonanie poleceń. Napraw własność za pomocą chown zamiast dodawania wyjątku safe.directory, ponieważ wyjątek wycisza kontrolę bez usuwania przyczyny problemu.
GitHub Actions: potoki budowania i wdrażania
Actions to system CI/CD (ciągłej integracji i ciągłego dostarczania) w serwisie GitHub. Po umieszczeniu pliku YAML w katalogu .github/workflows/, GitHub uruchamia go w momencie wystąpienia zdefiniowanego zdarzenia.
name: check
on:
push:
branches: [main]
jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: sudo apt-get update && sudo apt-get install -y shellcheck
- run: shellcheck *.shPlik ten jest workflow. Job (zadanie) wykonuje się na jednej maszynie. Step (krok) to pojedyncze polecenie lub opublikowana akcja. uses: pobiera akcję z innego repozytorium, a @v7 przypina jej główną wersję (wersja v7 jest aktualna dla actions/checkout na sierpień 2026). Zawsze należy stosować przypinanie wersji, ponieważ nieprzypięta akcja oznacza uruchomienie kodu, którego nie zweryfikowano, z dostępem do posiadanych sekretów.
runs-on: ubuntu-latest żąda od GitHub nowej maszyny wirtualnej, która jest usuwana po zakończeniu zadania. Standardowe maszyny (runners) są darmowe dla repozytoriów publicznych, a plan darmowy obejmuje 2000 minut miesięcznie dla repozytoriów prywatnych (stan na sierpień 2026). Przed zaplanowaniem budżetu w oparciu o tę wartość należy sprawdzić aktualną stronę z cennikiem.
Sekrety są przechowywane w ustawieniach repozytorium i odczytywane jako ${{ secrets.DEPLOY_KEY }}. Workflow wyzwalany przez pull request z forka otrzymuje token tylko do odczytu i nie ma dostępu do tych sekretów, ponieważ w przeciwnym razie osoba trzecia mogłaby otworzyć pull request, którego jedynym celem byłoby ich wyświetlenie.
Uruchamianie Actions runner na własnym VPS
runs-on: self-hosted przekazuje zadanie do maszyny, której jesteś właścicielem. Strona ustawień runnera w repozytorium udostępnia polecenie pobrania, adres internetowy repozytorium oraz token rejestracyjny ważny przez jedną godzinę. Wprowadź te dwa ostatnie elementy do REPO_URL oraz RUNNER_TOKEN, a następnie wykonaj trzy polecenia konfiguracyjne.
./config.sh --url "$REPO_URL" --token "$RUNNER_TOKEN"
sudo ./svc.sh install
sudo ./svc.sh start
./svc.sh statussvc.sh status powinno wskazać, że usługa jest aktywna i wyświetlić ostatnie wpisy z dziennika. Runner otwiera wychodzące połączenie HTTPS do GitHub w celu pobrania zadań, więc nie ma potrzeby otwierania żadnych portów przychodzących. svc.sh install tworzy jednostkę systemd i jest to krok, który często bywa pomijany: bez niego runner kończy działanie wraz z zamknięciem sesji SSH, a każde kolejne zadanie pozostaje w kolejce bez żadnego wyjaśnienia. pełna konfiguracja własnego runnera na VPS przeprowadza przez proces utwardzania zabezpieczeń oraz czyszczenia, które są niezbędne w przypadku długo działającego runnera.
Korzyścią jest to, że wdrożenie nie wymaga już klucza SSH dostępnego z Internetu, ponieważ zadanie jest wykonywane bezpośrednio na serwerze. Pamięć podręczna kompilacji pozostaje dostępna między uruchomieniami, a limit minut nie jest naliczany.
Jedno ostrzeżenie jest obowiązkowe. Dokumentacja GitHub zaleca używanie własnych runnerów wyłącznie w przypadku prywatnych repozytoriów, ponieważ forki publicznego repozytorium mogą uruchomić niebezpieczny kod na Twoim runnerze poprzez otwarcie pull requesta. Runner wykonuje dowolne polecenia zawarte w pliku workflow w danej gałęzi. W prywatnym repozytorium, gdzie kontrolujesz dostęp do wypychania zmian, ryzyko jest niewielkie. W przypadku repozytorium publicznego traktuj każdy własny runner jak maszynę, na której osoby trzecie mogą wykonywać dowolny kod.
Czy GitHub jest w ogóle potrzebny?
Nie. Git jest standardem, a GitHub to jedynie wygoda. Forgejo i Gitea to rozwiązania typu self-hosted forge, czyli serwery Git zintegrowane z systemem zgłoszeń (issues) oraz obsługą pull requestów. Oba programy są dystrybuowane jako pojedynczy plik binarny w języku Go i mogą działać na niewielkim VPS. Forgejo to fork Gitea z 2022 roku, który obecnie obsługuje platformę Codeberg. Przeniesienie repozytorium wymaga wykonania jednego polecenia, ponieważ protokół przesyłu danych jest identyczny.
git remote -v
git remote set-url origin git@git.example.com:you/vps-deploy.git
git push origin mainKażdy commit zostaje przeniesiony, ponieważ każdy klon repozytorium zawiera pełną historię zmian. Nie przenosi się natomiast warstwa zbudowana przez GitHub: zgłoszenia oraz wątki pull requestów. System CI również nie podlega migracji. Forgejo posiada własną implementację Actions, która odczytuje pliki YAML z .forgejo/workflows/, jednak dokumentacja wyraźnie wskazuje na ograniczenia, zaznaczając, że GitHub Actions i Forgejo Actions nie są tożsame i niektóre elementy mogą wymagać dostosowania. Wymagane jest również skonfigurowanie własnego runnera. Ten etap należy zaplanować jako portowanie, a nie kopiowanie.
Głównym powodem, dla którego większość projektów pozostaje na GitHubie, jest społeczność. Kod publiczny musi znajdować się tam, gdzie użytkownicy posiadają już konta. Prywatne skrypty wdrożeniowe nie muszą. Są to dwie odrębne decyzje i można podjąć je niezależnie.
Co psuje się najpierw i co oznacza komunikat o błędzie
Wypchnięcie (push) zostało odrzucone. Widzisz następujący komunikat:
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'github.com:yourname/vps-deploy.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally.Od czasu ostatniego pobrania (pull) wprowadzono zmiany, często poprzez edytor internetowy. Uruchom git pull --rebase, aby nałożyć swoje commity na te już istniejące, a następnie ponownie wykonaj push. Unikaj git push --force na współdzielonej gałęzi, ponieważ usuwa to commity innych osób z tej gałęzi na serwerze.
fatal: refusing to merge unrelated histories. Uruchomiłeś git init lokalnie oraz pozwoliłeś GitHub utworzyć repozytorium z plikiem README. Obie historie nie mają wspólnego commita, więc Git nie podejmie próby zgadywania. Czystym rozwiązaniem jest sklonowanie kopii z GitHub do nowego folderu i przeniesienie do niego swoich plików.
error: src refspec main does not match any. Gałąź o podanej nazwie tutaj nie istnieje. Zazwyczaj repozytorium nie posiada jeszcze żadnych commitów lub Twoja gałąź nazywa się master. git branch --show-current rozwiązuje ten problem.
Sekret trafił do commita. Natychmiast zrotuj poświadczenia. Traktuj je jako publiczne od momentu wypchnięcia, ponieważ forki, mirrory i zbuforowane widoki przechowują kopie, których nie masz możliwości usunąć.
FAQ
Czy GitHub to to samo co Git?
Nie. Git to program do kontroli wersji instalowany na maszynie, który działa bez sieci i bez konta. GitHub to komercyjna usługa hostingowa, która przechowuje repozytoria Git i dodaje do nich interfejs WWW, system zgłoszeń (issues), pull requests oraz CI. Git został wydany w 2005 roku, a GitHub wystartował w 2008 roku w oparciu o niego. Z Gita można korzystać bezterminowo bez użycia GitHuba. Każda funkcja GitHuba opiera się na Gicie.
Czy potrzebuję konta na GitHubie, aby używać Gita na moim VPS?
Nie. git init, git commit oraz git log działają na serwerze bez skonfigurowanego żadnego zdalnego repozytorium, co wystarcza do śledzenia zmian w plikach /etc lub wdrażania skryptów. Konto staje się przydatne, gdy wymagana jest kopia historii niezależna od serwera lub druga maszyna, która może ją sklonować. Samodzielnie hostowane platformy, takie jak Forgejo i Gitea, realizują tę samą potrzebę na własnym sprzęcie, a zwykły zdalny dostęp SSH wskazujący na "bare repository" na innej maszynie działa bez żadnego oprogramowania typu forge.
Czym jest pull request?
Pull request to prośba o scalenie jednej gałęzi z drugą, powiązana ze stroną dyskusji. Użytkownik wypycha (push) gałąź, otwiera PR względem main, a serwis prezentuje zmiany commit po commicie, umożliwiając recenzentom komentowanie poszczególnych linii oraz raportowanie wyników automatycznych testów. Jest to funkcja GitHuba, a nie Gita, dlatego sam Git nie posiada dla niej dedykowanego polecenia. Inne serwisy implementują ten sam koncept, nazywając go czasem merge request.
Czy powinienem uruchamiać runner GitHub Actions na własnym VPS?
W przypadku prywatnego repozytorium – często tak. Zadanie wykonuje się na sprzęcie, za który już płacisz, czas pracy nie jest limitowany, pamięć podręczna kompilacji pozostaje dostępna, a wdrożenie nie wymaga wystawiania klucza SSH na świat, ponieważ runner łączy się wychodząco z GitHubem i pobiera zadania. W przypadku repozytoriów publicznych GitHub odradza to rozwiązanie: każdy może wykonać fork repozytorium i otworzyć pull request, którego workflow uruchomi kod na Twojej maszynie.
Czy mogę później przenieść swoje repozytoria z GitHuba?
Kod – tak, bez problemu. Każdy klon zawiera pełną historię, więc git remote set-url origin <new url>, a następnie push, przenosi wszystko, co zawiera commit. To, co pozostaje, to warstwa należąca do GitHuba: zgłoszenia, dyskusje w pull requestach i historia Actions znajdują się w jego bazie danych, a nie w folderze .git. Narzędzia migracyjne mogą skopiować zgłoszenia przez API, a pliki workflow zazwyczaj wymagają edycji pod kątem CI nowego hosta. Pamiętanie o tym jest argumentem za umieszczaniem istotnej dokumentacji wewnątrz repozytorium, a nie w wątkach zgłoszeń.