Laptop z kodem na ekranie, przed nim świetlna bariera przepuszczająca część ikon plików; plik z kłódką przechodzi przez barierę

Gitignore nie działa? Plik pewnie jest już śledzony

Sytuacja, którą prędzej czy później spotyka każdy: w repozytorium wylądował plik .env albo katalog z logami. Dopisujesz go do .gitignore, robisz git status i – nic. Git dalej raportuje zmiany w tym pliku, jakby reguły w ogóle nie istniały.

Plik .gitignore działa poprawnie. Po prostu nie robi tego, czego się po nim spodziewasz. Pokażę, skąd bierze się to nieporozumienie, jak w dwie komendy potwierdzić diagnozę i jak wyjść z sytuacji bez kasowania czegokolwiek z dysku.

Dlaczego .gitignore nie działa na ten plik

Reguły z .gitignore dotyczą wyłącznie plików nieśledzonych (untracked). Decydują o tym, czego Git ma nie proponować do dodania. W momencie, w którym plik trafił choć raz do commita, przestaje być kandydatem – jest już częścią repozytorium i Git śledzi go dalej niezależnie od tego, co napiszesz w .gitignore.

To zachowanie jest opisane wprost w dokumentacji: reguły ignorowania nie mają wpływu na pliki znajdujące się już w indeksie. Innymi słowy – dopisanie .env do .gitignore nie jest instrukcją „przestań śledzić ten plik”, tylko „nie zaczynaj go śledzić”.

Diagnoza: sprawdź, czy plik jest śledzony

Zamiast zgadywać, zapytaj Gita wprost. Pierwsza komenda wypisze plik, jeśli jest w indeksie:

git ls-files .env

Jeśli w odpowiedzi zobaczysz ścieżkę pliku – masz sprawcę. Plik jest śledzony i żadna reguła w .gitignore tego nie zmieni.

Druga komenda bywa myląca, więc warto wiedzieć, jak jej używać. git check-ignore pokazuje, która reguła ignoruje dany plik:

git check-ignore -v .env

Dla pliku śledzonego ta komenda nie wypisze nic i zakończy się kodem wyjścia 1 – co łatwo odczytać jako „reguły są zepsute”. Tymczasem check-ignore domyślnie pomija pliki z indeksu, bo dla nich reguły ignorowania i tak nie mają zastosowania. Żeby zobaczyć samą regułę, dodaj --no-index:

git check-ignore -v --no-index .env

Teraz odpowiedź jest konkretna – plik źródłowy reguły, numer linii, sama reguła i sprawdzana ścieżka:

.gitignore:1:.env	.env

Zestawienie obu wyników daje pełny obraz: reguła istnieje i jest poprawna, ale plik jest śledzony, więc reguła go nie dotyczy.

Rozwiązanie: usuń plik z indeksu

Potrzebujesz komendy, która usunie plik z indeksu Gita, ale zostawi go na dysku. Robi to git rm z flagą --cached:

git rm --cached .env
git commit -m "Stop tracking .env"

Po pierwszej komendzie git status pokaże plik jako usunięty:

D  .env

To wpis o usunięciu z repozytorium, nie z systemu plików – .env leży na dysku nietknięty. Po commicie zmiany w tym pliku przestają pojawiać się w git status, bo od tej chwili jest plikiem nieśledzonym, na który wreszcie działa reguła z .gitignore.

Uwaga: Ta zmiana dotknie też inne osoby w projekcie. Gdy ktoś pobierze ten commit, Git usunie plik z jego katalogu roboczego – bo u niego był śledzony i właśnie zniknął z repozytorium. Uprzedź zespół i podeślij wzór pliku, np. .env.example.

Wariant masowy, gdy plików jest więcej

Jeśli .gitignore powstał późno i śledzonych śmieci jest więcej niż jeden plik, prościej wyczyścić cały indeks i zbudować go od nowa – już z uwzględnieniem reguł:

git rm -r --cached .
git add .
git commit -m "Apply gitignore rules to tracked files"

Pierwsza komenda usuwa z indeksu wszystko, druga dodaje z powrotem tylko to, czego .gitignore nie wyklucza. Pliki na dysku pozostają nietknięte, a w commicie wylądują wyłącznie usunięcia tego, co i tak nie powinno było być śledzone.

Przed commitem warto zerknąć na git status i upewnić się, że lista usunięć zawiera to, czego się spodziewasz. Pomaga w tym prompt pokazujący stan repozytorium – opisywałem taką konfigurację we wpisie o promptcie PowerShella z obsługą Gita.

To nie usuwa pliku z historii

Najważniejsze zastrzeżenie i – sądząc po liczbie wyciekających repozytoriów – najczęściej pomijane. git rm --cached zdejmuje plik ze śledzenia od bieżącego commita w przód. Wszystkie wcześniejsze commity nadal go zawierają, razem z zawartością.

Łatwo to sprawdzić – wystarczy sięgnąć do dowolnego starszego commita:

git log --oneline --all -- .env
git show <hash-starszego-commita>:.env

Druga komenda wypisze zawartość pliku sprzed usunięcia. Jeśli był tam klucz API albo hasło do bazy, nadal tam jest i nadal jest do odczytania przez każdego, kto ma dostęp do repozytorium.

Uwaga: Jeśli do repozytorium trafił prawdziwy sekret, potraktuj go jako spalony. Najpierw unieważnij i wygeneruj nowy klucz, dopiero potem zajmij się czyszczeniem historii. Kolejność ma znaczenie – czyszczenie historii nie cofnie tego, że ktoś zdążył sekret pobrać.

Do przepisania historii służy git-filter-repo – narzędzie rekomendowane obecnie przez projekt Git zamiast przestarzałego git filter-branch. Trzeba się liczyć z tym, że operacja zmienia hashe commitów i wymaga wymuszonego push oraz ponownego sklonowania repozytorium przez resztę zespołu. GitHub opisuje całą procedurę w dokumentacji usuwania wrażliwych danych.

Osobna sprawa: jeśli repozytorium jest podpięte pod hosting albo automatyczny deploy, sprawdź też zmienne środowiskowe po stronie usługi. Sekrety powinny mieszkać tam, a nie w plikach repozytorium – pisałem o takiej konfiguracji przy okazji deployu z GitHuba na Netlify.

Dwie inne przyczyny, gdy plik jednak nie jest śledzony

Jeśli git ls-files nic nie zwrócił, problem leży gdzie indziej. Najczęściej w jednej z dwóch rzeczy.

Reguła pochodzi z globalnego .gitignore

Odwrotny objaw: plik jest ignorowany, choć w projektowym .gitignore nie ma o nim ani słowa. Git czyta bowiem także plik globalny, wskazany przez core.excludesfile:

git config --get core.excludesfile

Tu z pomocą przychodzi git check-ignore -v, bo w pierwszej kolumnie podaje pełną ścieżkę do pliku z regułą. Jeśli wskazuje na coś spoza repozytorium – masz odpowiedź. To częsty efekt uboczny konfiguracji przenoszonej między maszynami razem z resztą developerskiego zestawu narzędzi.

Negacja wewnątrz wykluczonego katalogu

Klasyczna pułapka. Chcesz wykluczyć cały build/, ale zachować jeden podkatalog, więc piszesz:

build/
!build/keep/

I nie działa – build/keep/ nadal jest ignorowany. Powód: skoro cały katalog build/ został wykluczony, Git w ogóle do niego nie zagląda, więc nie ma szans zastosować reguły negującej do jego zawartości. Rozwiązaniem jest wykluczenie zawartości katalogu zamiast jego samego:

build/*
!build/keep/

Różnica sprowadza się do jednego znaku, a zmienia wynik – przy build/* Git wchodzi do katalogu i przetwarza jego elementy pojedynczo, dzięki czemu negacja ma na czym zadziałać.

Warto też pamiętać, że przy wielu pasujących regułach wygrywa ostatnia z nich. Jeśli reguły są rozrzucone po pliku, kolejność bywa istotniejsza niż sama treść – a git check-ignore -v i tak wskaże tę, która ostatecznie zadziałała.

Krótka ściąga

  • git ls-files <plik> – czy plik jest śledzony
  • git check-ignore -v --no-index <plik> – która reguła go ignoruje
  • git rm --cached <plik> – przestań śledzić, zostaw na dysku
  • git rm -r --cached . + git add . – przebuduj cały indeks według reguł
  • git config --get core.excludesfile – sprawdź globalny plik reguł

Wszystkie polecenia sprawdzone na Git 2.46. Są stabilne od wielu wersji, więc na starszych instalacjach też zadziałają – szczegóły składni znajdziesz w dokumentacji gitignore, git rm i git check-ignore.

Udostępnij

Zobacz również

Komentarze

Subskrybuj
Powiadom o
guest

0 Komentarze
0
Chętnie poznam Twoje zdanie, proszę o komentarzx