15%

Zaoszczędź 15% na wszystkich usługach hostingowych

Sprawdź swoje umiejętności i zdobądź Rabat na dowolny plan hostingowy

Użyj kodu:

Skills
Rozpocznij
14.10.2024

Git Kontrola Wersji: Kompletny Techniczny Przewodnik dla Programistów

Git to rozproszony system kontroli wersji (DVCS), który rejestruje migawki drzewa plików projektu w czasie, umożliwiając dowolnej liczbie współpracowników pracę równoległą bez nadpisywania wzajemnych zmian. Każdy programista posiada pełną kopię repozytorium — wraz z całą historią commitów — na swoim lokalnym komputerze, eliminując pojedynczy punkt awarii i umożliwiając w pełni offline’owe przepływy pracy.

Stworzony przez Linusa Torvaldsa w kwietniu 2005 roku jako zamiennik BitKeepera do rozwoju jądra Linux, Git został zaprojektowany od podstaw wokół trzech niepodważalnych wymagań: szybkości, integralności danych i wsparcia dla nieliniowych, rozproszonych przepływów pracy. Te cele projektowe nadal definiują to, co sprawia, że Git jest kategorycznie różny od swoich poprzedników i dlaczego pozostaje dominującym VCS przez ponad dwie dekady.

Jak Git różni się od scentralizowanej kontroli wersji

Zrozumienie architektury Gita wymaga bezpośredniego porównania z systemami scentralizowanymi, takimi jak Subversion (SVN) lub CVS, gdzie jeden autorytatywny serwer przechowuje kanoniczne repozytorium, a programiści pobierają płytkie kopie robocze.

WymiarGit (rozproszony)SVN (scentralizowany)
Model repozytoriumPełny klon na każdym węźleCienka kopia robocza, historia na serwerze
Możliwość pracy offlinePełny commit, branch, diff, logTylko odczyt; commity wymagają serwera
Koszt tworzenia gałęziBliski zeru (manipulacja wskaźnikiem)Kosztowne kopiowanie katalogu
Pojedynczy punkt awariiBrak — każdy klon może przywrócićAwaria serwera wstrzymuje wszystkie commity
Strategia scalaniaScalanie trójstronne + rebaseTylko scalanie trójstronne
Integralność historiiHaszowanie zawartości SHA-1/SHA-256Sekwencyjne numery rewizji
Zależność od sieciTylko dla push/pull/fetchPrawie każda operacja
Częściowe pobranieNieobsługiwane natywnieObsługiwane (sparse checkout)
Krzywa uczenia sięStroma krzywa na początkuŁagodniejsza dla weteranów SVN
Adopcja (2024)~95% profesjonalnych zespołówStarsze środowiska korporacyjne

Model rozproszony oznacza, że nawet jeśli platforma hostingowa, taka jak GitHub, doświadczy awarii, lokalny klon każdego programisty jest kompletną, autorytatywną kopią zapasową całej historii projektu.

Podstawowa architektura: co Git faktycznie przechowuje

Git nie przechowuje diffów. Przechowuje migawki. Każdy commit wskazuje na obiekt drzewa reprezentujący pełny stan każdego śledzonego pliku w danym momencie. Jeśli plik nie zmienił się między dwoma commitami, Git przechowuje wskaźnik do poprzedniego bloba zamiast go duplikować — w ten sposób Git osiąga zarówno kompletność, jak i efektywność przechowywania.

Cztery podstawowe typy obiektów w magazynie obiektów Gita (.git/objects/) to:

  • Blob — surowa zawartość pliku, adresowana przez hash SHA
  • Tree — lista katalogów mapująca nazwy plików na hashe blobów lub poddrzew
  • Commit — wskaźnik do drzewa, zero lub więcej commitów nadrzędnych, metadane autora i wiadomość
  • Tag — opatrzony adnotacją wskaźnik do konkretnego commita, używany jako znacznik wydania

Każdy obiekt jest niezmienny i adresowany przez zawartość. Zmiana jednego bajtu w dowolnym pliku powoduje całkowicie inny hash SHA, który kaskadowo propaguje się przez obiekty drzewa i commita. Dlatego historia Gita jest kryptograficznie odporna na manipulacje — nie można po cichu zmienić przeszłego commita bez zmiany każdego kolejnego hasha commita.

Obszar staging (zwany też indeksem, przechowywany w .git/index) to plik binarny przechowujący proponowany następny commit. Ten model trzech stref — katalog roboczy, indeks, repozytorium — jest najbardziej niezrozumianą cechą architektoniczną Gita i źródłem większości zamieszania u początkujących.

Instalacja i konfiguracja Gita

Przed uruchomieniem jakichkolwiek poleceń zweryfikuj instalację i skonfiguruj swoją tożsamość. Git osadza informacje o autorze w każdym obiekcie commita, a błędnie skonfigurowana tożsamość jest jedną z najczęstszych przyczyn nieuporządkowanych historii commitów we współdzielonych repozytoriach.

# Verify installation
git --version

# Set global identity (stored in ~/.gitconfig)
git config --global user.name "Your Name"
git config --global user.email "you@example.com"

# Set default branch name to 'main' (modern convention)
git config --global init.defaultBranch main

# Set preferred editor for commit messages
git config --global core.editor "vim"

# Enable colored output
git config --global color.ui auto

# Verify configuration
git config --list

Konfiguracja jest warstwowa: --system (wszyscy użytkownicy, /etc/gitconfig), --global (bieżący użytkownik, ~/.gitconfig) i --local (repozytorium, .git/config). Bardziej szczegółowe zakresy nadpisują szersze.

Podstawowe polecenia Gita: kompletny przewodnik

Inicjalizacja i klonowanie

git init tworzy nowe repozytorium, zapisując katalog .git/ w bieżącym folderze. Nie tworzy żadnych commitów — repozytorium zaczyna się puste.

git init
git init my-project        # Initialize into a new subdirectory
git init --bare repo.git   # Bare repository (no working tree, used for servers)

Repozytorium bare zawiera tylko magazyn obiektów i referencje — bez katalogu roboczego. To właściwy format dla zdalnego repozytorium, do którego wielu programistów wykonuje push. Jeśli samodzielnie hostujesz Gita na serwerze VPS Hosting, zawsze inicjalizuj współdzielone repozytoria jako bare.

git clone tworzy pełną lokalną kopię zdalnego repozytorium, w tym wszystkie gałęzie, tagi i historię.

git clone https://github.com/user/repo.git
git clone git@github.com:user/repo.git          # SSH transport (preferred for auth)
git clone --depth 1 https://github.com/user/repo.git  # Shallow clone (latest commit only)
git clone --branch develop https://github.com/user/repo.git  # Clone specific branch

Płytkie klony (--depth) są przydatne w potokach CI/CD, gdzie potrzebny jest tylko najnowszy stan, a nie pełna historia. Znacznie skracają czas klonowania dużych repozytoriów, ale uniemożliwiają niektóre operacje zależne od historii, takie jak git bisect.

Sprawdzanie stanu

git status to najczęściej uruchamiane polecenie w każdym przepływie pracy. Pokazuje stan trzech stref repozytorium.

git status
git status -s    # Short format: two-column status codes
git status -sb   # Short format with branch info

git diff porównuje zawartość między strefami lub commitami.

git diff                    # Working directory vs. index (unstaged changes)
git diff --staged           # Index vs. last commit (what will be committed)
git diff HEAD               # Working directory vs. last commit (all changes)
git diff main..feature      # Compare tips of two branches
git diff abc123..def456     # Compare two specific commits
git diff --stat             # Show changed files and line counts only

git log przechodzi przez graf commitów. Jego opcje filtrowania należą do najpotężniejszych i najrzadziej używanych funkcji Gita.

git log
git log --oneline --graph --decorate --all   # Visual branch graph
git log -p                                   # Show patch (diff) for each commit
git log --author="Jane"                      # Filter by author
git log --since="2 weeks ago"               # Filter by date
git log --grep="fix:"                        # Filter by commit message pattern
git log -- path/to/file                      # History of a specific file
git log --follow -- path/to/file             # Follow renames

Kombinacja --graph --oneline --decorate --all jest tak powszechnie przydatna, że większość inżynierów tworzy dla niej alias:

git config --global alias.lg "log --oneline --graph --decorate --all"

Staging i commitowanie

git add filename.py          # Stage a specific file
git add src/                 # Stage an entire directory
git add .                    # Stage all changes in current directory
git add -p                   # Interactive patch staging (stage hunks, not whole files)
git add -u                   # Stage modifications and deletions, but not new files

Interaktywny staging (git add -p) to jedna z najpotężniejszych i najrzadziej używanych funkcji Gita. Pozwala przeglądać i selektywnie dodawać do stagingu poszczególne fragmenty w pliku, umożliwiając precyzyjne, atomowe commity nawet gdy katalog roboczy zawiera wiele niezwiązanych ze sobą zmian.

git commit -m "feat: add OAuth2 token refresh logic"
git commit --amend           # Modify the most recent commit (message or content)
git commit --amend --no-edit # Amend content without changing the message
git commit -v                # Open editor showing full diff of staged changes

Kluczowa zasada: Nigdy nie zmieniaj commitów, które zostały już wypchnięte do współdzielonego zdalnego repozytorium. Zmiana przepisuje hash commita, zmuszając współpracowników do wykonania rebase lub resetu lokalnych gałęzi.

Push i pull

git push origin main
git push origin feature/auth     # Push a specific branch
git push -u origin feature/auth  # Push and set upstream tracking
git push --force-with-lease      # Safer force push (fails if remote has new commits)
git push origin --delete old-branch  # Delete a remote branch
git push --tags                  # Push all local tags

Preferuj --force-with-lease zamiast --force gdy musisz przepisać zdalną historię. Sprawdza, czy nikt inny nie wykonał push od czasu ostatniego fetch, zapobiegając przypadkowej utracie danych.

git pull origin main
git pull --rebase origin main    # Fetch and rebase instead of merge
git pull --ff-only               # Only fast-forward; abort if a merge commit would be created

git fetch pobiera zdalne zmiany bez dotykania katalogu roboczego ani bieżącej gałęzi. To bezpieczny sposób na sprawdzenie zmian upstream przed ich integracją.

git fetch origin
git fetch --all          # Fetch from all remotes
git fetch --prune        # Remove remote-tracking branches that no longer exist upstream

Gałęzie i scalanie: podstawowy przepływ pracy

Model gałęzi Gita to jego najbardziej znacząca architektonicznie cecha. Gałąź to po prostu nazwany wskaźnik (plik 41-bajtowy w .git/refs/heads/) do hasha commita. Tworzenie gałęzi jest natychmiastowe niezależnie od rozmiaru repozytorium.

Zarządzanie gałęziami

git branch                        # List local branches
git branch -a                     # List all branches (local and remote-tracking)
git branch -v                     # List branches with last commit info
git branch feature/user-auth      # Create a new branch
git branch -d feature/user-auth   # Delete merged branch
git branch -D feature/user-auth   # Force delete (even if unmerged)
git branch -m old-name new-name   # Rename a branch

Przełączanie gałęzi

Nowoczesny Git (2.23+) rozdziela funkcje git checkout na dwa dedykowane polecenia:

git switch main                   # Switch to existing branch
git switch -c feature/payments    # Create and switch in one step
git restore filename.py           # Discard working directory changes to a file
git restore --staged filename.py  # Unstage a file (remove from index)

git checkout nadal działa dla wszystkich tych przypadków, ale git switch i git restore mają jaśniejszą, mniej niejednoznaczną semantykę i powinny być preferowane w nowoczesnych przepływach pracy.

Strategie scalania

git merge feature/user-auth           # Standard merge (creates merge commit if needed)
git merge --no-ff feature/user-auth   # Always create merge commit (preserves branch topology)
git merge --squash feature/user-auth  # Squash all branch commits into one staged change
git merge --abort                     # Abort an in-progress conflicted merge

Scalanie fast-forward następuje, gdy gałąź docelowa nie rozeszła się ze źródłową — Git po prostu przesuwa wskaźnik do przodu. Nie jest tworzony żaden commit scalania. --no-ff wymusza commit scalania nawet w tym przypadku, co zachowuje wizualną historię gałęzi funkcji w git log --graph.

Scalanie squash sprowadza wszystkie commity z gałęzi funkcji do jednej zestawionej zmiany, którą następnie ręcznie commitujemy. Daje to czystą liniową historię w main, ale usuwa szczegółową historię commitów gałęzi funkcji.

Rebase

git rebase odtwarza commity z jednej gałęzi na szczycie innej, przepisując ich hashe w celu stworzenia liniowej historii.

git rebase main                  # Rebase current branch onto main
git rebase -i HEAD~5             # Interactive rebase: edit last 5 commits
git rebase --onto main server client  # Transplant client branch onto main, excluding server
git rebase --abort               # Abort a rebase in progress
git rebase --continue            # Continue after resolving a conflict

Interaktywny rebase (-i) to narzędzie do dbania o higienę commitów dla profesjonalistów. Pozwala zmieniać kolejność, łączyć, edytować, usuwać lub dzielić commity przed ich udostępnieniem. Typowy przypadek użycia: porządkowanie nieuporządkowanej gałęzi funkcji przed otwarciem pull requesta.

StrategiaHistoriaPrzypadek użyciaRyzyko
Scalanie (domyślne)Nieliniowa, zachowuje gałęzieDługotrwałe gałęzie funkcjiHałaśliwy `git log`
Scalanie `–no-ff`Nieliniowa, jawne commity scalaniaWymuszona topologia gałęziJak wyżej
Scalanie `–squash`Liniowa, jeden commit na funkcjęCzysta gałąź głównaUtrata szczegółowej historii
RebaseLiniowa, bez commitów scalaniaGałęzie osobiste, porządkowanie przed PRPrzepisuje hashe; niebezpieczne na współdzielonych gałęziach
Cherry-pickSelektywna, liniowaBackportowanie poprawekZduplikowane commity między gałęziami

Złota zasada rebase: Nigdy nie wykonuj rebase commitów istniejących na publicznej, współdzielonej gałęzi. Rebase przepisuje hashe commitów. Jeśli współpracownik oparł swoją pracę na tych commitach, jego historia się rozejdzie i będzie musiał ją ręcznie pogodzić.

Rozwiązywanie konfliktów scalania

Konflikty występują, gdy dwie gałęzie modyfikują ten sam obszar tego samego pliku. Git oznacza konflikt w pliku standardowymi znacznikami konfliktu:

<<<<<<< HEAD
const timeout = 30000;
=======
const timeout = 60000;
>>>>>>> feature/increase-timeout

Przepływ pracy przy rozwiązywaniu konfliktów:

# After a conflicted merge or rebase
git status                    # Identify conflicted files (marked as "both modified")
# Edit each conflicted file, remove markers, keep correct content
git add resolved-file.js      # Mark as resolved
git commit                    # Complete the merge (message is pre-populated)

W przypadku złożonych konfliktów narzędzie do scalania trójstronnego zapewnia wyraźniejszy widok:

git mergetool                 # Launch configured merge tool (vimdiff, meld, etc.)
git config --global merge.tool vimdiff

Cofanie zmian: macierz decyzyjna

Wybór niewłaściwego polecenia cofania to jeden z najczęstszych sposobów, w jakie programiści tracą pracę lub uszkadzają współdzieloną historię. Właściwy wybór zależy od dwóch zmiennych: gdzie zmiana się znajduje i czy została wypchnięta.

ScenariuszPoleceniePrzepisuje historięBezpieczne na współdzielonej gałęzi
Usuń plik ze stagingu`git restore –staged file`NieTak
Odrzuć zmiany w katalogu roboczym`git restore file`NieTak
Cofnij ostatni commit, zachowaj zmiany w stagingu`git reset –soft HEAD~1`TakNie
Cofnij ostatni commit, zachowaj zmiany poza stagingiem`git reset HEAD~1`TakNie
Cofnij ostatni commit, odrzuć wszystkie zmiany`git reset –hard HEAD~1`TakNie
Bezpieczne cofnięcie wypchnięrego commita`git revert <hash>`NieTak
Usuń plik z całej historii`git filter-repo`TakNie
git reset --soft HEAD~1      # Undo commit, keep changes in index
git reset HEAD~1             # Undo commit, keep changes in working dir
git reset --hard HEAD~1      # Undo commit, discard all changes permanently

git revert abc1234           # Create new commit that inverts abc1234
git revert HEAD~3..HEAD      # Revert last 3 commits (creates 3 revert commits)
git revert -n HEAD~3..HEAD   # Stage the reversals without committing (batch revert)

git reset --hard jest nieodwracalne przez normalne polecenia Gita. Jeśli przypadkowo je uruchomisz, jedyną ścieżką odzyskiwania jest git reflog, który rejestruje każdą pozycję, na którą wskazywał HEAD przez około 90 dni.

git reflog                   # Show HEAD movement history with hashes
git checkout -b recovery abc1234  # Recover by creating a branch at the lost commit

Zaawansowane polecenia dla produkcyjnych przepływów pracy

git stash

git stash zapisuje bieżący stan katalogu roboczego i indeksu na stosie, dając czysty katalog roboczy do zmiany kontekstu.

git stash                        # Stash tracked changes
git stash -u                     # Include untracked files
git stash push -m "WIP: auth refactor"  # Stash with a descriptive name
git stash list                   # List all stash entries
git stash pop                    # Apply most recent stash and remove it from stack
git stash apply stash@{2}        # Apply specific stash without removing it
git stash drop stash@{2}         # Delete a specific stash entry
git stash branch feature/wip     # Create a new branch from a stash

git cherry-pick

git cherry-pick abc1234                    # Apply a single commit to current branch
git cherry-pick abc1234 def5678            # Apply multiple commits
git cherry-pick abc1234 --no-commit        # Apply changes without committing
git cherry-pick main~3..main              # Apply a range of commits

Cherry-pick to standardowy mechanizm backportowania poprawek błędów do gałęzi konserwacyjnych. Jeśli naprawisz krytyczną lukę bezpieczeństwa w main, wykonujesz cherry-pick tego commita do v2.1-stable i v2.0-stable bez scalania niepowiązanych funkcji.

git bisect

git bisect wykonuje wyszukiwanie binarne przez historię commitów, aby znaleźć dokładny commit, który wprowadził błąd. To jedno z najpotężniejszych i najmniej znanych narzędzi debugowania Gita.

git bisect start
git bisect bad                   # Mark current commit as broken
git bisect good v2.3.0           # Mark a known-good commit or tag
# Git checks out the midpoint commit automatically
# Test your code, then:
git bisect good                  # If this commit is fine
git bisect bad                   # If this commit is broken
# Repeat until Git identifies the first bad commit
git bisect reset                 # Return to original HEAD when done

W repozytorium z 1000 commitami między dobrym a złym punktem, git bisect znajduje winowajcę w co najwyżej 10 krokach.

git tag

Tagi oznaczają konkretne commity jako znaczące — zazwyczaj wersje wydań.

git tag v1.4.2                          # Lightweight tag (just a pointer)
git tag -a v1.4.2 -m "Release 1.4.2"   # Annotated tag (recommended; stores metadata)
git tag -a v1.4.2 abc1234              # Tag a specific past commit
git push origin v1.4.2                 # Push a specific tag
git push origin --tags                 # Push all tags
git tag -d v1.4.2                      # Delete local tag
git push origin --delete v1.4.2        # Delete remote tag

Zawsze używaj tagów z adnotacjami dla wydań. Przechowują imię i nazwisko osoby tagującej, adres e-mail, datę i wiadomość, a także mogą być podpisane GPG. Lekkie tagi są odpowiednie tylko dla tymczasowych lokalnych zakładek.

git worktree

git worktree umożliwia jednoczesne pobranie wielu katalogów roboczych z tego samego repozytorium — każdy na innej gałęzi. Eliminuje to potrzebę stashowania lub commitowania pracy w toku, gdy trzeba przełączyć się na hotfix.

git worktree add ../hotfix-branch hotfix/critical-auth-bug
git worktree list
git worktree remove ../hotfix-branch

Jest to szczególnie cenne na Serwerze Dedykowanym uruchamiającym potok CI/CD, gdzie wiele zadań kompilacji potrzebuje jednoczesnego dostępu do różnych gałęzi tego samego repozytorium bez wzajemnych zakłóceń.

Przepływy pracy Git dla zespołów

Właściwa strategia gałęzi zależy od rytmu wydań i wielkości zespołu. Istnieją trzy dominujące modele:

Przepływ pracy z gałęziami funkcji

Każda funkcja lub poprawka żyje na własnej gałęzi. Programiści otwierają pull requesty, aby scalić z main. Prosty, skuteczny dla większości zespołów.

Gitflow

Definiuje długotrwałe gałęzie main i develop, plus krótkotrwałe gałęzie feature/, release/ i hotfix/ ze ścisłymi regułami scalania. Odpowiedni dla oprogramowania z jawnymi wydaniami wersjonowanymi (biblioteki, aplikacje pakietowe).

Trunk-Based Development

Programiści commitują bezpośrednio do main (lub używają bardzo krótkotrwałych gałęzi scalanych w ciągu dnia). W dużej mierze opiera się na flagach funkcji, aby ukryć niekompletną pracę. Preferowany przez zespoły o wysokiej prędkości praktykujące ciągłe wdrażanie.

Przepływ pracyRytm wydańWielkość zespołuZłożoność CI/CD
Gałąź funkcjiElastycznyDowolnaNiska
GitflowZaplanowane wydaniaŚredni–DużyŚrednia
Trunk-BasedCiągłe wdrażanieDowolnaWysoka

Hosting repozytoriów Git: samodzielny hosting vs. zarządzane platformy

Dla zespołów wymagających suwerenności danych, zgodności lub prywatnej infrastruktury, samodzielny hosting serwera Git jest realnym i często koniecznym wyborem. Opcje obejmują Gitea (lekka, oparta na Go), GitLab CE (pełna platforma DevOps) i Forgejo (fork Gitea z zarządzaniem społecznościowym).

Minimalna samodzielnie hostowana instancja Gitea działa wygodnie na planie VPS Hosting z 2 vCPU i 2 GB RAM. Dla większych zespołów lub GitLab CE z runnerami CI, 4–8 GB RAM to praktyczne minimum.

Przy samodzielnym hostingu zabezpiecz swój serwer Git za pomocą:

  • Uwierzytelniania kluczem SSH (całkowicie wyłącz uwierzytelnianie hasłem)
  • HTTPS z ważnym certyfikatem — Certyfikaty SSL są niezbędne do ochrony poświadczeń podczas transmisji
  • Reguł zapory sieciowej ograniczających ekspozycję portu Git (22 lub niestandardowy port SSH, 443 dla HTTPS)
  • Regularnych automatycznych kopii zapasowych katalogów bare repozytorium .git
  • Sekretów webhook dla integracji CI/CD

Dla zespołów używających potoków wdrożeniowych opartych na Git, które zarządzają również infrastrukturą webową, połączenie samodzielnie hostowanego serwera Git z VPS z cPanel daje zintegrowane hooki wdrożeniowe obok znanych narzędzi do zarządzania hostingiem.

Hooki Git: automatyzacja bramek jakości

Hooki Git to skrypty wykonywane automatycznie w określonych punktach cyklu życia Gita. Znajdują się w .git/hooks/ i domyślnie nie są commitowane do repozytorium (użyj narzędzia takiego jak pre-commit lub husky, aby je udostępniać).

Kluczowe hooki dla produkcyjnych przepływów pracy:

HookWyzwalaczTypowe zastosowanie
`pre-commit`Przed utworzeniem commitaUruchamianie linterów, formaterów, testów
`commit-msg`Po napisaniu wiadomości commitaWymuszanie formatu conventional commit
`pre-push`Przed push do zdalnegoUruchamianie pełnego zestawu testów
`post-receive`Po odebraniu push przez zdalneWyzwalanie wdrożenia, wysyłanie powiadomień
`pre-rebase`Przed rozpoczęciem rebaseZapobieganie rebase współdzielonych gałęzi
# Example pre-commit hook: reject commits with debug print statements
#!/bin/bash
if git diff --cached | grep -E '^+.*(console.log|debugger|print("DEBUG)'; then
  echo "ERROR: Debug statement detected. Remove before committing."
  exit 1
fi

Hook post-receive na serwerowym repozytorium bare to podstawa prostego wdrożenia opartego na Git: push na serwer, hook pobiera nowy HEAD do katalogu webowego, uruchamia kroki kompilacji i restartuje usługi — bez zewnętrznej platformy CI.

.gitignore: utrzymywanie repozytoriów w czystości

Plik .gitignore informuje Git, które pliki i wzorce mają pozostać nieśledzone. Powinien być commitowany do repozytorium i starannie utrzymywany.

# Dependencies
node_modules/
vendor/

# Build artifacts
dist/
build/
*.o
*.pyc
__pycache__/

# Environment and secrets — NEVER commit these
.env
.env.local
*.pem
*.key
config/secrets.yml

# IDE files
.idea/
.vscode/
*.swp

# OS files
.DS_Store
Thumbs.db

Krytyczna pułapka: Jeśli plik był już śledzony przed dodaniem do .gitignore, Git będzie go nadal śledzić. Musisz jawnie zaprzestać jego śledzenia:

git rm --cached path/to/sensitive-file
git commit -m "chore: stop tracking secrets file"

Nigdy nie commituj poświadczeń, kluczy API ani kluczy prywatnych do repozytorium — nawet prywatnego. Używaj zmiennych środowiskowych, menedżerów sekretów (HashiCorp Vault, AWS Secrets Manager) lub plików .env, które są dodane do .gitignore.

Dostrajanie wydajności dla dużych repozytoriów

Standardowy Git pogarsza się w repozytoriach z milionami plików lub gigabajtami zasobów binarnych. Strategie łagodzenia:

  • Git LFS (Large File Storage): Zastępuje duże pliki binarne plikami wskaźnikowymi w repozytorium i przechowuje rzeczywistą zawartość na oddzielnym serwerze LFS. Niezbędne dla repozytoriów zawierających media, wagi modeli ML lub skompilowane pliki binarne.
  • Częściowe klonowanie: git clone --filter=blob:none pobiera commity i drzewa, ale pobiera bloby na żądanie. Znacznie zmniejsza rozmiar początkowego klonu dla dużych monorepozytoriów.
  • Sparse checkout: git sparse-checkout set path/to/subdir pobiera tylko podzbiór drzewa roboczego. Przydatne w monorepozytoriach, gdzie programista pracuje tylko w jednym katalogu usługi.
  • Plik commit-graph: git commit-graph write --reachable wstępnie oblicza graf commitów, przyspieszając operacje takie jak git log --graph i zapytania o osiągalność w dużych historiach.
  • git maintenance start: Planuje zadania konserwacji w tle (pakowanie luźnych obiektów, aktualizacje commit-graph, prefetch fetch), aby z czasem utrzymać szybkość operacji na repozytorium.

Techniczna lista kontrolna kluczowych wniosków

Przed uznaniem konfiguracji Git za gotową do produkcji zweryfikuj każdy z poniższych punktów:

  • Skonfigurowana tożsamość: user.name i user.email ustawione poprawnie w odpowiednim zakresie konfiguracji
  • Używane klucze SSH: Uwierzytelnianie hasłem do zdalnych zastąpione parami kluczy SSH lub HTTPS opartym na tokenach
  • Commitowany .gitignore: Sekrety, artefakty kompilacji i pliki systemowe wykluczone przed pierwszym commitem
  • Domyślna gałąź nazwana main: init.defaultBranch ustawione globalnie, aby uniknąć starszego nazewnictwa master
  • Wiadomości commitów zgodne z konwencją: Conventional Commits (feat:, fix:, chore:) lub format uzgodniony przez zespół wymuszany przez hook commit-msg
  • git revert dla publicznej historii: git reset --hard używany tylko na lokalnych, niewypchnietych commitach
  • --force-with-lease zamiast --force: Zapobiega przypadkowemu nadpisaniu pushów współpracowników
  • Tagi z adnotacjami dla wydań: git tag -a z wiadomością, nie lekkie tagi
  • Hooki udostępniane przez pre-commit lub husky: Bramki jakości egzekwowane spójnie w całym zespole
  • Skonfigurowany Git LFS, jeśli repozytorium zawiera zasoby binarne powyżej 1 MB
  • Repozytorium bare na serwerze: Samodzielnie hostowane zdalne inicjalizowane z git init --bare
  • Regularne git fetch --prune: Gałęzie śledzące zdalne utrzymywane w synchronizacji z rzeczywistym stanem zdalnym

Często zadawane pytania

Jaka jest różnica między git fetch a git pull?

git fetch pobiera commity, gałęzie i tagi ze zdalnego do lokalnych referencji śledzących zdalne (np. origin/main) bez dotykania katalogu roboczego ani bieżącej gałęzi. git pull to git fetch natychmiast po którym następuje git merge (lub git rebase jeśli skonfigurowane). Używaj git fetch, gdy chcesz sprawdzić zmiany upstream przed ich integracją.

Kiedy powinienem używać git rebase zamiast git merge?

Używaj rebase, aby zlinearyzować lokalną gałąź funkcji przed otwarciem pull requesta, zachowując czytelność historii projektu. Nigdy nie wykonuj rebase gałęzi, którą inni programiści już sklonowali lub oparli na niej swoją pracę — przepisywanie opublikowanych hashy commitów zmusza wszystkich innych do ręcznego pogodzenia rozeszłych historii.

Jak trwale usunąć wrażliwy plik, który został przypadkowo commitowany?

Użyj git filter-repo (nowoczesnego zamiennika git filter-branch): git filter-repo --path secrets.env --invert-paths. Przepisuje to całą historię repozytorium, usuwając plik z każdego commita. Po przepisaniu wymuś push wszystkich gałęzi i tagów, a następnie natychmiast zmień ujawnione poświadczenia — zakładaj, że są skompromitowane niezależnie od tego, jak szybko działasz.

Czym jest stan odłączonego HEAD i jak się z niego wyjść?

Odłączony HEAD oznacza, że wskaźnik HEAD odwołuje się bezpośrednio do konkretnego hasha commita, a nie do nazwy gałęzi. Wszelkie commity, które wykonasz, nie będą należeć do żadnej gałęzi i staną się nieosiągalne po przełączeniu. Aby wyjść: git switch -c new-branch-name, aby przypisać commity do nowej gałęzi, lub git switch main, aby je odrzucić.

Jak Git obsługuje pliki binarne inaczej niż pliki tekstowe?

Git przechowuje pliki binarne jako nieprzezroczyste bloby — nie może obliczać znaczących diffów na poziomie linii ani wykonywać automatycznych scaleń na nich. Konflikty w plikach binarnych muszą być rozwiązywane przez wybór jednej wersji w całości. W przypadku repozytoriów ze znaczącymi zasobami binarnymi skonfiguruj Git LFS, aby przechowywać pliki binarne zewnętrznie i utrzymywać samo repozytorium lekkim i szybkim.

15%

Zaoszczędź 15% na wszystkich usługach hostingowych

Sprawdź swoje umiejętności i zdobądź Rabat na dowolny plan hostingowy

Użyj kodu:

Skills
Rozpocznij