Terapeuta rasy kaukaskiej siedzi przy stole w pokoju z żabką i laptopem

.gitkeep i .gitignore – czym się różnią i kiedy ich używać?

9 min. czytania

.gitignore i .gitkeep rozwiązują dwa różne problemy: .gitignore mówi Gitowi, czego nie śledzić, a .gitkeep “zmusza” Gita, by śledził pusty katalog. Oba pliki często współpracują w projektach webowych, dbając o porządek w repozytorium, prywatność danych i przewidywalną strukturę aplikacji.

Jak Git traktuje pliki i katalogi

Zrozumienie różnicy między .gitignore a .gitkeep zaczyna się od sposobu, w jaki Git śledzi zawartość repozytorium:

  • w systemie kontroli wersji Git śledzone są pliki, a nie katalogi jako takie,
  • jeśli katalog jest pusty, Git go ignoruje – nie zostanie dodany do repozytorium,
  • katalog trafia do repozytorium dopiero wtedy, gdy zawiera co najmniej jeden plik (nawet pusty).

Skutek w praktyce: jeśli w projekcie utworzysz np. public/uploads/ na przyszłe pliki użytkowników, ale katalog jest pusty, to po git add . i git commit ten folder w ogóle nie trafi do repozytorium.

To jedno z miejsc, gdzie pojawia się .gitkeep.

Czym jest .gitignore?

.gitignore to oficjalna funkcja Gita – plik tekstowy, w którym określasz, które pliki lub katalogi mają być ignorowane przy git status, git add i git commit. Git rozpoznaje nazwę .gitignore i interpretuje jej zawartość zgodnie ze swoją składnią wzorców.

Jak działa .gitignore

Najważniejsze zasady działania to:

  • wpisujesz w nim wzorce pasujące do plików i katalogów,
  • wszystko, co pasuje do wzorców, jest traktowane jako ignorowane,
  • reguły mogą działać globalnie (na cały projekt) lub lokalnie w konkretnych podkatalogach – możesz mieć wiele plików .gitignore w jednym repozytorium.

Oto typowe wpisy dla projektu webowego:

# Zbudowane pliki frontendu
dist/
build/

# Zależności Node.js
node_modules/

# Pliki środowiskowe z sekretami
.env
.env.local

# Pliki IDE i systemowe
.vscode/
.idea/
.DS_Store
Thumbs.db

Takie reguły:

  • zmniejszają rozmiar repozytorium,
  • przyspieszają operacje Gita,
  • ograniczają ryzyko przypadkowego wrzucenia danych wrażliwych (np. kluczy API, danych logowania itp.) do repozytorium.

Dla bezpieczeństwa i prywatności w .gitignore możesz zadbać, aby nie commitować plików z danymi osobowymi czy eksportami logów.

Czym jest .gitkeep?

.gitkeep nie jest oficjalną funkcją Gita. To wyłącznie umowna nazwa pliku–placeholdera, którą społeczność przyjęła do śledzenia pustych katalogów. Git nie ma żadnej specjalnej logiki związanej z nazwą .gitkeep; traktuje go jak zwykły plik – znaczenie nadajemy mu my (konwencja zespołu).

Jak działa .gitkeep w praktyce

Postępuj według poniższych kroków:

  1. Utwórz katalog, np. public/uploads/.
  2. Dodaj w nim plik: public/uploads/.gitkeep.
  3. Katalog przestaje być pusty, więc Git może go śledzić i doda go do repozytorium.

Plik może być pusty lub może zawierać krótki komentarz wyjaśniający jego rolę. Nazwa też może być dowolna (np. .keep, .placeholder, README.md), ale .gitkeep stało się najpopularniejszym wzorcem.

.gitignore vs .gitkeep – kluczowe różnice

Poniższa tabela zbiera najważniejsze różnice między tymi plikami:

Cecha .gitignore .gitkeep
Status w Git Oficjalna funkcja, opisana w dokumentacji. Nieoficjalna konwencja społeczności.
Znaczenie nazwy Nazwa ma specjalne znaczenie – Git rozumie .gitignore. Nazwa nie ma specjalnego znaczenia – to zwykły plik.
Główny cel Wskazuje pliki/katalogi, które Git ma ignorować. Umożliwia śledzenie pustych katalogów.
Rodzaj działania Aktywnie wpływa na zachowanie Gita (status, add, commit). Pasywny placeholder – “działa”, bo zapełnia katalog.
Składnia Obsługuje wzorce (glob, ścieżki, negacje). Nie ma specjalnej składni – zawartość jest dowolna.
Zakres Może istnieć wiele plików .gitignore w projekcie; może też być globalny. Zwykle umieszczany wewnątrz konkretnego katalogu, który chcesz śledzić.
Typowy użytek Ochrona przed śledzeniem artefaktów builda, zależności, sekretów. Zachowanie struktury katalogów (np. uploads/, logs/, tmp/).

Przykłady z projektów webowych

Typowe zastosowania .gitignore

W projektach front‑ i back‑endowych .gitignore najczęściej wykorzystasz do poniższych celów:

  • Ignorowanie zależności – katalogi node_modules/ (Node.js) i vendor/ (PHP/Composer);
  • Ignorowanie artefaktów builda – katalogi dist/, build/, .next/, .nuxt/, public/build/ itd.;
  • Ignorowanie plików z sekretami i konfiguracjami lokalnymi – pliki .env, .env.local, config/local.php itp.;
  • Ignorowanie plików IDE i systemowych – katalogi/pliki .idea/, .vscode/, *.swp, .DS_Store, Thumbs.db.

Dzięki temu:

  • repozytorium pozostaje lżejsze i czytelniejsze,
  • każdy członek zespołu instaluje zależności lokalnie zamiast pobierać je z Gita,
  • dane wrażliwe i pliki lokalne nie wyciekają przypadkiem do historii repozytorium.

W kontekście dostępności i ochrony prywatności w .gitignore możesz uwzględnić np. storage/exports/, backups/, logs/, aby nie commitować plików z realnymi danymi użytkowników.

Typowe zastosowania .gitkeep

.gitkeep wykorzystaj, gdy katalog jest (lub bywa) pusty, ale musi istnieć w repozytorium, bo:

  • aplikacja lub framework zakłada jego obecność,
  • CI/CD, skrypty deployu lub testy oczekują konkretnej struktury katalogów,
  • chcesz jasno pokazać strukturę projektu innym programistom.

Najczęściej dotyczy to takich ścieżek:

  • public/uploads/ – na pliki wgrywane przez użytkowników (awatar, dokumenty, wideo),
  • storage/cache/, storage/logs/, tmp/ – na cache, logi, pliki tymczasowe,
  • public/media/ – na media generowane dynamicznie,
  • .well-known/acme-challenge/ – katalog wykorzystywany przez Let’s Encrypt / ACME.

Aby dodać pusty katalog do repozytorium, wykonaj:

mkdir -p public/uploads
touch public/uploads/.gitkeep
git add public/uploads/.gitkeep
git commit -m "Dodaj katalog public/uploads z plikiem .gitkeep"

Dzięki temu:

  • nowy developer po git clone widzi gotową strukturę katalogów (nawet jeśli jeszcze nikt nic nie wgrał),
  • backend i frontend nie muszą tworzyć katalogów “w locie” przy pierwszym zapisie pliku,
  • łatwiej zrozumieć, gdzie w projekcie lądują pliki użytkowników czy logi.

Wspólne użycie – śledzimy katalog, ignorujemy jego zawartość

Bardzo częsty wzorzec w projektach webowych wygląda tak:

Katalog ma zawsze istnieć w repozytorium,
ale nie chcemy śledzić żadnych plików, które się w nim pojawią.

Typowy przykład to public/uploads/:

  • katalog jest potrzebny (aplikacja zapisuje tam pliki),
  • pliki wewnątrz często zawierają dane osobowe, których nie chcesz mieć w Git,
  • jednocześnie chcesz, by katalog był utworzony od razu po klonowaniu repozytorium.

Rozwiązanie wdrożysz w dwóch krokach:

  1. W katalogu umieść .gitkeep, by katalog był śledzony.
  2. W .gitignore dodaj reguły, które ignorują wszystkie pliki wewnątrz tego katalogu, z wyjątkiem .gitkeep.

Przykładowa konfiguracja:

# Ignoruj wszystkie pliki w public/uploads/
public/uploads/*

# ...ale nie ignoruj samego .gitkeep
!public/uploads/.gitkeep

Katalog public/uploads/ będzie obecny w repozytorium, ponieważ zawiera .gitkeep. Każdy inny plik w tym katalogu będzie ignorowany (nie pojawi się w git status).

To świetny wzorzec z punktu widzenia dostępności i ochrony prywatności:

  • struktura projektu jest jasna,
  • nie grozi przypadkowe wrzucenie realnych danych użytkowników (np. dokumentacji medycznej, nagrań audio z danymi osobowymi) do repozytorium,
  • audyty bezpieczeństwa (również w kontekście RODO) są prostsze, bo dane użytkowników nie trafiają do historii Gita.

Czy zamiast .gitkeep można użyć .gitignore w pustym katalogu?

Niektórzy programiści tworzą w pustym katalogu plik .gitignore z komentarzem i regułą gwiazdki:

# Ten katalog jest potrzebny, ale jego zawartość ma być ignorowana
*

Technicznie to działa:

  • katalog przestaje być pusty (Git może go śledzić),
  • reguła * ignoruje wszystkie pliki w katalogu,
  • komentarz wyjaśnia intencję.

Problem polega na tym, że nazwa .gitignore sugeruje “ignorowanie”, a nie “zachowaj katalog”; ten sam plik zaczyna pełnić dwie role naraz – placeholdera i konfiguracji ignorowania, co bywa mylące dla nowych osób w zespole.

Z tego powodu wiele zespołów woli używać .gitkeep jako czystego placeholdera, a logikę ignorowania trzymać w głównym .gitignore (lub w .gitignore bezpośrednio w katalogu, ale z jasnymi komentarzami).

Obie metody są poprawne – najważniejsze to ustalić jednolitą konwencję w projekcie i opisać ją (np. w CONTRIBUTING.md).

Dobre praktyki dla .gitignore i .gitkeep w projektach webowych

1. Traktuj .gitignore jak część architektury projektu

Oto zalecenia, które uporządkują repozytorium i zwiększą bezpieczeństwo:

  • przemyśl listę reguł – dopasuj ją do używanego stacku (Node.js, PHP, Python, Ruby, Java itd.);
  • ignoruj zależności – np. node_modules/, vendor/;
  • ignoruj artefakty builda – np. dist/, build/, .next/, .nuxt/;
  • ignoruj pliki environment – np. .env, .env.*;
  • ignoruj lokalne pliki IDE i systemowe – np. .idea/, .vscode/, .DS_Store, Thumbs.db;
  • dodawaj komentarze – przy mniej oczywistych regułach, aby ułatwić pracę zespołowi.

2. Wykorzystaj .gitignore do ochrony prywatności użytkowników

Ignoruj katalogi, w których mogą pojawiać się realne dane użytkowników (np. exports/, backups/, logs/, uploads/). W połączeniu z .gitkeep utrzymasz niezbędną strukturę katalogów, nie trzymając w repozytorium wrażliwych plików.

3. Czytelnie oznaczaj katalogi techniczne .gitkeep-em

Aby uniknąć nieporozumień, stosuj spójne oznaczenia:

  • używaj jednej, spójnej nazwy (np. wszędzie .gitkeep),
  • w razie potrzeby dodaj do .gitkeep krótki komentarz (np. # Ten plik utrzymuje katalog w repozytorium),
  • nie nadużywaj .gitkeep – używaj go tam, gdzie katalog faktycznie powinien istnieć.

4. Unikaj typowych błędów

Te wskazówki oszczędzą ci kłopotów i nadpisywania historii:

  • nie commituj plików z sekretami – jeśli już tak się stało, usuń je z historii Gita (np. git filter-repo) i natychmiast przegeneruj klucze,
  • nie zakładaj, że .gitignore działa wstecz – plik zacommitowany wcześniej pozostanie w historii,
  • nie używaj .gitkeep do “oznaczania ważnych katalogów” bez powodu – jego rola to techniczne utrzymanie pustego katalogu w repozytorium.

Kiedy używać którego pliku – szybkie podsumowanie praktyczne

Poniższa tabela ułatwia szybki wybór właściwego podejścia:

Użyj Kiedy Przykłady
.gitignore gdy czegoś nie chcesz w repozytorium oraz chcesz chronić prywatność i bezpieczeństwo dist/, build/, node_modules/, .env, pliki IDE
.gitkeep gdy katalog ma być widoczny nawet, gdy jest pusty uploads/, logs/, tmp/, katalogi cache wymagane przez framework
oba naraz gdy katalog powinien istnieć, ale zawartość ma być ignorowana public/uploads/, storage/logs/ + reguły folder/* i !folder/.gitkeep