Kurs Git: gałęzie, praca zespołowa, merge i rebase
zweryfikowano 7 września 2026 · 10 min
Utwórz gałąź komendą git switch -c nom, popracuj, a potem scal ją przez git merge z poziomu gałęzi docelowej. Przy konflikcie Git wstawia do pliku znaczniki: wpisz poprawną treść, usuń znaczniki, a następnie git add i git commit. git merge --abort w dowolnym momencie cofa wszystko.
Gałąź to równoległa linia rozwoju. Pozwala pracować nad funkcjonalnością bez ruszania stabilnej wersji, a koledze z zespołu robić to samo u siebie. Ten rozdział obejmuje pełny cykl: utworzenie gałęzi, scalenie jej, ręczne rozwiązanie konfliktu i wybór między merge a rebase.
git switch zamiast git checkout
Historycznie git checkout służył do wszystkiego: zmiany gałęzi, utworzenia nowej, przywrócenia pliku, ustawienia się na konkretnym commicie. To nagromadzenie ról jest pierwszym źródłem zamieszania u początkujących i źródłem wypadków u całej reszty.
Git 2.23, wydany w sierpniu 2019 roku, rozdzielił tę komendę na dwie: git switch do przechodzenia między gałęziami i git restore do wycofywania zmian. Przy wydaniu obie były oznaczone jako eksperymentalne, w oficjalnej dokumentacji już nie są. Ten rozdział ich używa i za każdym razem podaje odpowiednik z checkout, który jeszcze długo będziesz spotykać w kursach i na Stack Overflow.
| Zamiar | Nowoczesna komenda | Dawna forma |
|---|---|---|
| Zmiana gałęzi | git switch nom | git checkout nom |
| Utworzenie gałęzi i przejście na nią | git switch -c nom | git checkout -b nom |
| Powrót do poprzedniej gałęzi | git switch - | git checkout - |
| Cofnięcie zmian w pliku | git restore fichier | git checkout -- fichier |
| Wyjęcie pliku z indeksu | git restore --staged fichier | git reset HEAD fichier |
Utworzenie gałęzi i praca na niej
git switch -c feature/panierSwitched to a new branch 'feature/panier'Gałąź wychodzi od commita, na którym byłeś. Możesz teraz normalnie zmieniać, dodawać i commitować: nic z tego nie pojawi się na main, dopóki tego nie scalisz.
Git nie narzuca żadnej reguły nazewnictwa gałęzi, ale przedrostki feature/, fix/ i hotfix/ to rozpowszechniona konwencja, a interfejsy hostingów grupują je wizualnie.
Żeby zobaczyć, w którym miejscu jesteś:
git branch # lokalne gałęzie
git branch -vv # z ostatnim commitem i śledzoną gałęzią zdalną
git branch -a # lokalne i zdalne
git switch - # powrót do poprzedniej gałęziŻeby opublikować gałąź i pokazać ją zespołowi:
git push -u origin feature/panierPobranie gałęzi kolegi z zespołu
W drugą stronę git fetch aktualizuje twoją wiedzę o serwerze, nie zmieniając niczego w twoich gałęziach:
git fetch origin feature/collegue # konkretna gałąź
git fetch --all # wszystkie zdalne repozytoria
git branch -r # to, co wiesz o serwerze origin/HEAD -> origin/main
origin/feature/collegue
origin/mainZostaje już tylko przejść na tę gałąź. Git sam tworzy gałąź lokalną i wiąże ją z tą z serwera:
git switch feature/colleguebranch 'feature/collegue' set up to track 'origin/feature/collegue'.
Switched to a new branch 'feature/collegue'Kiedy Git odmawia zmiany gałęzi
To jeden z pierwszych błędów, na jakie trafisz:
error: Your local changes to the following files would be overwritten by checkout:
index.html
Please commit your changes or stash them before you switch branches.
AbortingGit chroni twoją pracę: zmieniony przez ciebie plik ma inną zawartość na drugiej gałęzi, a przejście na nią nadpisałoby go. Są trzy wyjścia, w kolejności od najlepszego.
Zacommitować, jeśli praca trzyma się kupy. To prawie zawsze właściwa odpowiedź, niedoskonały commit na gałęzi roboczej nic nie kosztuje i poprawisz go później komendami cofania z poprzedniego rozdziału.
Odłożyć na bok, jeśli praca jest w połowie zrobiona:
git stash # odkłada zmiany na bok
git switch main # …robisz to, co masz do zrobienia…
git switch -
git stash pop # przywraca zmianySaved working directory and index state WIP on main: 6d495d9 Page d accueilWyrzucić, przez git restore ., jeśli zmiany były nic niewarte. Bez możliwości powrotu.
Scalanie gałęzi
Kiedy funkcjonalność jest gotowa, przejdź na gałąź docelową i scal:
git switch main
git merge feature/panierKiedy obie gałęzie zmieniły różne pliki, Git scala sam i o nic nie pyta. Ciekawy jest ten drugi przypadek.
Rozwiązanie konfliktu
Oto sytuacja odtworzona na potrzeby tego rozdziału. Na feature/panier druga linia pliku index.html została zastąpiona komunikatem o pustym koszyku. Na main pierwsza linia została zmieniona, żeby dodać nazwę marki. Obie gałęzie ruszyły ten sam plik.
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.Nic się nie zepsuło. Git scalił, co mógł, a resztę zostawia tobie do rozstrzygnięcia. Pierwsza rzecz do zrobienia: sprawdzić, w którym miejscu jesteś:
git statusOn branch main
Your branch is ahead of 'origin/main' by 1 commit.
(use "git push" to publish your local commits)
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
no changes added to commit (use "git add" and/or "git commit -a")Żeby dostać samą listę plików do obsłużenia:
git diff --name-only --diff-filter=UOtwórz plik. Git wstawił w nim znaczniki:
<<<<<<< HEAD
<h1>Boutique Gekkode</h1>
<p>Bienvenue sur la boutique.</p>
=======
<h1>Boutique</h1>
<p>Votre panier est vide.</p>
>>>>>>> feature/panierCzyta się to mechanicznie. Między <<<<<<< HEAD a ======= znajduje się wersja z gałęzi, na której jesteś, tutaj main. Między ======= a >>>>>>> znajduje się wersja z gałęzi, którą scalasz.
Do ciebie należy napisanie poprawnego wyniku. Niekoniecznie jest nim jedna albo druga wersja: tutaj obie zmiany są dobre i muszą współistnieć.
<h1>Boutique Gekkode</h1>
<p>Votre panier est vide.</p>Usuń wszystkie trzy znaczniki, nie mogą zostać w pliku. Potem daj Gitowi znać, że sprawa jest załatwiona, i zakończ scalanie:
git add index.html
git commit -m "Fusionne feature/panier dans main"* 0899b0c Fusionne feature/panier dans main
|
| * aacf4c0 Panier : message quand le panier est vide
* | 11ff16b Ajoute le nom de la marque au titre
|/
* 6d495d9 Page d accueilCommit scalenia ma dwóch rodziców, co widać na grafie.
Anulować wszystko i zacząć od zera
Jeśli konflikt cię przerasta, nic nie musisz:
git merge --abortRepozytorium wraca dokładnie do stanu sprzed komendy merge. Nic nie ginie, możesz zacząć od nowa później albo omówić sprawę z autorem drugiej gałęzi.
merge czy rebase
Obie komendy włączają pracę z jednej gałęzi do drugiej, ale nie w ten sam sposób.
git merge tworzy commit scalenia, który łączy obie historie. Historia zachowuje dokładny ślad tego, co się wydarzyło, łącznie z tym, że dwie gałęzie istniały równolegle. Graf jest wierny, ale się rozgałęzia.
git rebase odtwarza twoje commity na wierzchu gałęzi docelowej, tak jakbyś pracował od jej ostatniej wersji. Historia zostaje linią prostą, łatwiejszą do czytania, ale zostaje przepisana: twoje commity zmieniają identyfikator.
git switch feature/panier
git rebase mainRebase może napotkać te same konflikty co scalanie, commit po commicie. Rozwiązuje się je tak samo, różni się tylko komenda pozwalająca kontynuować:
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
error: could not apply 4937109... Promo
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Could not apply 4937109... Promogit add index.html
git rebase --continue
# albo, żeby wszystko anulować
git rebase --abortZłota zasada mieści się w jednym zdaniu: nigdy nie rób rebase gałęzi, którą inni już pobrali. Przepisanie współdzielonej historii zmusza kolegów z zespołu do naprawiania własnej ręcznie. Na twojej własnej gałęzi roboczej, zanim ją zaproponujesz, rebase jest natomiast całkowicie na miejscu i daje dużo czytelniejszą historię.
Codzienny przypadek: ktoś wypchnął zmiany przed tobą
Chcesz wypchnąć zmiany, a Git odmawia:
To /root/o.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to '/root/o.git'
hint: Updates were rejected because the remote contains work that you do notSerwer ma commity, których ty nie masz. Musisz je najpierw włączyć. I tu, na świeżym repozytorium, Git zamiast działać zadaje ci pytanie:
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:Od wersji 2.27 Git nie wybiera za ciebie. Odpowiedz raz na zawsze, tak jak proponuje rozdział o instalacji:
git config --global pull.rebase truePrzebieg wygląda wtedy tak:
git pull --rebase
git pushFrom /root/o
622a60b..38b7dc5 main -> origin/main
Rebasing (1/1)Successfully rebased and updated refs/heads/main.
* 5b45117 Ajoute app.js
* 38b7dc5 Ajoute la doc
* 622a60b DepartTwój commit został przeniesiony nad commit kolegi, a historia została liniowa, bez pasożytniczego commita scalenia. To ustawienie warto polecić zespołowi, który zaczyna.
Na koniec ostrzeżenie: nigdy nie próbuj odblokować odrzuconego push komendą git push --force. Nadpisuje ona pracę obecną na serwerze. Jeśli naprawdę musisz wymusić wypchnięcie, po rebase własnej gałęzi, użyj git push --force-with-lease, które odmawia nadpisania commitów, których nie widziałeś.
Sprzątanie
Scalona gałąź nie ma już racji bytu. Jeśli została opublikowana z -u, najpierw wypchnij jej ostatnie commity: Git odmawia usunięcia lokalnej gałęzi wyprzedzającej swoją gałąź zdalną, nawet gdy jest scalona z main.
git push origin feature/panier
git branch -d feature/panierDeleted branch feature/panier (was bc2203a).Bez tego wcześniejszego push komunikat jest jednoznaczny:
warning: not deleting branch 'feature/panier' that is not yet merged to
'refs/remotes/origin/feature/panier', even though it is merged to HEAD
error: the branch 'feature/panier' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D feature/panier'
hint: Disable this message with "git config set advice.forceDeleteBranch false"Jeśli gałąź nie została scalona, Git cię zatrzymuje, co jest przydatną siatką bezpieczeństwa:
error: the branch 'feature/promo' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D feature/promo'
hint: Disable this message with "git config set advice.forceDeleteBranch false"Żeby usunąć gałąź także na serwerze i wyczyścić lokalne referencje, które stały się nieaktualne:
git push origin --delete feature/panier
git fetch --prunegit fetch pobiera stan serwera, nie scalając niczego z twoimi gałęziami, w przeciwieństwie do git pull. Opcja --prune usuwa przy okazji te gałęzie zdalne, które już nie istnieją: te, które koledzy z zespołu scalili i skasowali.
Umiesz już współpracować. Ostatni rozdział dotyczy organizacji: jaki model gałęzi wybrać w zależności od zespołu.
Częste błędy
git stash, zanim zmienisz gałąź.git pull nie wybiera sam między scaleniem a rebase. Rozstrzygnij to przez git config --global pull.rebase true.git pull --rebase. Nigdy nie obchodź tego przez git push --force: nadpisuje pracę innych.<<<<<<<, ======= i >>>>>>> muszą zniknąć z pliku przed git add.