Git oder GitHub: Was VPS-Betreiber wissen müssen
Git läuft lokal auf Ihrem Rechner oder VPS, GitHub ist ein gehosteter Dienst. Erfahren Sie, was der Unterschied für Deployments und Sicherungen bedeutet.
Was ist GitHub?
GitHub ist ein gehosteter Dienst, der Git-Repositorys speichert und eine Website darum aufbaut. Git ist das Versionskontrollprogramm, das auf Ihrem eigenen Computer oder Server ausgeführt wird. GitHub ist das Produkt eines einzelnen Unternehmens auf Basis von Git und gehört seit 2018 zu Microsoft. Sie können Git täglich verwenden, ohne GitHub zu öffnen. GitHub können Sie nicht ohne Git verwenden.
Diese Unterscheidung ist wichtig, sobald Sie einen VPS (virtuellen privaten Server) besitzen. Git zeichnet den Verlauf Ihrer Konfigurationsdateien und Deploy-Skripte auf. GitHub ist der Ort, an dem eine Kopie dieses Verlaufs liegt, wenn der Server selbst keine besitzt. Außerdem können Sie dort Builds und Reviews ausführen. Diese Anleitung verfolgt ein Beispiel vom leeren Verzeichnis bis zum Deployment auf einem Server. Jedes neue Wort wird an der Stelle erklärt, an der es erstmals vorkommt.
Was Git selbst übernimmt
Git ist ein Versionsverwaltungssystem. Es zeichnet den Zustand eines Verzeichnisses im Zeitverlauf auf. Dadurch sehen Sie, was sich wann und warum geändert hat. Git wurde 2005 für die Arbeit am Linux-Kernel entwickelt. Git ist verteilt. Das bedeutet, dass jede Kopie eines Repositorys die vollständige Historie enthält. Im Design gibt es keinen zentralen Server. Der Laptop eines Kollegen enthält eine ebenso vollständige Kopie wie jeder Server.
Installieren Sie Git und legen Sie Ihre Identität fest. Git verweigert das Aufzeichnen eines Commits ohne Namen und E-Mail-Adresse. Beide Angaben werden direkt im Commit gespeichert.
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"Unter Ubuntu 24.04 gibt git --version git version 2.43.0 aus. Jede Version aus den vergangenen Jahren verhält sich bei allen folgenden Schritten genauso.
Das Beispiel: ein Repository für Ihre VPS-Deploy-Dateien
Ein Repository, meist kurz „Repo“ genannt, ist ein Verzeichnis, das Git überwacht. Es wird zu einem Repository, sobald Sie git init ausführen. Dadurch wird darin ein verstecktes Verzeichnis .git angelegt. Dieses Verzeichnis ist das Repository. Wenn Sie .git löschen, bleibt ein gewöhnliches Verzeichnis ohne Verlauf zurück.
mkdir vps-deploy && cd vps-deploy
git init -b main
printf '.env\n*.key\n' > .gitignore-b main nennt den ersten Branch main. Wenn Sie diese Angabe weglassen, gibt Git stattdessen einen langen Hinweis zum Namen des Standard-Branches aus. .gitignore enthält Pfade, die Git niemals verfolgen darf. Tragen Sie Ihre Datei mit den geheimen Werten am ersten Tag dort ein. Eine Datei, die einmal committet wurde, bleibt im Verlauf erhalten, auch wenn Sie sie löschen. Um sie ordnungsgemäß zu entfernen, müssen Sie jeden danach erstellten Commit neu schreiben.
Commits: die Einheit der Historie
Fügen Sie nun ein Skript hinzu und zeichnen Sie es auf.
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 verschiebt eine Änderung in den Staging-Bereich. Dort wird festgelegt, welche Änderungen in den nächsten Commit aufgenommen werden. git commit schreibt diese Liste als einen Eintrag in die Historie. Ein Commit enthält einen Snapshot jeder verfolgten Datei, eine Nachricht, einen Autor, einen Zeitstempel und einen Verweis auf den vorherigen Commit. git log --oneline gibt eine Zeile pro Commit aus. Jede Zeile beginnt mit einem kurzen Hash wie a1b2c3d. Dieser Hash ist der Name des Commits. Fast jeder Git-Befehl akzeptiert ihn.
Überspringen Sie den Schritt git add, und git commit antwortet no changes added to commit (use "git add" and/or "git commit -a"). Es ist nichts defekt. Git teilt Ihnen mit, dass der Staging-Bereich leer ist. Daher gibt es nichts, von dem ein Snapshot erstellt werden kann. git status ist der Befehl, den Sie ausführen sollten, wenn Sie nicht weiterwissen. Er nennt den aktuellen Branch, die vorgemerkten Änderungen und die Dateien, die Git sehen kann, aber noch nicht verfolgt.
Branches: eine zweite Entwicklungslinie
Ein Branch ist ein beweglicher Zeiger auf einen Commit. main ist ein Branch und in keiner Weise etwas Besonderes an Git. Das Erstellen eines Branches kostet nichts, weil Git einen neuen Zeiger schreibt, statt Ihre Dateien zu kopieren.
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
lsNach git switch main fehlt backup.sh in der Auflistung. Es wurde nichts gelöscht. Die Datei ist im Branch add-backup vorhanden, aber main hatte sie nie. Deshalb hat Git sie aus Ihrem Arbeitsverzeichnis entfernt, als Sie den Branch gewechselt haben. Das überrascht jeden genau einmal. git switch add-backup stellt die Datei wieder her.
Remotes: wo GitHub schließlich erscheint
Bisher lief alles auf einem einzigen Rechner, vollständig ohne Netzwerkzugriff. Ein Remote ist eine benannte URL für eine weitere Kopie desselben Repositorys. GitHub hostet eine dieser Kopien für Sie. Der übliche Name für das zentrale Remote lautet origin.
Erstellen Sie über die GitHub-Website ein leeres Repository und verbinden Sie es anschließend. Verwenden Sie hier bevorzugt SSH statt HTTPS: Ein SSH-Schlüssel ist eine Datei, die Sie kontrollieren, und er läuft nicht wie ein persönliches Zugriffstoken ab.
ssh-keygen -t ed25519 -C "vps-deploy"
cat ~/.ssh/id_ed25519.pub
ssh -T git@github.comFügen Sie den ausgegebenen öffentlichen Schlüssel auf der Seite für SSH-Schlüssel Ihres GitHub-Kontos ein und führen Sie den Test erneut aus. Ein funktionierender Schlüssel antwortet mit Hi yourname! You've successfully authenticated, but GitHub does not provide shell access.. GitHub stellt keine Shell bereit. Diese Ablehnung ist daher der Erfolgsfall. git@github.com: Permission denied (publickey). bedeutet, dass Ihr Schlüssel entweder nicht angeboten oder nicht akzeptiert wurde. Prüfen Sie deshalb, ob Sie die Datei .pub und nicht den danebenliegenden privaten Schlüssel eingefügt haben.
git remote add origin git@github.com:yourname/vps-deploy.git
git push -u origin maingit push sendet Ihre Commits an das Remote. -u speichert, dass das lokale main dem Remote main folgt, sodass später ein einfaches git push genügt. git clone <url> ist auf einem neuen Rechner das Gegenstück: Der Befehl kopiert das gesamte Repository einschließlich seiner Historie und richtet origin für Sie ein. Ein HTTPS-Remote funktioniert ebenfalls. Dabei wird dasselbe Protokoll wie bei jeder Webseite verwendet, was in Netzwerken hilfreich ist, die ausgehenden Port 22 blockieren. Falls dieser Satz weiterer Erklärung bedarf, beschreibt wie eine HTTP-Anfrage tatsächlich aufgebaut ist die technischen Einzelheiten.
Pull Requests, Issues und Forks: Die GitHub-Bestandteile, nicht Git
Alles darüber gehört zu Git und funktioniert mit jedem Server. Die drei folgenden Begriffe bezeichnen GitHub-Funktionen. Andere Hosting-Dienste übernehmen diese Begriffe, Git selbst kennt sie jedoch nicht.
Ein Pull Request (PR) ist eine Anfrage, einen Branch in einen anderen zu mergen, ergänzt um eine Seite für die Diskussion. Sie pushen add-backup und öffnen einen PR gegen main. Die Website zeigt die Unterschiede Commit für Commit an. Andere Benutzer kommentieren einzelne Zeilen. Automatisierte Prüfungen melden für den Branch Erfolg oder Fehlschlag. Wenn Sie auf „Merge“ klicken, führt GitHub den Merge in seiner eigenen Kopie aus und aktualisiert anschließend main. Der Name stammt aus dem ursprünglichen Workflow. Dabei baten Sie einen Maintainer, Ihren Branch in dessen Branch zu pullen.
Ein Issue ist ein nummerierter Thread zu einem Fehler oder einer Aufgabe. Es wird in der GitHub-Datenbank gespeichert, nicht in Ihrem Repository. Das sollten Sie wissen, bevor Sie einen Hosting-Dienst auswählen: Wenn Sie das Repository klonen, erhalten Sie alle Commits, aber kein einziges Issue. Um Issues zu exportieren, müssen Sie die API aufrufen.
Ein Fork ist eine eigene serverseitige Kopie des Repositorys einer anderen Person. Sie haben Schreibzugriff auf diese Kopie, pushen einen Branch dorthin und öffnen einen Pull Request aus Ihrer Kopie zurück in das ursprüngliche Repository. So können Sie zu einem Projekt beitragen, dessen Maintainer Sie bisher nicht kennen. Ein Fork ist ein Klon, der auf GitHub liegt und seine Herkunft speichert.
Software liest alle drei über dieselbe API aus, die auch eine Person verwendet. Ein Pull-Request-Review-Agent, den Sie auf Ihrem eigenen Server ausführen überwacht neue PRs, liest den Diff und veröffentlicht Zeilenkommentare. Konventionen wie eine AGENTS.md-Datei im Root eines Repositorys existieren, weil ein Repository inzwischen sowohl von Tools als auch von Personen gelesen wird.
Was GitHub für den Besitzer eines VPS tatsächlich tut
Beginnen Sie mit der Speicherung außerhalb des Servers. Ihre Deploy-Skripte und Playbooks gehören an einen Ort, der nicht der von ihnen konfigurierte Server ist. Bauen Sie den VPS aus einem frischen Image neu auf, klonen Sie das Repository und führen Sie die Skripte aus. Halten Sie dieses Repository privat und hinterlegen Sie für den Server einen deploy key: einen SSH-Schlüssel, der für ein einzelnes Repository statt für Ihr gesamtes Konto registriert und auf schreibgeschützten Zugriff beschränkt ist. Ein offengelegter schreibgeschützter Deploy-Schlüssel gibt ein Repository preis. Ein offengelegter Kontoschlüssel gibt alles preis, in das Sie pushen können.
sudo git clone git@github.com:yourname/vps-deploy.git /srv/vps-deploy
cd /srv/vps-deploy
git pull --ff-only--ff-only verweigert das Erstellen eines Merge-Commits. Auf einem Server, der Änderungen nur übernimmt, ist ein Merge immer ein Fehler. Dieses Flag macht aus einer unübersichtlichen Historie den eindeutigen Fehler fatal: Not possible to fast-forward, aborting.. Auf dem Server wurde etwas geändert, das dort nicht geändert werden sollte. Ermitteln Sie die Ursache, bevor Sie erneut pullen.
Wenn Sie als root klonen und Git anschließend als ein anderer Benutzer ausführen, erhalten Sie fatal: detected dubious ownership in repository at '/srv/vps-deploy'. Git verweigert das Lesen eines Repositorys, das einem anderen Benutzer gehört, weil ein manipuliertes .git/config Git dazu bringen kann, Befehle auszuführen. Korrigieren Sie den Besitz mit chown, statt eine Ausnahme für safe.directory hinzuzufügen. Die Ausnahme unterdrückt die Prüfung, beseitigt aber nicht die Ursache.
GitHub Actions: Build- und Bereitstellungspipelines
Actions ist das CI/CD-System (Continuous Integration und Continuous Delivery) von GitHub. Legen Sie eine YAML-Datei unter .github/workflows/ ab. GitHub führt sie aus, sobald das angegebene Ereignis eintritt.
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 *.shDie Datei ist ein Workflow. Ein Job wird auf einem Rechner ausgeführt. Ein Schritt ist entweder ein einzelner Befehl oder eine veröffentlichte Action. uses: bindet eine Action aus einem anderen Repository ein. @v7 legt ihre Hauptversion fest (v7 ist für actions/checkout im August 2026 aktuell). Legen Sie immer eine Version fest. Bei einer Action ohne Versionsbindung wird Code ausgeführt, den Sie nicht geprüft haben und der Zugriff auf Ihre Secrets hat.
runs-on: ubuntu-latest fordert eine neue virtuelle Maschine von GitHub an. Diese wird gelöscht, sobald der Job endet. Standard-Runner sind in öffentlichen Repositories kostenlos. Der kostenlose Tarif umfasst für private Repositories im August 2026 außerdem 2,000 Minuten pro Monat. Prüfen Sie die aktuelle Preisseite, bevor Sie Ihr Budget auf dieser Zahl aufbauen.
Secrets werden in den Repository-Einstellungen gespeichert und als ${{ secrets.DEPLOY_KEY }} gelesen. Ein durch einen Pull Request aus einem Fork ausgelöster Workflow erhält ein schreibgeschütztes Token und keinen Zugriff auf diese Secrets. Andernfalls könnte ein Fremder einen PR eröffnen, dessen einzige Aufgabe darin besteht, die Secrets auszugeben.
Den Actions-Runner auf dem eigenen VPS ausführen
runs-on: self-hosted sendet den Job stattdessen an eine Maschine, die Ihnen gehört. Auf der Runner-Einstellungsseite des Repositorys finden Sie eine Download-Zeile, die Webadresse des Repositorys und ein Registrierungstoken, das eine Stunde lang gültig ist. Tragen Sie die letzten beiden Werte in REPO_URL und RUNNER_TOKEN ein. Danach besteht die Einrichtung aus drei Befehlen.
./config.sh --url "$REPO_URL" --token "$RUNNER_TOKEN"
sudo ./svc.sh install
sudo ./svc.sh start
./svc.sh statussvc.sh status sollte den Dienst als aktiv melden und aktuelle Logzeilen anzeigen. Der Runner öffnet eine ausgehende HTTPS-Verbindung zu GitHub und fragt nach Arbeit. Sie müssen daher keinen eingehenden Port dafür öffnen. svc.sh install erstellt die systemd-Unit. Dieser Schritt wird häufig übersprungen: Ohne ihn beendet sich der Runner mit Ihrer SSH-Sitzung, und jeder nachfolgende Job bleibt ohne Erklärung in der Warteschlange. die vollständige Einrichtung eines selbst gehosteten Runners auf einem VPS beschreibt die erforderlichen Maßnahmen zur Absicherung und Bereinigung eines langfristig betriebenen Runners.
Der Vorteil besteht darin, dass ein Deployment keinen eingehenden SSH-Schlüssel mehr benötigt, der aus dem Internet erreichbar ist, weil der Job bereits auf dem Server ausgeführt wird. Auch der Build-Cache bleibt zwischen den Ausführungen erhalten, und es läuft keine minutengenaue Abrechnung.
Eine Warnung ist unbedingt zu beachten. Die eigene Dokumentation von GitHub empfiehlt selbst gehostete Runner nur für private Repositorys, weil Forks eines öffentlichen Repositorys gefährlichen Code auf Ihrem Runner ausführen können, indem sie einen Pull Request eröffnen. Der Runner führt alles aus, was die Workflow-Datei auf diesem Branch vorgibt. Bei einem privaten Repository, bei dem Sie kontrollieren, wer pushen darf, ist das Risiko gering. Bei einem öffentlichen Repository müssen Sie jeden selbst gehosteten Runner als Maschine behandeln, auf der Fremde Code ausführen können.
GitHub überhaupt erforderlich?
Nein. Git ist der Standard, GitHub ist eine Komfortlösung. Forgejo und Gitea sind selbst gehostete Forges. Ein Forge ist ein Git-Host mit verknüpften Issues und Pull Requests. Beide werden als einzelnes Go-Binary ausgeliefert und laufen auf einem kleinen VPS. Forgejo ist ein Fork von Gitea aus dem Jahr 2022 und bildet inzwischen die Grundlage für Codeberg. Ein Repository lässt sich mit einem Befehl verschieben, weil das Übertragungsprotokoll identisch ist.
git remote -v
git remote set-url origin git@git.example.com:you/vps-deploy.git
git push origin mainJeder Commit wird übertragen, weil jeder Clone bereits die vollständige Historie enthält. Nicht übertragen wird die Ebene, die GitHub darauf aufgebaut hat: die Issues und die Diskussionen in Pull Requests. Auch CI wird nicht übertragen. Forgejo verfügt über eine eigene Actions-Implementierung, die ähnliche YAML-Dateien aus .forgejo/workflows/ einliest. In der Dokumentation werden die Grenzen ausdrücklich beschrieben: GitHub Actions und Forgejo Actions sind nicht identisch, und manche Dinge funktionieren möglicherweise nicht sofort. Außerdem wird ein eigener Runner benötigt. Planen Sie diesen Schritt als Portierung, nicht als Kopie.
Der wichtigste Grund, warum die meisten Projekte bei GitHub bleiben, sind die Mitwirkenden. Öffentlicher Code muss dort liegen, wo die Benutzer bereits ein Konto haben. Ihre privaten Deployment-Skripte müssen das nicht. Das sind zwei getrennte Entscheidungen, und Sie können sie unterschiedlich beantworten.
Was zuerst fehlschlägt und was die Fehlermeldung bedeutet
Ein Push wird abgelehnt. Sie sehen Folgendes:
! [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.Seit Ihrem letzten Pull wurde etwas gepusht, häufig eine Änderung, die Sie im Webeditor vorgenommen haben. Führen Sie git pull --rebase aus, um Ihre Commits auf deren Commits neu aufzusetzen, und pushen Sie anschließend erneut. Vermeiden Sie git push --force auf einem gemeinsam verwendeten Branch, weil dadurch die anderen Commits dieses Branches auf dem Server entfernt werden.
fatal: refusing to merge unrelated histories. Sie haben lokal git init ausgeführt und GitHub gleichzeitig das Repository mit einer README-Datei erstellen lassen. Die beiden Historien haben keinen gemeinsamen Commit. Daher kann Git die Historien nicht automatisch zusammenführen. Die saubere Lösung besteht darin, die GitHub-Kopie in einen neuen Ordner zu klonen und Ihre Dateien dorthin zu verschieben.
error: src refspec main does not match any. Der von Ihnen angegebene Branch existiert hier nicht. In der Regel enthält das Repository bisher keine Commits oder Ihr Branch heißt master. Mit git branch --show-current lässt sich das eindeutig feststellen.
Ein Geheimnis ist in einem Commit gelandet. Ersetzen Sie das betreffende Zugangsmittel sofort. Behandeln Sie es ab dem Zeitpunkt des Pushs als öffentlich, da Forks, Spiegel und zwischengespeicherte Ansichten Kopien enthalten können, die Sie nicht löschen können.
FAQ
Ist GitHub dasselbe wie Git?
Nein. Git ist ein Versionsverwaltungsprogramm, das Sie auf einem Rechner installieren. Es funktioniert ohne Netzwerk und ohne Benutzerkonto. GitHub ist ein kommerzieller Hosting-Dienst. Er speichert Git-Repositorys und ergänzt sie um eine Weboberfläche, Issues, Pull Requests und CI. Git wurde 2005 veröffentlicht. GitHub wurde 2008 darauf aufbauend gestartet. Sie können Git dauerhaft ohne GitHub verwenden. Jede GitHub-Funktion verwendet darunter Git.
Benötige ich ein GitHub-Konto, um Git auf meinem VPS zu verwenden?
Nein. git init, git commit und git log funktionieren auf einem Server auch ohne konfiguriertes Remote-Repository. Das reicht bereits aus, um Änderungen an /etc-Dateien oder Deploy-Skripten zu verfolgen. Ein Konto wird nützlich, wenn Sie eine Kopie der Historie außerhalb des Servers speichern möchten oder wenn ein zweiter Rechner das Repository klonen soll. Selbst gehostete Forges wie Forgejo und Gitea erfüllen denselben Zweck auf eigener Hardware. Ein einfaches SSH-Remote-Repository, das auf ein Bare-Repository auf einem anderen Rechner zeigt, funktioniert sogar vollständig ohne Forge-Software.
Was ist ein Pull Request?
Ein Pull Request ist eine Anfrage, einen Branch in einen anderen zu mergen. Dazu gehört eine Diskussionsseite. Sie pushen einen Branch und öffnen den PR gegen main. Der Host zeigt die Änderungen Commit für Commit an. Reviewer können dadurch einzelne Zeilen kommentieren. Automatisierte Prüfungen können ihren Erfolg oder Fehlschlag melden. Ein Pull Request ist eine GitHub-Funktion und keine Git-Funktion. Git selbst stellt daher keinen Befehl dafür bereit. Andere Hosts implementieren dasselbe Konzept und nennen es teilweise Merge Request.
Sollte ich einen GitHub Actions Runner auf meinem eigenen VPS betreiben?
Bei einem privaten Repository häufig ja. Der Job läuft auf Hardware, für die Sie bereits bezahlen. Es werden keine Minuten abgerechnet. Der Build-Cache bleibt verfügbar. Für ein Deployment muss außerdem kein eingehender SSH-Schlüssel im Internet erreichbar sein, weil der Runner ausgehend eine Verbindung zu GitHub herstellt und dort Arbeit anfordert. Bei einem öffentlichen Repository rät GitHub davon ab. Jeder kann Ihr Repository forken und einen Pull Request öffnen, dessen Workflow Code auf Ihrem Rechner ausführt.
Kann ich meine Repositorys später von GitHub weg migrieren?
Den Code ja, problemlos. Jeder Clone enthält die vollständige Historie. Daher verschiebt git remote set-url origin <new url> gefolgt von einem Push alles, was ein Commit enthält. Nicht übernommen wird die von GitHub verwaltete Ebene. Issues, Pull-Request-Diskussionen und die Actions-Historie liegen in der GitHub-Datenbank und nicht in Ihrem .git-Ordner. Migrationstools können Issues über die API kopieren. Workflow-Dateien müssen für die CI des neuen Hosts normalerweise angepasst werden. Das sollten Sie bei der Planung berücksichtigen. Es spricht dafür, die eigentliche Dokumentation im Repository und nicht in Issue-Threads abzulegen.