Git: Jak używać .gitignore i .gitkeep?

gitignore vs gitkeep

Jeśli pracujesz z gitem, masz swoje repozytoria na platformie typu Github, Gitlab, Bitbucket etc, zapewne widujesz pliki „z kropkami”  takie jak .gitignore czy .gitkeep. Czym są i czym się od siebie różnią? Postaram się, krótko wyjaśnić.

Czym jest plik .gitignore?

Pracując z repozytorium Git, szybko zauważysz, że niektóre pliki i foldery są zbędne. Możesz napotkać pliki dodawane automatycznie przez edytor, pliki tymczasowe, czy pliki ze zmiennymi środowiskowymi, których w żadnym wypadku nie chcesz udostępniać publicznie.

Tu pojawia się specjalny plik o nazwie .gitignore, umieszczony zazwyczaj bezpośrednio w głównym katalogu naszego repozytorium.

Plik .gitignore pozwala nam wykluczyć z repozytorium te elementy, które są zbędne, czy to pliki konfiguracyjne, tymczasowe, czy dane osobowe. Innymi słowy:

W Git, plik .gitignore służy do określania, które pliki lub katalogi proces śledzenia zmian powinien ignorować.

Dzięki .gitignore, programiści mogą unikać przypadkowego dodawania niepożądanych plików do repozytorium. Nasze repozytorium pozostaje czyste i uporządkowane, a historia zmian nie zostaje zanieczyszczona przez nieistotne pliki.

Aby pliki były ignorowane należy przestrzegać konwencji jaką znajdzeimy w oficjalnej dokumentacji Gita jako Patterns.

Przykładowo, dodając wzorzec *.log do pliku .gitignore, zapobiegamy śledzeniu wszelkich plików logów.

Szablony .gitignore dla różnych języków programowania

Tutaj znajdziecie gotowe szablony gitignore dla różnych technologii i języków np. Python, Java, Kotlin, Go i wiele innych: https://github.com/github/gitignore/tree/main. Jeśli czegoś nie znajdziesz w tym projekcie, na pewno ktoś już taki szablon przygotował. Wystarczy dobrze poszukać 😉

Warto też zaznaczyć, że istnieją dwa podejścia do używania plików .gitignore:

  • 1 – każde repozytorium powinno zawierać ustandaryzowany plik .gitignore, który będzie ignorował wszystkie pliki specyficzne dla języka, systemu operacyjnego i narzędzi, których używają jego programiści (np. pycache), oraz wszelkie pliki usuwane z powodów biznesowych (np. pliki danych, pliki za duże dla repozytorium).
  • 2 – programista powinien być odpowiedzialny za własny osobisty plik .gitignore, który będzie ignorował wszystkie niepotrzebne pliki repozytorium związane z językami i narzędziami, których aktualnie używa. Jeśli w repozytorium znajduje się plik .gitignore, jest on tam, aby uwzględnić logikę specyficzną dla danego repozytorium

Czym jest plik .gitkeep?

W przeciwieństwie do .gitignore, .gitkeep nie jest częścią oficjalnej dokumentacji Gita. To nieoficjalna konwencja stosowana przez użytkowników Gita, służąca do śledzenia pustych katalogów. Git domyślnie nie śledzi pustych katalogów – nie dodaje ich do naszego repozytorium .gitkeep jest sposobem na obejście tego ograniczenia.

Słowem, chcemy przekazać Gitowi informację:

Hej, ten folder jest ważny, nawet jeśli na razie jest pusty.

Skoro jest to konwencja, a nie część narzędzia Git, to warto zauważyć, że nie nazwa a położenie jest tu najważniejsze. Sam plik używany do śledzenia pustego katalogu może mieć dowolną nazwę – nie musi to być koniecznie .gitkeep. Można wybrać nazwy takie jak .empty, czy po prostu .keep albo jakąkolwiek inną. Ważne jest, aby plik ten umieścić bezpośrednio w pustym katalogu, który chcemy śledzić w repozytorium. Tym sposobem przestaje on być pusty 😉

.gitignore vs .gitkeep

Z jednej strony .gitkeep, eleganckie i proste rozwiązanie do śledzenia pustych katalogów. Z drugiej strony .gitignore, który poza swoją główną rolą, może też posłużyć do tego celu. Wybór zależy od kontekstu projektu.

W jaki sposób śledzić pusty folder przez gitignore?

Możemy utworzyć plik .gitignore w pustym folderze, a następnie dodaj zgodnie z wzorcem z dokumentacji następujące linie:

# Ignoruj wszystko w tym katalogu
*
# Ale nie ignoruj tego pliku .gitignore
!.gitignore

* – gwiazdka oznacza, że wszystkie pliki w katalogu są ignorowane
oprócz pliku .gitignore, który wykluczyliśmy za pomocą ! znaku wykrzyknika, odpowiadającego za zaprzeczenie.
Skoro plik .gitignore jest śledzony, cały katalog również będzie śledzony przez Git.

Następnie wystarczy tę zmianę dodać do Gita, jak zawsze i zatwierdzić

git add "path/to/empty_directory/.gitignore"
git commit -m "Add empty directory"

Co ważne, rozwiązanie to zadziała również, nie dla pustego folderu!

Tym sposobem możemy dodać do repozytorium jako pusty katalog, folder, który zawierał pliki, ale z jakiegoś powodu chcemy, tych plików nie śledzić. Folder w Git nie jest pusty – zawiera plik .gitignore w środku.

W jaki sposób śledzić jako pusty folder przez .gitignore razem z .gitkeep, gdy folder zawiera lokalnie jakieś pliki?

Czy ma to sens? Tak, chociaż nie często się przydaje.
Metoda przyda się jeśli:

  • chcesz mieć w repozytorium katalog, ale bez plików się w nim znajdujacych np. folder logów systemu, ale bez plików logów, które interesują cię tylko lokalnie
  • chcesz wysłać do repozytorium git strukturę katalogów, zanim będą w niej pliki np. będą dodane później, ale strukture chcesz zdefiniować już teraz

W jaki sposób śledzić folder, który już ma pliki lokalnie, ale zdalnie ma pozostać pusty?

Poprzedni punkt, po części odpowiedział już na to pytanie, ale nie podoba nam się tamto rozwiązanie, ponieważ mamy dwa pliki .gitignore, a chcemy jednak te pliki rozróżnić.

W folderze tworzymy plik .gitkeep, aby śledzić dany folder w Git, oraz dodajemy linie do pliku .gitignore, aby zignorować wszystkie pliki wewnątrz naszego folderu.

Jak używać .gitignore i .gitkeep razem? – krok po kroku

1. Załóżmy, że mamy w projekcie folder logs. W folderze tym mamy różne pliki systemowe, których nie chcemy dodawać do naszego zdalnego repozytrium.

app
│   .gitignore
│   index.html
│   script.js
│
├───images
│
└───logs
    │   2452321.log
    │   2453111.log

2. W folderze logs, należy utowrzyć pusty plik .gitkeep lub .keep (nazwa to tylko konwencja).

app
│   .gitignore
│   index.html
│   script.js
│
├───images
│
└───logs
    │   .gitkeep
    │   2452321.log
    │   2453111.log

3. Teraz, jeśli chcemy móc śledzić folder, ale nie jego zawartość – co ma sens dla logów, dodaj następującą zawartość do pliku .gitignore

# Ignoruj wszystko wewnątrz folderu logs
logs/*
# Nie ignoruj pliku .gitkeep w folderze logs
!logs/.gitkeep

Tada! 🎉 Możemy zacommitować zmiany i dodać do repozytorium. Nasz pliki wewnątrz folderu logs nie pojawią się online.

Dajcie znać, czy korzystacie z gitignore i gitkeep w swoich projektach.