Git LFS w Linuksie – jak okiełznać duże pliki w repozytoriach Git?

Git jest jednym z najważniejszych narzędzi w świecie Linuksa. Trudno wyobrazić sobie współczesny projekt programistyczny bez systemu kontroli wersji, który pozwala śledzić zmiany, wracać do wcześniejszych wersji kodu i wygodnie współpracować z innymi.

Problem zaczyna się wtedy, gdy w repozytorium pojawiają się duże pliki binarne.

Zdjęcia, nagrania audio, materiały wideo, modele 3D, obrazy dysków, archiwa, duże zestawy danych czy pliki projektów graficznych nie zachowują się tak jak kod źródłowy. Git został zaprojektowany przede wszystkim z myślą o efektywnym śledzeniu zmian w plikach, w których można analizować różnice. W przypadku dużych plików binarnych sytuacja wygląda zupełnie inaczej.

I właśnie tutaj pojawia się Git LFS – Git Large File Storage.

To rozszerzenie Gita pozwala nadal wersjonować duże pliki za pomocą znanych poleceń git add, git commit i git push, ale przenosi właściwą zawartość dużych plików poza standardową historię repozytorium. W samym Git przechowywany jest niewielki plik wskaźnikowy, a właściwe dane trafiają do magazynu LFS.

Brzmi ciekawie? Sprawdźmy, jak działa Git LFS i jak skonfigurować go w Linuksie.

Dlaczego duże pliki są problemem dla Gita?

Na pierwszy rzut oka można przecież zrobić coś takiego:

git add film.mp4
git commit -m "Dodano film"
git push

Technicznie Git na to pozwala. Problem polega na tym, że duży plik binarny może bardzo szybko zwiększyć rozmiar repozytorium.

Załóżmy, że mamy plik:

material-promocyjny.mp4

o rozmiarze 500 MB.

Po pewnym czasie poprawiamy film i zapisujemy kolejną wersję. Następnie kolejną. I jeszcze jedną.

W przypadku kodu Git może przechowywać informacje pozwalające efektywnie opisywać różnice między kolejnymi wersjami. Dla dużego pliku binarnego taka analiza nie daje porównywalnych korzyści. W efekcie kolejne wersje mogą znacząco zwiększać rozmiar danych przechowywanych przez repozytorium. GitLab zwraca uwagę, że wielokrotne zmiany dużych plików binarnych mogą z czasem spowalniać takie operacje jak clone, fetch czy pull.

To prowadzi do klasycznego problemu:

mały projekt może mieć bardzo duże repozytorium.

I nie chodzi wyłącznie o zajęte miejsce na serwerze.

Duże repozytorium oznacza również:

  • dłuższe klonowanie,
  • większy transfer danych,
  • większe zużycie miejsca na dysku,
  • dłuższe pobieranie zmian,
  • większy koszt przechowywania historii,
  • problemy z limitami usług hostingowych.

Warto więc zastanowić się, czy każdy plik rzeczywiście powinien trafiać bezpośrednio do standardowego repozytorium Git.

Czym właściwie jest Git LFS?

Git LFS, czyli Git Large File Storage, jest rozszerzeniem Gita przeznaczonym do wersjonowania dużych plików, przede wszystkim binarnych. Jest to projekt open source rozwijany jako rozszerzenie ekosystemu Git.

Najważniejsza różnica polega na sposobie przechowywania danych.

W tradycyjnym Git duży plik jest częścią repozytorium. W Git LFS w repozytorium znajduje się natomiast mały plik wskaźnikowy, który mówi, gdzie znajduje się właściwy obiekt i jaki jest jego identyfikator.

Schemat wygląda więc mniej więcej tak:

                     REPOZYTORIUM GIT
                    ┌─────────────────┐
                    │ kod źródłowy    │
                    │ konfiguracja    │
                    │ .gitattributes  │
                    │ pointer pliku   │
                    └────────┬────────┘
                             │
                             │ odwołanie
                             ▼
                    ┌─────────────────┐
                    │   Git LFS       │
                    │                 │
                    │ duży plik       │
                    │ np. 500 MB      │
                    └─────────────────┘

Dzięki temu Git może nadal zarządzać wersjami pliku, ale nie musi przechowywać jego pełnej zawartości w standardowej strukturze repozytorium.

Oficjalna dokumentacja GitHub opisuje to bardzo podobnie: Git LFS umieszcza w repozytorium referencję do pliku, natomiast jego rzeczywista zawartość znajduje się poza zwykłym repozytorium Git.

Git LFS nie zastępuje Gita

To bardzo ważne.

Git LFS nie jest alternatywnym systemem kontroli wersji. Nie zamiast Gita, lecz razem z Gitem.

Nadal korzystamy z:

git status
git add
git commit
git push
git pull
git clone

Git LFS działa w tle i przejmuje obsługę plików, które oznaczymy jako przechowywane w LFS.

Dzięki temu codzienny workflow praktycznie się nie zmienia.

Instalacja Git LFS w Linuksie

Najpierw potrzebujemy oczywiście Gita.

W Debianie i Ubuntu możemy skorzystać z:

sudo apt update
sudo apt install git git-lfs

W Fedorze:

sudo dnf install git git-lfs

W Arch Linux:

sudo pacman -S git-lfs

Dostępne są również oficjalne pakiety i binaria dla Linuksa.

Po instalacji sprawdźmy:

git lfs version

Powinniśmy otrzymać informację o zainstalowanej wersji programu.

Pierwsza konfiguracja Git LFS

Po instalacji należy aktywować Git LFS dla użytkownika:

git lfs install

To jednorazowa konfiguracja. Oficjalna dokumentacja Git LFS wskazuje właśnie tę komendę jako podstawowy krok przygotowania środowiska.

Możemy teraz przejść do repozytorium:

cd moj-projekt

i sprawdzić status:

git status

Od tego momentu możemy określić, które pliki mają być obsługiwane przez LFS.

Jak powiedzieć Git LFS, które pliki ma przechowywać?

Służy do tego polecenie:

git lfs track

Załóżmy, że nasz projekt zawiera duże pliki wideo:

video/demo.mp4
video/tutorial.mp4
video/prezentacja.mov

Możemy powiedzieć Git LFS, aby obsługiwał wszystkie pliki MP4:

git lfs track "*.mp4"

Albo kilka różnych formatów:

git lfs track "*.mp4"
git lfs track "*.mov"
git lfs track "*.mkv"

Możemy również wskazać konkretny katalog:

git lfs track "assets/video/*"

Podobnie możemy obsłużyć grafiki, modele 3D, archiwa czy inne duże pliki:

git lfs track "*.psd"
git lfs track "*.blend"
git lfs track "*.zip"

Dokładny zestaw rozszerzeń powinien oczywiście zależeć od projektu.

Co robi git lfs track?

To polecenie nie przenosi automatycznie wszystkich istniejących plików do osobnego magazynu.

Modyfikuje przede wszystkim plik:

.gitattributes

Po wykonaniu:

git lfs track "*.mp4"

możemy zobaczyć coś w rodzaju:

*.mp4 filter=lfs diff=lfs merge=lfs -text

Ten plik jest bardzo ważny.

To właśnie .gitattributes informuje Gita, które pliki powinny być obsługiwane przez LFS.

Dlatego po użyciu git lfs track warto sprawdzić:

git status

a następnie dodać .gitattributes do repozytorium:

git add .gitattributes

Dokumentacja GitHub również wykorzystuje git lfs track do przypisywania określonych rozszerzeń do Git LFS.

Dodawanie dużego pliku do repozytorium

Załóżmy, że mamy:

film.mp4

o rozmiarze 1 GB.

Najpierw informujemy LFS:

git lfs track "*.mp4"

Następnie:

git add .gitattributes
git add film.mp4

Tworzymy commit:

git commit -m "Dodano duży plik wideo"

I wysyłamy zmiany:

git push

Na pierwszy rzut oka wygląda to dokładnie tak samo jak normalny workflow Git.

Różnica polega na tym, co dzieje się pod spodem.

Co właściwie znajduje się w repozytorium?

Możemy to łatwo sprawdzić.

Polecenie:

git lfs ls-files

pokaże pliki zarządzane przez Git LFS.

Przykładowo:

a7d3e12a * film.mp4

Możemy też podejrzeć, co Git widzi w pliku:

git show HEAD:film.mp4

Zamiast całego gigabajtowego filmu zobaczymy niewielki tekst przypominający:

version https://git-lfs.github.com/spec/v1
oid sha256:...
size 1048576000

To właśnie pointer Git LFS.

Zawiera między innymi wersję formatu, identyfikator SHA-256 oraz rozmiar właściwego pliku.

I tutaj znajduje się sedno całej technologii.

Git przechowuje mały opis obiektu, a Git LFS zajmuje się jego właściwą zawartością.

Co dzieje się podczas git clone?

Załóżmy, że ktoś pobiera nasze repozytorium:

git clone https://example.com/moj-projekt.git

Git pobiera standardową część repozytorium, w tym wskaźniki LFS.

Następnie Git LFS może pobrać właściwe dane.

Dla użytkownika końcowego wszystko wygląda jednak tak, jakby duży plik normalnie znajdował się w katalogu projektu:

ls -lh

zobaczymy:

-rw-r--r-- 1 user user 1.0G film.mp4

Nie musimy ręcznie zamieniać pointera na plik.

Git LFS wykonuje tę pracę za nas.

Jak sprawdzić, czy wszystko działa?

Przydatne jest polecenie:

git lfs ls-files

Możemy również sprawdzić konfigurację:

git lfs env

To szczególnie pomocne przy diagnozowaniu problemów z serwerem LFS.

Jeżeli chcemy zobaczyć informacje o obiektach LFS:

git lfs status

Te kilka poleceń warto zapamiętać:

git lfs version
git lfs env
git lfs status
git lfs ls-files

Git LFS a git clone

Jeżeli klonujemy repozytorium wykorzystujące LFS, zwykle wystarczy:

git clone URL_REPOZYTORIUM

Git LFS współpracuje z procesem klonowania i pobiera odpowiednie obiekty.

Możemy jednak zdecydować, że nie chcemy od razu pobierać dużych plików.

Przydatne jest wtedy:

GIT_LFS_SKIP_SMUDGE=1 git clone URL_REPOZYTORIUM

W takim przypadku możemy pobrać repozytorium bez automatycznego pobierania właściwej zawartości plików LFS.

Później dane możemy pobrać:

git lfs pull

To może być bardzo przydatne na serwerach, maszynach CI/CD albo komputerach, na których nie potrzebujemy wszystkich dużych zasobów.

Czy można pobierać tylko wybrane pliki?

Tak.

Jedną z przydatnych funkcji Git LFS jest możliwość kontrolowania pobierania obiektów.

Przykładowo:

git lfs fetch

pobiera obiekty do lokalnego magazynu LFS, ale niekoniecznie aktualizuje pliki w katalogu roboczym tak jak pull.

Możemy następnie wykorzystać:

git lfs checkout

aby uzupełnić pliki robocze na podstawie pobranych obiektów.

W przypadku naprawdę dużych repozytoriów warto pamiętać, że Git LFS i git sparse-checkout rozwiązują dwa różne problemy.

sparse-checkout odpowiada przede wszystkim na pytanie:

które katalogi i pliki chcę mieć w moim katalogu roboczym?

Git LFS odpowiada natomiast:

gdzie i jak przechowywać duże obiekty binarne?

Te technologie mogą więc świetnie się uzupełniać.

Git LFS + sparse-checkout

To szczególnie interesujące w dużych projektach.

Wyobraźmy sobie repozytorium:

projekt/
├── src/
├── docs/
├── tests/
├── assets/
│   ├── images/
│   ├── audio/
│   ├── video/
│   └── models/
└── tools/

Git LFS może zarządzać:

assets/video/
assets/audio/
assets/models/

natomiast sparse-checkout może ograniczyć zawartość katalogu roboczego do tego, czego aktualnie potrzebujemy.

Możemy więc połączyć oba rozwiązania:

git lfs track "*.mp4"
git lfs track "*.wav"
git lfs track "*.blend"

oraz:

git sparse-checkout init
git sparse-checkout set src docs

W efekcie otrzymujemy dwa poziomy kontroli:

Git
│
├── sparse-checkout
│   └── kontroluje zawartość katalogu roboczego
│
└── Git LFS
    └── kontroluje sposób przechowywania dużych plików

To bardzo wygodne rozwiązanie w przypadku dużych projektów, w których problemem są jednocześnie rozmiar repozytorium i ogromna liczba plików.

Co jeśli plik został już dodany do zwykłego Gita?

To częsty problem.

Załóżmy, że przez pomyłkę zrobiliśmy:

git add film.mp4
git commit -m "Dodano film"
git push

Dopiero później stwierdziliśmy:

Chwileczkę, ten plik powinien być w Git LFS!

Samo wykonanie:

git lfs track "*.mp4"

nie naprawia automatycznie wcześniejszej historii.

Najpierw możemy oznaczyć plik jako LFS:

git lfs track "*.mp4"

następnie usunąć go z indeksu:

git rm --cached film.mp4

i dodać ponownie:

git add .gitattributes
git add film.mp4

Następnie:

git commit -m "Przenieś film do Git LFS"

Trzeba jednak pamiętać o jednej bardzo ważnej rzeczy:

jeżeli duży plik został już zatwierdzony w historii repozytorium, jego wcześniejsza wersja nadal pozostaje w historii.

Samo dodanie aktualnej wersji do LFS nie zmniejszy magicznie istniejącej historii.

Jeżeli chcemy naprawdę usunąć duże obiekty ze starej historii, potrzebujemy migracji historii.

Migracja istniejącego repozytorium do Git LFS

Git LFS udostępnia do tego między innymi:

git lfs migrate

Przykładowo możemy migrować określone rozszerzenia:

git lfs migrate import --include="*.mp4,*.mov"

Możemy również określić większą liczbę typów:

git lfs migrate import \
  --include="*.mp4,*.mov,*.zip,*.psd,*.blend"

Uwaga: migracja historii zmienia istniejące commity.

Oznacza to, że po wykonaniu takiej operacji SHA commitów może się zmienić, a współpracownicy posiadający stare klony repozytorium będą musieli odpowiednio zsynchronizować swoje kopie.

Nie należy więc uruchamiać git lfs migrate import na współdzielonym repozytorium bez wcześniejszego zaplanowania całej operacji.

Jeżeli repozytorium jest publiczne albo pracuje nad nim większy zespół, temat wymaga szczególnej ostrożności.

Jak znaleźć duże pliki w repozytorium?

Zanim zaczniemy migrację, warto najpierw sprawdzić, co właściwie zajmuje miejsce.

Prostym sposobem jest:

git count-objects -vH

Możemy również wykorzystać:

git verify-pack -v .git/objects/pack/*.idx

a następnie przeanalizować największe obiekty.

W większych projektach warto też skorzystać z narzędzi przeznaczonych do analizy historii Git.

Najważniejsze jest jednak to, aby nie zaczynać migracji w ciemno.

Najpierw znajdźmy problematyczne pliki.

Czy każdy duży plik powinien trafić do LFS?

Nie.

To jeden z najważniejszych punktów całego tematu.

Git LFS najlepiej sprawdza się w sytuacji, gdy plik:

  • jest duży,
  • jest binarny,
  • powinien być wersjonowany razem z projektem,
  • może mieć wiele wersji,
  • jest potrzebny członkom zespołu,
  • powinien być powiązany z konkretną wersją kodu.

Przykładowe zastosowania:

Grafika

*.psd
*.xcf
*.kra
*.blend

Wideo

*.mp4
*.mov
*.mkv

Audio

*.wav
*.flac
*.ogg

Modele 3D

*.fbx
*.obj
*.blend

Duże dane

*.bin
*.dat
*.model

Archiwa

*.zip
*.tar
*.tar.gz

Oczywiście rozszerzenie pliku nie jest jedynym kryterium. Najważniejsze jest to, jak plik jest wykorzystywany w projekcie.

Git LFS nie jest magicznym magazynem na wszystko

Można łatwo dojść do wniosku:

Mam duży plik? Wrzucam go do LFS.

Nie zawsze jest to najlepsze rozwiązanie.

Jeżeli mamy na przykład kilka terabajtów danych naukowych, kopie zapasowe, ogromne zbiory nagrań albo dane generowane automatycznie, Git LFS może nie być właściwym narzędziem.

W takich przypadkach lepiej rozważyć dedykowane rozwiązania do przechowywania danych:

S3 / object storage
NAS
serwer plików
zewnętrzny storage
artefakty CI/CD
repozytorium danych

Git powinien przede wszystkim przechowywać kod i informacje potrzebne do odtworzenia konkretnej wersji projektu.

Git LFS jest świetnym rozwiązaniem, gdy duży plik jest częścią tego procesu wersjonowania.

Nie jest natomiast zamiennikiem dla systemu backupowego ani magazynu danych.

Git LFS a GitHub

Git LFS jest obsługiwany przez popularne platformy hostingowe, między innymi GitHub i GitLab.

W przypadku GitHub warto zwrócić uwagę na limity oraz koszty związane z przechowywaniem i transferem danych. Aktualna dokumentacja GitHub podaje między innymi limit rozmiaru pojedynczego pliku Git LFS wynoszący 5 GB.

To ważna rzecz:

Git LFS nie oznacza, że nagle otrzymujemy nieograniczone miejsce na serwerze.

Nadal obowiązują limity konkretnej platformy.

Dlatego przed wrzuceniem do LFS setek gigabajtów danych należy sprawdzić warunki hostingu, którego używamy.

Jak sprawdzić, które pliki są w LFS?

Najprościej:

git lfs ls-files

Przykładowy wynik:

8f3a12c4 * assets/video/demo.mp4
42b19d7e * assets/models/world.blend
6f9a12a1 * assets/audio/theme.wav

Jeżeli pliku nie ma na tej liście, prawdopodobnie Git traktuje go jak zwykły obiekt.

Możemy też sprawdzić:

git status

oraz:

git lfs status

Jak pobrać wszystkie obiekty LFS?

W niektórych sytuacjach potrzebujemy wszystkich wersji plików LFS.

Możemy użyć:

git lfs fetch --all

Należy jednak uważać z tą opcją.

Jeśli repozytorium ma bardzo długą historię i przez lata przechowywało setki gigabajtów danych, --all może pobrać naprawdę dużo danych.

To świetna opcja do tworzenia lokalnej kopii danych LFS, ale niekoniecznie coś, co chcemy wykonywać na każdym komputerze.

Co dzieje się podczas git push?

Git LFS integruje się z procesem wysyłania zmian.

Gdy wykonujemy:

git push

Git LFS zajmuje się odpowiednimi dużymi obiektami.

Właśnie dlatego nie musimy wykonywać osobnego:

lfs-upload-film

czy innego ręcznego procesu.

Z perspektywy użytkownika nadal jest to Git:

git add .
git commit -m "Aktualizacja projektu"
git push

Git LFS wykorzystuje między innymi mechanizm hooków, aby odpowiednie obiekty zostały wysłane do serwera LFS.

Najczęstszy błąd: LFS jest skonfigurowany, ale plik nadal jest ogromny

To może się zdarzyć.

Sprawdźmy:

git lfs ls-files

Jeśli naszego pliku nie ma na liście, sprawdźmy:

git check-attr filter -- film.mp4

Dla pliku obsługiwanego przez LFS powinniśmy otrzymać:

film.mp4: filter: lfs

Możemy też sprawdzić:

cat .gitattributes

Powinniśmy znaleźć odpowiednią regułę, np.:

*.mp4 filter=lfs diff=lfs merge=lfs -text

Jeżeli jej nie ma, Git LFS nie wie, że dany plik ma być przez niego obsługiwany.

Czy Git LFS spowalnia pracę?

W praktyce celem Git LFS jest właśnie ograniczenie problemów związanych z dużymi plikami.

Oficjalny projekt wskazuje między innymi na szybsze klonowanie i pobieranie danych w repozytoriach zawierających duże pliki, ponieważ ciężkie obiekty są przechowywane poza standardową historią Git.

Nie oznacza to jednak, że transfer gigabajtowego pliku nagle staje się błyskawiczny.

Jeśli aplikacja potrzebuje pobrać:

2 GB

danych, nadal trzeba przesłać 2 GB.

Git LFS pomaga przede wszystkim w organizacji, wersjonowaniu i kontroli tego procesu, a nie w magicznym zmniejszaniu rozmiaru danych.

Git LFS czy .gitignore?

To dwa zupełnie różne mechanizmy.

.gitignore mówi:

Tego pliku nie chcę w repozytorium.

Git LFS mówi:

Ten plik chcę wersjonować, ale jego właściwą zawartość przechowuj poza standardowym repozytorium Git.

Przykład:

node_modules/
*.log
.env

To dobre przypadki dla .gitignore.

Natomiast:

demo.mp4
model.blend
texture.psd
dataset.bin

mogą być dobrymi kandydatami do Git LFS, jeżeli rzeczywiście powinny być częścią repozytorium.

Git LFS czy sparse-checkout?

Tutaj różnica jest jeszcze ciekawsza.

Git sparse-checkout ogranicza to, co znajduje się w katalogu roboczym.

Git LFS zmienia sposób przechowywania dużych plików.

Można to zapamiętać bardzo prosto:

sparse-checkout → CO mam mieć lokalnie?

Git LFS        → JAK przechowywać duże pliki?

Dlatego te technologie się nie wykluczają.

W dużym repozytorium można zastosować obie.

Git LFS czy osobne repozytorium?

To zależy od projektu.

Jeżeli mamy:

projekt/
├── kod
├── konfiguracja
├── dokumentacja
└── kilka dużych modeli

Git LFS będzie bardzo naturalnym rozwiązaniem.

Jeżeli natomiast mamy:

repozytorium/
└── 8 TB danych

to prawdopodobnie problem powinien zostać rozwiązany inaczej.

Warto zadać sobie trzy pytania:

  1. Czy ten plik powinien być wersjonowany?
  2. Czy musi być związany z konkretną wersją kodu?
  3. Czy użytkownicy projektu rzeczywiście potrzebują go w repozytorium?

Jeżeli odpowiedź brzmi „tak” na wszystkie trzy pytania, Git LFS jest bardzo dobrym kandydatem.

Minimalny workflow Git LFS

Jeżeli chcesz zapamiętać tylko podstawy, wystarczy ten zestaw:

1. Instalacja

sudo apt install git-lfs

2. Aktywacja

git lfs install

3. Wybór dużych plików

git lfs track "*.mp4"

4. Dodanie konfiguracji

git add .gitattributes

5. Dodanie pliku

git add film.mp4

6. Commit

git commit -m "Dodano film"

7. Push

git push

8. Kontrola

git lfs ls-files

I to właściwie wszystko, czego potrzeba do rozpoczęcia pracy.

Kilka dobrych praktyk

Na koniec warto zapamiętać kilka zasad.

Nie wrzucaj do LFS wszystkiego

Git LFS powinien rozwiązywać konkretny problem, a nie być domyślnym miejscem dla każdego pliku binarnego.

Nie ignoruj limitów hostingu

To, że plik można przechowywać w LFS, nie oznacza, że hosting zapewnia nieograniczoną przestrzeń i transfer.

Zawsze wersjonuj .gitattributes

Bez tego inni użytkownicy repozytorium mogą nie mieć prawidłowej konfiguracji LFS.

Zanim zmigrujesz historię, zrób kopię

Operacje:

git lfs migrate import

mogą zmienić historię commitów.

Nie traktuj LFS jako backupu

Git LFS przechowuje wersje plików, ale nie zastępuje strategii backupowej.

Łącz LFS z innymi narzędziami

W naprawdę dużych repozytoriach bardzo dobrze może sprawdzić się kombinacja:

Git
 +
Git LFS
 +
sparse-checkout

Każde z tych narzędzi rozwiązuje inny problem.

Podsumowanie

Git jest świetnym narzędziem do wersjonowania kodu, ale duże pliki binarne potrafią szybko zamienić wygodne repozytorium w ciężki i powolny magazyn danych.

Git LFS – Git Large File Storage – rozwiązuje ten problem w elegancki sposób.

Zamiast przechowywać ogromny plik bezpośrednio jako standardowy obiekt Git, repozytorium przechowuje niewielki pointer, natomiast właściwa zawartość trafia do magazynu LFS. Dzięki temu nadal możemy korzystać z normalnego workflow:

git add
git commit
git push
git pull

a jednocześnie unikamy niepotrzebnego obciążania standardowej historii repozytorium.

Największą zaletą Git LFS jest właśnie to, że nie zmusza nas do zmiany sposobu pracy z Gitem.

Jeżeli projekt zawiera duże pliki wideo, audio, grafiki, modele 3D czy inne binarne artefakty, warto rozważyć:

git lfs install
git lfs track "*.mp4"
git add .gitattributes
git add .
git commit -m "Dodano pliki LFS"
git push

A jeśli repozytorium jest naprawdę duże, warto pójść krok dalej i połączyć Git LFS ze sparse-checkout.

Wtedy Git przestaje być problemem zarówno dla ogromnych plików, jak i dla ogromnej liczby plików.

I właśnie wtedy zaczyna się robić naprawdę ciekawie.

About the author

Autor "BIELI" to zapalony entuzjasta otwartego oprogramowania, który dzieli się swoją pasją na blogu poznajlinuxa.pl. Jego wpisy są skarbnicą wiedzy na temat Linuxa, programowania oraz najnowszych trendów w świecie technologii. Autor "BIELI" wierzy w siłę społeczności Open Source i zawsze stara się inspirować swoich czytelników do eksplorowania i eksperymentowania z kodem.