Git - Zaawansowane techniki i workflow dla zespołów
Git Zaawansowane techniki
poradnikiGit - Zaawansowane techniki i workflow
Git to zdecydowanie najpopularniejszy system kontroli wersji na swiecie. Wiekszosc programistow zna podstawy - git add, git commit, git push - ale prawdziwa sila Gita kryje sie w zaawansowanych technikach, ktore potrafia radykalnie usprawnic prace zespolu. W tym artykule omowimy strategie branchowania, zaawansowane komendy, automatyzacje za pomoca hookow, konwencje commitow i wiele wiecej.
Strategie branchowania#
Wybor odpowiedniej strategii branchowania to jedna z najwazniejszych decyzji architektonicznych w projekcie. Kazda z popularnych strategii ma swoje zalety i wady, a wybor powinien zalezec od wielkosci zespolu, czestotliwosci deploymentow i specyfiki projektu.
Git Flow#
Git Flow to klasyczna strategia zaproponowana przez Vincenta Driessena. Opiera sie na dwoch glownych galezi - main (produkcja) i develop (rozwoj) - oraz trzech typach galezi pomocniczych.
# Inicjalizacja Git Flow
git flow init
# Rozpoczecie nowej funkcjonalnosci
git flow feature start login-page
# Praca nad funkcjonalnoscia
git add .
git commit -m "feat: add login form component"
# Zakonczenie funkcjonalnosci - merge do develop
git flow feature finish login-page
# Rozpoczecie wydania
git flow release start 1.2.0
# Zakonczenie wydania - merge do main i develop
git flow release finish 1.2.0
# Hotfix na produkcji
git flow hotfix start fix-auth-bug
git flow hotfix finish fix-auth-bug
Zalety Git Flow:
- Jasna separacja kodu produkcyjnego i rozwojowego
- Dobrze sprawdza sie przy zaplanowanych cyklach wydawniczych
- Latwe zarzadzanie hotfixami
Wady Git Flow:
- Zlozonosc - wiele galezi do zarzadzania
- Dlugie cykle integracji moga prowadzic do konfliktow
- Nie nadaje sie do CI/CD z czestymi deploymentami
Trunk Based Development#
Trunk Based Development (TBD) to podejscie, w ktorym wszyscy programisci pracuja na jednej glownej galezi. Krotkotrwale galeze feature (maksymalnie 1-2 dni) sa szybko mergowane z powrotem do trunk.
# Utworzenie krotkiej galezi feature
git checkout -b feature/add-search main
# Szybka iteracja - male commity
git commit -m "feat: add search input component"
git commit -m "feat: add search API integration"
# Czeste rebazowanie na main
git fetch origin
git rebase origin/main
# Szybki merge z powrotem do main
git checkout main
git merge feature/add-search
git push origin main
# Uzywanie feature flags do ukrywania niedokonczonych funkcji
# if (featureFlags.isEnabled('new-search')) { ... }
Zalety TBD:
- Minimalizuje konflikty mergowania
- Idealne dla CI/CD
- Wymusza male, czeste commity
Wady TBD:
- Wymaga dojrzalego zespolu i dobrych praktyk
- Koniecznosc stosowania feature flags
- Trudniejsze zarzadzanie wieloma wersjami
GitHub Flow#
GitHub Flow to uproszczona wersja, idealna dla projektow open source i zespolow stosujacych ciagle dostarczanie.
# Utworzenie galezi z main
git checkout -b feature/user-dashboard main
# Praca i commity
git add .
git commit -m "feat: add user dashboard layout"
git push -u origin feature/user-dashboard
# Utworzenie Pull Request na GitHubie
gh pr create --title "Add user dashboard" --body "Implements #42"
# Po review i zatwierdzeniu - merge przez interfejs webowy
# lub z linii polecen
gh pr merge --squash
Kiedy wybrac ktora strategie?
| Kryterium | Git Flow | TBD | GitHub Flow | |-----------|----------|-----|-------------| | Wielkosc zespolu | Duze zespoly | Male-srednie | Male-srednie | | Cykl wydawniczy | Zaplanowany | Ciagly | Ciagly | | Zlozonosc | Wysoka | Niska | Niska | | CI/CD | Opcjonalne | Wymagane | Zalecane |
Interactive Rebase - przepisywanie historii#
Interactive rebase to jedno z najpotezniejszych narzedzi Gita. Pozwala przepisac historie commitow - laczenie, rozdzielanie, zmiana kolejnosci i edycja komunikatow.
# Interaktywny rebase ostatnich 5 commitow
git rebase -i HEAD~5
# Rebase na galaz main
git rebase -i main
W edytorze zobaczysz liste commitow z dostepnymi akcjami:
pick a1b2c3d feat: add user model
pick d4e5f6g fix: typo in user model
pick g7h8i9j feat: add user controller
pick j1k2l3m feat: add user routes
pick m4n5o6p fix: missing import
# Dostepne komendy:
# p, pick = uzyj commita
# r, reword = uzyj commita, ale edytuj komunikat
# e, edit = uzyj commita, ale zatrzymaj sie do edycji
# s, squash = polacz z poprzednim commitem
# f, fixup = jak squash, ale odrzuc komunikat
# d, drop = usun commit
Typowe zastosowania:
# Polaczenie fixow z glownym commitem (squash)
pick a1b2c3d feat: add user model
fixup d4e5f6g fix: typo in user model
pick g7h8i9j feat: add user controller
pick j1k2l3m feat: add user routes
fixup m4n5o6p fix: missing import
# Zmiana komunikatu commita (reword)
reword a1b2c3d feat: add user model with validation
# Podzielenie commita na mniejsze
edit a1b2c3d feat: add user model and controller
# Po zatrzymaniu:
git reset HEAD~1
git add src/models/user.ts
git commit -m "feat: add user model"
git add src/controllers/user.ts
git commit -m "feat: add user controller"
git rebase --continue
Wazne: Nigdy nie rebazuj commitow, ktore zostaly juz wypchnierte do zdalnego repozytorium i sa wspoldzielone z innymi programistami. Przepisywanie wspoldzielonej historii prowadzi do powaznych problemow.
Cherry-pick - wybieranie commitow#
Cherry-pick pozwala przeniesc pojedynczy commit z jednej galezi do drugiej bez mergowania calej galezi.
# Przeniesienie jednego commita
git cherry-pick a1b2c3d
# Przeniesienie zakresu commitow
git cherry-pick a1b2c3d..f6g7h8i
# Cherry-pick bez automatycznego commita
git cherry-pick --no-commit a1b2c3d
# Rozwiazywanie konfliktow podczas cherry-pick
git cherry-pick a1b2c3d
# ... rozwiaz konflikty ...
git add .
git cherry-pick --continue
# Anulowanie cherry-pick
git cherry-pick --abort
Typowe zastosowania:
- Przenoszenie hotfixow miedzy galeziami
- Selektywne wybieranie zmian z galezi feature
- Backportowanie poprawek do starszych wersji
Git Bisect - szukanie bledow binarnie#
git bisect pomaga znalezc commit, ktory wprowadzil blad, uzywajac wyszukiwania binarnego. Jest niezwykle skuteczny przy dlugiej historii commitow.
# Rozpoczecie sesji bisect
git bisect start
# Oznaczenie aktualnego commita jako blednego
git bisect bad
# Oznaczenie ostatniego znanego dobrego commita
git bisect good v1.0.0
# Git wybierze commit posrodku - przetestuj i oznacz
git bisect good # lub git bisect bad
# Kontynuuj az Git znajdzie winny commit
# ...
# Zakonczenie sesji
git bisect reset
Automatyzacja bisect za pomoca skryptu testowego:
# Automatyczny bisect z komenda testowa
git bisect start HEAD v1.0.0
git bisect run npm test
# Bisect z wlasnym skryptem
git bisect run ./scripts/test-regression.sh
# Skrypt powinien zwrocic 0 (good) lub 1 (bad)
Git Stash - tymczasowe przechowywanie zmian#
Stash pozwala tymczasowo odlozyc niezacommitowane zmiany, aby przejsc do innej pracy.
# Podstawowy stash
git stash
# Stash z opisem
git stash push -m "work in progress: login form"
# Stash wlacznie z nowymi plikami (untracked)
git stash push -u -m "WIP: new feature with new files"
# Lista stashowanych zmian
git stash list
# stash@{0}: On feature/login: work in progress: login form
# stash@{1}: On main: quick experiment
# Przywrocenie ostatniego stasha
git stash pop
# Przywrocenie konkretnego stasha
git stash pop stash@{1}
# Przywrocenie bez usuwania ze stasha
git stash apply stash@{0}
# Podglad zmian w stashu
git stash show -p stash@{0}
# Utworzenie galezi ze stasha
git stash branch feature/from-stash stash@{0}
# Usuniecie stasha
git stash drop stash@{0}
# Wyczyszczenie wszystkich stashowanych zmian
git stash clear
Git Worktrees - rownolegla praca na wielu galeziach#
Worktrees pozwalaja miec jednoczesnie kilka galezi wyciagnietych w roznych katalogach, wspoldzielacych jedno repozytorium .git.
# Dodanie worktree dla istniejacej galezi
git worktree add ../project-hotfix hotfix/critical-bug
# Dodanie worktree z nowa galezi
git worktree add -b feature/new-ui ../project-new-ui main
# Lista aktywnych worktrees
git worktree list
# /home/user/project a1b2c3d [main]
# /home/user/project-hotfix d4e5f6g [hotfix/critical-bug]
# /home/user/project-new-ui g7h8i9j [feature/new-ui]
# Praca w osobnym worktree
cd ../project-hotfix
git add .
git commit -m "fix: critical auth bypass"
git push origin hotfix/critical-bug
# Powrot do glownego katalogu
cd ../project
# Usuniecie worktree
git worktree remove ../project-hotfix
# Porzadkowanie nieistniejacych worktrees
git worktree prune
Zalety worktrees:
- Brak koniecznosci stashowania zmian przy przelaczaniu kontekstu
- Mozliwosc rownoczesnego budowania/testowania roznych galezi
- Wspoldzielony
.git- oszczednosc miejsca na dysku
Git Submodules - zarzadzanie zaleznosciami#
Submodules pozwalaja osadzic jedno repozytorium Git wewnatrz drugiego jako podkatalog.
# Dodanie submodulu
git submodule add https://github.com/org/shared-lib.git libs/shared
# Klonowanie repozytorium z submodulami
git clone --recurse-submodules https://github.com/org/main-project.git
# Inicjalizacja submodulow po klonowaniu bez --recurse
git submodule init
git submodule update
# Aktualizacja submodulu do najnowszej wersji
cd libs/shared
git fetch
git checkout v2.0.0
cd ../..
git add libs/shared
git commit -m "chore: update shared-lib to v2.0.0"
# Aktualizacja wszystkich submodulow
git submodule update --remote --merge
# Usuniecie submodulu
git submodule deinit libs/shared
git rm libs/shared
rm -rf .git/modules/libs/shared
Git Hooks - automatyzacja procesow#
Hooki to skrypty uruchamiane automatycznie w odpowiedzi na zdarzenia Git. Mozna je uzyc do walidacji, formatowania kodu, uruchamiania testow i wielu innych zadan.
Pre-commit hook#
#!/bin/sh
# .git/hooks/pre-commit
# Sprawdzenie formatowania kodem za pomoca Prettier
echo "Running Prettier check..."
npx prettier --check "src/**/*.{ts,tsx,js,jsx}" || {
echo "ERROR: Kod nie jest sformatowany. Uruchom: npx prettier --write ."
exit 1
}
# Uruchomienie lintera
echo "Running ESLint..."
npx eslint "src/**/*.{ts,tsx}" --max-warnings 0 || {
echo "ERROR: Bledy ESLint. Napraw je przed commitem."
exit 1
}
# Sprawdzenie typow TypeScript
echo "Running type check..."
npx tsc --noEmit || {
echo "ERROR: Bledy typow TypeScript."
exit 1
}
echo "All checks passed!"
Commit-msg hook#
#!/bin/sh
# .git/hooks/commit-msg
commit_msg=$(cat "$1")
# Walidacja formatu Conventional Commits
pattern="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?: .{1,72}$"
if ! echo "$commit_msg" | head -1 | grep -qE "$pattern"; then
echo "ERROR: Komunikat commita nie jest zgodny z Conventional Commits."
echo ""
echo "Format: <typ>(<zakres>): <opis>"
echo ""
echo "Typy: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert"
echo ""
echo "Przyklady:"
echo " feat(auth): add OAuth2 login flow"
echo " fix(api): handle null response from payment gateway"
echo " docs: update API documentation"
exit 1
fi
Zarzadzanie hookami za pomoca Husky#
Zamiast recznego zarzadzania hookami w .git/hooks/, mozna uzyc narzedzia Husky:
# Instalacja Husky
npm install -D husky
# Inicjalizacja
npx husky init
# Dodanie pre-commit hooka
echo "npx lint-staged" > .husky/pre-commit
# Konfiguracja lint-staged w package.json
{
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{json,md,yml}": ["prettier --write"]
}
}
Conventional Commits i Semantic Versioning#
Conventional Commits to specyfikacja struktury komunikatow commitow, ktora umozliwia automatyczne generowanie changelogow i zarzadzanie wersjami.
Format Conventional Commits#
<typ>[opcjonalny zakres]: <opis>
[opcjonalne cialo]
[opcjonalne stopki]
Typy commitow i ich wplyw na wersjonowanie:
| Typ | Opis | SemVer |
|-----|------|--------|
| feat | Nowa funkcjonalnosc | MINOR (1.x.0) |
| fix | Naprawa bledu | PATCH (1.0.x) |
| docs | Dokumentacja | - |
| style | Formatowanie | - |
| refactor | Refaktoryzacja | - |
| perf | Optymalizacja wydajnosci | PATCH |
| test | Testy | - |
| build | System budowania | - |
| ci | Konfiguracja CI | - |
| chore | Pozostale | - |
Breaking Changes powoduja zmiane wersji MAJOR (x.0.0):
feat(api)!: change authentication endpoint response format
BREAKING CHANGE: The /auth/login endpoint now returns
a different JSON structure. See migration guide.
Automatyzacja wersjonowania#
# Instalacja semantic-release
npm install -D semantic-release @semantic-release/changelog @semantic-release/git
# Konfiguracja w .releaserc.json
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"@semantic-release/npm",
"@semantic-release/git"
]
}
Strategie monorepo#
Monorepo to podejscie, w ktorym wiele projektow/pakietow znajduje sie w jednym repozytorium. Git oferuje narzedzia, ktore pomagaja w efektywnym zarzadzaniu takimi strukturami.
Sparse Checkout#
# Wlaczenie sparse checkout
git sparse-checkout init --cone
# Wybranie tylko potrzebnych katalogow
git sparse-checkout set packages/frontend packages/shared
# Dodanie kolejnego katalogu
git sparse-checkout add packages/backend
# Lista aktywnych katalogow
git sparse-checkout list
# Wylaczenie sparse checkout
git sparse-checkout disable
Narzedzia do monorepo#
# Turborepo - budowanie tylko zmienionych pakietow
npx turbo run build --filter=...[HEAD~1]
# Nx - analiza zaleznosci
npx nx affected --target=test --base=main
# pnpm workspaces - zarzadzanie zaleznosciami
pnpm install --filter @myorg/frontend
Filtrowanie historii w monorepo#
# Logi tylko dla konkretnego katalogu
git log --oneline -- packages/frontend/
# Diff tylko dla konkretnego pakietu
git diff main -- packages/api/
# Blame dla pliku w pakiecie
git blame packages/shared/src/utils.ts
Git LFS - Large File Storage#
Git LFS rozwiazuje problem przechowywania duzych plikow (grafiki, modele 3D, dane binarne) w repozytoriach Git.
# Instalacja Git LFS
git lfs install
# Sledzenie duzych plikow
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "assets/videos/**"
# Sprawdzenie konfiguracji
cat .gitattributes
# *.psd filter=lfs diff=lfs merge=lfs -text
# *.zip filter=lfs diff=lfs merge=lfs -text
# Dodanie .gitattributes do repozytorium
git add .gitattributes
git commit -m "chore: configure Git LFS for binary files"
# Normalne uzywanie Git - LFS dziala transparentnie
git add assets/logo.psd
git commit -m "feat: add new logo design"
git push
# Sprawdzenie statusu LFS
git lfs status
git lfs ls-files
Podpisywanie commitow (GPG/SSH)#
Podpisywanie commitow pozwala zweryfikowac tozsamosc autora i zapewnia integralnosc kodu.
# Konfiguracja podpisywania GPG
gpg --gen-key
gpg --list-secret-keys --keyid-format=long
# Ustawienie klucza w Git
git config --global user.signingkey ABC123DEF456
git config --global commit.gpgsign true
# Podpisanie commita
git commit -S -m "feat: add verified feature"
# Weryfikacja podpisu
git log --show-signature
# Podpisywanie kluczem SSH (Git 2.34+)
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
# Weryfikacja podpisow SSH
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers
echo "user@example.com ssh-ed25519 AAAA..." >> ~/.ssh/allowed_signers
Plik .gitattributes#
.gitattributes pozwala kontrolowac, jak Git traktuje rozne typy plikow - od konwersji konca linii po strategie mergowania.
# Normalizacja koncow linii
* text=auto
# Wymuszenie LF dla plikow zrodlowych
*.js text eol=lf
*.ts text eol=lf
*.tsx text eol=lf
*.json text eol=lf
*.yml text eol=lf
*.md text eol=lf
# Pliki binarne - bez konwersji
*.png binary
*.jpg binary
*.gif binary
*.ico binary
*.woff2 binary
# Wlasna strategia mergowania dla plikow lock
package-lock.json merge=ours
yarn.lock merge=ours
pnpm-lock.yaml merge=ours
# Roznicowanie plikow binarnych
*.pdf diff=pdf
# Git LFS
*.psd filter=lfs diff=lfs merge=lfs -text
# Eksport - wykluczenie z archiwow
.github/ export-ignore
tests/ export-ignore
.gitignore export-ignore
Zaawansowane strategie mergowania#
Git oferuje rozne strategie mergowania, ktore mozna wybrac w zaleznosci od sytuacji.
# Domyslna strategia (ort w nowszych wersjach)
git merge feature/new-ui
# Merge z zachowaniem historii (no fast-forward)
git merge --no-ff feature/new-ui
# Strategia ours - zachowaj nasza wersje
git merge -s ours legacy-branch
# Merge z preferowaniem naszych zmian przy konfliktach
git merge -X ours feature/conflicting
# Merge z preferowaniem ich zmian przy konfliktach
git merge -X theirs feature/external-update
# Squash merge - jeden commit z calej galezi
git merge --squash feature/many-commits
git commit -m "feat: add complete user management module"
# Octopus merge - scalenie wielu galezi naraz
git merge feature/a feature/b feature/c
Rerere - pamietanie rozwiazanych konfliktow#
# Wlaczenie rerere (reuse recorded resolution)
git config --global rerere.enabled true
# Git zapamietuje, jak rozwiazales konflikty
# i automatycznie zastosuje te same rozwiazania
# gdy napotka identyczne konflikty w przyszlosci
# Podglad zapamietanych rozwiazan
git rerere diff
# Wyczyszczenie cache rerere
git rerere forget <plik>
Rozwiazywanie konfliktow#
Konflikty sa nieuniknione w pracy zespolowej. Oto sprawdzone podejscia do ich rozwiazywania.
# Sprawdzenie statusu konfliktow
git status
# Podglad konfliktow w pliku
# <<<<<<< HEAD
# nasza wersja kodu
# =======
# ich wersja kodu
# >>>>>>> feature/other-branch
# Uzycie narzedzia do mergowania
git mergetool
# Rozwiazywanie z uzyciem konkretnej wersji
git checkout --ours -- src/config.ts # nasza wersja
git checkout --theirs -- src/config.ts # ich wersja
# Anulowanie merge
git merge --abort
# Anulowanie rebase
git rebase --abort
Najlepsze praktyki przy rozwiazywaniu konfliktow:
- Czeste mergowanie/rebazowanie - im czesciej synchronizujesz sie z glowna galezi, tym mniejsze konflikty
- Male commity - latwiej zrozumiec i rozwiazac konflikty w malych zmianach
- Komunikacja w zespole - informuj, gdy pracujesz nad wspolnymi plikami
- Narzedzia wizualne - VS Code, IntelliJ, Beyond Compare ulatwiaja rozwiazywanie zlozonych konfliktow
Przydatne aliasy i konfiguracja#
# Przydatne aliasy
git config --global alias.lg "log --oneline --graph --all --decorate"
git config --global alias.st "status -sb"
git config --global alias.co "checkout"
git config --global alias.br "branch -vv"
git config --global alias.unstage "reset HEAD --"
git config --global alias.last "log -1 HEAD --stat"
git config --global alias.amend "commit --amend --no-edit"
git config --global alias.wip "commit -am 'WIP: work in progress'"
# Przydatna konfiguracja
git config --global pull.rebase true
git config --global push.autoSetupRemote true
git config --global fetch.prune true
git config --global diff.algorithm histogram
git config --global merge.conflictstyle zdiff3
git config --global init.defaultBranch main
git config --global core.autocrlf input
Podsumowanie#
Zaawansowane techniki Git moga znaczaco usprawnic prace zespolu:
- Strategie branchowania - wybierz Git Flow, Trunk Based Development lub GitHub Flow w zaleznosci od potrzeb projektu
- Interactive rebase - utrzymuj czysta, czytelna historie commitow
- Cherry-pick i bisect - precyzyjne zarzadzanie zmianami i szukanie bledow
- Stash i worktrees - efektywne przelaczanie kontekstu
- Hooks - automatyzacja walidacji i kontroli jakosci
- Conventional Commits - ustrukturyzowane komunikaty umozliwiajace automatyzacje
- Git LFS - obsluga duzych plikow binarnych
- Podpisywanie commitow - weryfikacja tozsamosci i integralnosci kodu
Kluczem jest stopniowe wdrazanie tych technik i dostosowywanie ich do specyfiki projektu. Nie trzeba uzywac wszystkiego naraz - zacznij od tego, co przyniesie najwiekszy zysk w Twoim zespole.
Potrzebujesz wsparcia?#
W MDS Software Solutions Group pomagamy w:
- Projektowaniu workflow Git dopasowanego do Twojego zespolu
- Konfiguracji CI/CD z zaawansowanymi strategiami branchowania
- Wdrazaniu Conventional Commits i automatycznego wersjonowania
- Migracji do monorepo i optymalizacji duzych repozytoriow
- Szkoleniach z zaawansowanych technik Git
Skontaktuj sie z nami, aby omowic Twoj projekt!
Zespół ekspertów programistycznych specjalizujących się w nowoczesnych technologiach webowych.