 Autor: [Tomasz Nowosielski](/autorzy/tomasz-nowosielski) Redaktor naczelny, analityk hostingu · Zweryfikowano Kwiecień 2026

1.  [Strona główna](/) ›
2.  [Baza wiedzy](/baza-wiedzy/) ›
3.  Git Hooks — automatyzacja deployment

# Git Hooks — automatyzacja deployment przez git push

Opublikowano: 9 kwietnia 2026 · Kategoria: DevOps / VPS

Git hooks to skrypty uruchamiane automatycznie przez git w kluczowych momentach cyklu życia repozytorium. Dzięki nim możesz wdrożyć aplikację na serwer jednym poleceniem `git push production main` — bez GitHub Actions, bez Jenkins, bez żadnej zewnętrznej usługi. Oto jak to skonfigurować krok po kroku.

## Rodzaje git hooków

Git rozróżnia hooki po stronie klienta (lokalne) i po stronie serwera (zdalne). Do automatyzacji deploymentu używamy hooków serwerowych:

Hook

Strona

Kiedy się uruchamia

Typowe zastosowanie

`pre-commit`

Klient

Przed zatwierdzeniem commita

Lint, formatowanie, testy jednostkowe

`pre-push`

Klient

Przed wysłaniem do remote

Testy integracyjne, sprawdzenie branch

`pre-receive`

Serwer

Przed zaakceptowaniem push

Walidacja, wymuszanie konwencji

`post-receive`

Serwer

Po zaakceptowaniu push

**Deploy — checkout, build, restart**

`update`

Serwer

Przed aktualizacją ref-a

Kontrola dostępu per branch

## Krok 1: Bare repo na serwerze

Na serwerze (przez SSH) utwórz repozytorium bare — przechowuje ono historię git, ale nie ma katalogu roboczego z plikami:

\# Na serwerze (przez SSH)
ssh user@twoj-serwer.pl

# Utwórz katalogi
mkdir -p /home/deploy/app.git
mkdir -p /var/www/app

# Zainicjuj bare repo
cd /home/deploy/app.git
git init --bare

# Sprawdź zawartość — brak katalogu roboczego!
ls
# HEAD  branches/  config  description  hooks/  info/  objects/  refs/

## Krok 2: Hook post-receive

Utwórz plik `/home/deploy/app.git/hooks/post-receive`:

#!/bin/bash
# /home/deploy/app.git/hooks/post-receive

set -e  # Przerwij przy błędzie

REPO\_DIR="/home/deploy/app.git"
WEB\_DIR="/var/www/app"
BRANCH="main"

# Odczytaj które gałęzie są pushowane
while read oldrev newrev refname; do
  PUSHED\_BRANCH=${refname##refs/heads/}

  if \[ "$PUSHED\_BRANCH" != "$BRANCH" \]; then
    echo "Pominięto gałąź $PUSHED\_BRANCH (deploy tylko z $BRANCH)"
    continue
  fi

  echo "=== Deploy z gałęzi $BRANCH ==="

  # Checkout plików do webroot
  git --work-tree="$WEB\_DIR" --git-dir="$REPO\_DIR" checkout -f "$BRANCH"

  cd "$WEB\_DIR"

  # PHP: instalacja zależności
  if \[ -f "composer.json" \]; then
    echo "--- composer install ---"
    composer install --no-dev --optimize-autoloader --quiet
  fi

  # Node.js: instalacja i build
  if \[ -f "package.json" \]; then
    echo "--- npm ci && npm run build ---"
    npm ci --production=false
    npm run build
  fi

  # Laravel: migracje i cache
  if \[ -f "artisan" \]; then
    echo "--- artisan migrate + cache ---"
    php artisan migrate --force
    php artisan config:cache
    php artisan route:cache
    php artisan view:cache
  fi

  # Restart PHP-FPM (opcjonalnie)
  # sudo systemctl reload php8.2-fpm

  echo "=== Deploy zakończony pomyślnie ==="
done

\# Nadaj uprawnienia wykonywania
chmod +x /home/deploy/app.git/hooks/post-receive

## Krok 3: Remote na lokalnej maszynie

Na lokalnym komputerze dodaj serwer jako remote git:

\# Dodaj remote o nazwie "production"
git remote add production ssh://user@twoj-serwer.pl/home/deploy/app.git

# Wyślij kod i uruchom deploy
git push production main

# Wynik w terminalu:
# === Deploy z gałęzi main ===
# --- composer install ---
# --- artisan migrate + cache ---
# === Deploy zakończony pomyślnie ===

## Zero-downtime deploy przez symlink

Standardowy checkout nadpisuje pliki live — przez kilkanaście sekund aplikacja może być w niespójnym stanie. Bezpieczniejsze podejście to symlink swap (wzorzec Capistrano):

#!/bin/bash
# post-receive — wersja z symlinkami (zero-downtime)

REPO\_DIR="/home/deploy/app.git"
RELEASES\_DIR="/var/www/releases"
CURRENT\_LINK="/var/www/current"
TIMESTAMP=${$(date +%Y%m%d%H%M%S)}
RELEASE\_DIR="$RELEASES\_DIR/$TIMESTAMP"

while read oldrev newrev refname; do
  \[ "${refname##refs/heads/}" = "main" \] || continue

  # Utwórz katalog dla nowego release
  mkdir -p "$RELEASE\_DIR"

  # Checkout do nowego katalogu
  git --work-tree="$RELEASE\_DIR" --git-dir="$REPO\_DIR" checkout -f main

  cd "$RELEASE\_DIR"

  # Build
  composer install --no-dev -q
  php artisan migrate --force
  php artisan config:cache

  # Atomowe przełączenie symlinku (ln -sfn jest atomowe)
  ln -sfn "$RELEASE\_DIR" "$CURRENT\_LINK"

  echo "Deploy $TIMESTAMP aktywny"

  # Zachowaj tylko 5 ostatnich releases
  ls -dt "$RELEASES\_DIR"/\* | tail -n +6 | xargs rm -rf
done

Nginx serwuje z `/var/www/current/public`. Przełączenie symlinku jest atomowe — użytkownicy nie zauważą przerwy. Rollback to jedno polecenie: `ln -sfn /var/www/releases/POPRZEDNI /var/www/current`.

## Zmienne środowiskowe w hooku

Hook post-receive działa w ograniczonym środowisku — PATH może nie zawierać katalogu z `composer` czy `node`. Kilka zasad:

#!/bin/bash
# Na początku hooka — ustaw PATH i zmienne środowiskowe

export PATH="/usr/local/bin:/usr/bin:/bin:/home/deploy/.composer/vendor/bin:$PATH"
export HOME="/home/deploy"
export NVM\_DIR="/home/deploy/.nvm"

# Załaduj nvm jeśli używasz Node.js przez nvm
\[ -s "$NVM\_DIR/nvm.sh" \] && \\. "$NVM\_DIR/nvm.sh"

# Załaduj .env.production zamiast wbudowywania sekretów w hook
if \[ -f "/etc/app/env.production" \]; then
  source /etc/app/env.production
fi

## Obsługa błędów i powiadomienia

#!/bin/bash
set -e

# Przechwytuj błędy i wysyłaj powiadomienie
trap 'on\_error' ERR

on\_error() {
  local EXIT\_CODE=$?
  echo "BLAD: Deploy nieudany (kod $EXIT\_CODE)" >&2

  # Powiadomienie na Slack/Discord
  curl -s -X POST "$SLACK\_WEBHOOK\_URL" \\
    -H "Content-Type: application/json" \\
    -d '{"text": "Deploy FAILED na produkcji! Sprawdz logi."}' || true

  exit $EXIT\_CODE
}

# Logowanie do pliku
exec >>/var/log/deploy.log 2>&1
echo "\[$(date)\] Deploy z commita $newrev"

## Git Hooks vs GitHub Actions — kiedy co wybrać?

Kryterium

Git Hooks

GitHub Actions

Zależności zewnętrzne

Zero — tylko git i SSH

GitHub account, internet

Szybkość deployu

Bardzo szybki (sekundy)

Wolniejszy (runner startup ~30s)

Koszty

Zero (już masz serwer)

Darmowy dla public repos, płatny dla private

Testy przed deployem

Tylko to co wpiszesz w skrypcie

Pełna macierz (node 18/20/22, Ubuntu/Windows)

Deploy na wiele serwerów

Trudniejszy (SSH w pętli)

Łatwy (matrix lub parallel jobs)

Sekrety i klucze API

Pliki na serwerze (/etc/app/)

GitHub Secrets (szyfrowane)

Rollback

Ręczny symlink lub git checkout

Depends on workflow design

Idealny dla

Małe projekty, hobby, VPS solo

Zespoły, open source, multi-env

Git hooks to świetny wybór dla małych projektów na jednym VPS — zero konfiguracji poza serwerem, zero kosztów, maksymalna kontrola. GitHub Actions warto wybrać gdy potrzebujesz testów na wielu środowiskach, deploymentu na wiele serwerów lub integracji z zewnętrznymi serwisami (Slack, Sentry, Datadog).

## Najczęstsze pytania

Czym jest git hook post-receive? +

Post-receive to skrypt wykonywalny umieszczony w katalogu hooks/ repozytorium bare na serwerze. Git uruchamia go automatycznie po każdym git push — możesz w nim umieścić dowolne polecenia: checkout kodu do webroot, instalację zależności, restart serwera aplikacji. Skrypt działa z uprawnieniami użytkownika który push-uje lub właściciela procesu git na serwerze.

Czym jest repozytorium bare i dlaczego jest potrzebne do deploymentu? +

Repozytorium bare (git init --bare) przechowuje tylko historię git bez kopii roboczej plików. Na serwer push-ujesz do repo bare (np. /home/deploy/app.git), a hook post-receive checkout-uje pliki do osobnego katalogu webroot (np. /var/www/app). Nie można push-ować do zwykłego repozytorium z zaznaczoną gałęzią — git odmówi przyjęcia zmian.

Kiedy wybrać git hooks zamiast GitHub Actions? +

Git hooks sprawdzają się przy: małych projektach z jednym serwerem, braku konta GitHub/GitLab, gdy chcesz mieć 100% kontrolę bez zewnętrznych usług, lub gdy GitHub Actions jest zbyt wolny dla częstych deploymentów. GitHub Actions jest lepszy gdy potrzebujesz: testów na wielu wersjach środowiska, powiadomień Slack/email, równoległych pipeline'ów lub deploy na wiele serwerów jednocześnie.

Jak zrobić rollback po nieudanym deployu przez git hook? +

Najbezpieczniejszy rollback to symlink swap: hook wypakuje kod do katalogu releases/$(date +%s)/, a następnie przełącza symlink current → nowy katalog (ln -sfn). Jeśli cokolwiek zawiedzie — wystarczy ln -sfn releases/poprzedni current i reload Nginx. Alternatywnie: trzymaj poprzednią wersję w /var/www/app.prev i po awarii mv app app.broken && mv app.prev app.

## Sprawdź oferty pasujące do tego scenariusza

Poniżej masz szybkie przejścia do ofert i stron z kodami rabatowymi tam, gdzie są dostępne.

Contabo

VPS z pełnym dostępem SSH — idealny do konfiguracji git hooks i własnego CD

Self-hosted CD

[Aktywuj rabat →](/out/contabo)

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/contabo)

Mikrus

Tani VPS do testowania git hooks przed wdrożeniem na produkcji

Dev/Test

[Aktywuj rabat →](/out/mikrus)

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/mikrus)

LH.pl

Hosting z SSH i git — gotowe środowisko bez konfiguracji serwera

Managed

[Aktywuj rabat →](/out/lh-pl)

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/lh-pl)

## Powiązane strony

-   [Git deploy na hostingu — GitHub Actions i SFTP](/baza-wiedzy/git-deploy-hosting)
-   [Node.js Express — deployment na VPS](/baza-wiedzy/nodejs-express-produkcja)
-   [Nginx — load balancer i reverse proxy](/baza-wiedzy/nginx-load-balancer-konfiguracja)
-   [Wszystkie artykuły](/baza-wiedzy/)