Tento článek patří do seriálu Jak na git. Ostatní články seriálu:
- Jak na git díl 0 - Co, proč, jak?
- Jak na git - díl 1. - git init, remote, config, clone, add, commit, push
- Jak na git - díl 2. - git status, log, checkout, reset
- Jak na git - díl 3. - git revert, stash, diff, clean
- Jak na git - díl 4. - git pull, git fetch, git branch, git merge
- Jak na git - díl 5. - git tag, git cherry-pick a opravy rozbitého gitu
- Jak na git - díl 6. - git rebase a interaktivní rebase
- Git - přidávání částí souborů do commitu
- Git - tutoriály a návody
Oficiální dokumentace k dnešním příkazům: git pull, git fetch, git branch, git merge
Stahování commitů ze serveru
Ve všech předchozích článcích byly popsány možnosti nahrávání commitů, sledování změn, vrácení apod. Pokud ale více lidí pracuje s jedním repozitářem, je potřeba si stáhnout commity ze serveru.
Stejně jako na dveřích je push z jedné strany a pull z druhé, tak i na gitu je nečekaně příkaz git pull. Pokud commity na sebe navazují, git provede fast-forward merge. Pokud na sebe ale nenavazují, vytvoří se merge commit při kterém mohou vzniknout konflikty. O tom níže.
# Stáhne nové commity z hlavního repozitáře, nejčastěji origin git pull # Repozitář lze specifikovat git pull repository_name # Lze upravit merge commit zprávu před vytvořením commitu git pull --edit # Nevytvoří commit, před sloučením lze provést úpravy/inspekci kódu git pull --no-commit # I když lze provést fast-forward merge, provede merge commit git pull --no-ff
Postupnými kroky s git fetch a git merge
Příkaz git pull je ve skutečnosti zkratka pro 2 příkazy git fetch a git merge. Příkaz git fetch stáhne commity ze serveru, ale ponechá je nesloučené se speciálním ukazatelem FETCH HEAD. Poté lze provést samotné sloučení pomocí git merge.
# Stáhne všechny větve z hlavního repozitáře git fetch # Repozitář i větev lze specifikovat git fetch origin master # Smaže všechny reference, které na vzdáleném repozitáři neexistují git fetch --prune
Po stáhnutí ať už jedné nebo více větví, git vypíše, o které větve se jedná. Změny poté lze vysledovat stejně jako v předchozích případech pomocí git log a git diff. Fetchnuté změny lze nyní sloučit pomocí git merge, který je popsán také níže při slučování větví.
# Vypsání všech commitů mezi lokální a vzdálenou master větví git log --oneline master..origin/master # git diff bude také fungovat # Sloučení do aktuální větve vzdálenou větev origin/master git merge origin/master
Více než 1 větev
Mít v gitu jen jednu větev by nebylo moc praktické a byla by to nuda. Proto je možnost vytvářet větví více, navzájem je mezi sebou slučovat, znova větvit apod. Nejčastější větve jsou master (hlavní, produkce) a dev (vývojová). Pro další nové funkcionality se mohou vytvářet nové větve, které se poté slučují do master či dev větve. To již je pak na domluvě každého týmu. Hlavní výhodou je možnost přepínání mezi větvemi, kdy se všechny soubory vždy změní tak, jak by měly v dané větvi vypadat.
Příkaz git branch vytvoří novou větev z aktuálního commitu, a další commit se přidá do té větve, ve které se git nachází. Větev není nic zázračného, jen množství pointerů, podobně jako HEAD. Commit vždy musí mít svého předchůdce, nelze proto vytvořit commit z ničeho a je důležité se rozhodnout, z jakého commitu a jaké větve se nová větev vytvoří.
# Vypíše seznam všech větví (--all přidá vzdálené) git branch --all # Vypíše seznam větví včetně názvu vzdálené, kterou sleduje git branch -vv # Vytvoří novou větev s názvem new_feature, neprovede ale checkout git branch new_feature # Větev vytvoří a přepne se do ní (provede checkout) git checkout -b new_feature # Vymaže větev pouze, pokud pokud je mergnutá do jiné větve git branch -d new_feature # Přejmenuje aktuální větev git branch -m awesome_feature # Přepnutí do existující větve git checkout master
Nahrání větve, nebo commitů do vzdáleného repozitáře
Pokud je vytvořena nová větev, soubory upraveny a vytvořen commit, je potřeba nahrát novou větev na server. Je potřeba také zajistit, aby lokální větev sledovala tu vzdálenou. Pokud lokální větev new_feature sleduje větev origin/new_feature, lze provádět git push a git pull bez dalších parametrů.
# Vytvoří na vzdáleném repozitáři větev se stejným názvem a nastaví # sledování s aktuální větví, 2 možné zápisy git push -u origin git push --set-upstream origin # Nahraje všechny větve git push --all
Stáhnutí nové větve ze vzdáleného repozitáře
Pokud spolupracovník vytvoří větev a nahraje ji do repozitáře, někdy je potřeba si ji stáhnout. K tomu slouží opět zmíněný příkaz git fetch následovaných příkazem checkout.
# Stáhne info ze serveru, včetně nových větví a vypíše jejich názvy git fetch # Přepne do nové větve a automaticky nastaví sledování git checkout new_branch_from_coworker
Slučování a řešení konfliktů
Slučování se provádí pomocí git merge příkazu. Dříve byl využit pro sloučení commitů po fetchi, používá se také pro sloučení dříve rozdělených větví. Je to opět jednoduché, stačí se přepnout do větve, do které je potřeba sloučit jinou větev a poté použít git merge.
# Sloučí větev new_feature do aktuální větve (např master) git merge new_feature # Následující přepínače jsou stejné jako u git pull # Lze upravit merge commit zprávu před vytvořením commitu git merge new_feature --edit # Nevytvoří commit, před sloučením lze provést úpravy/inspekci kódu git merge new_feature --no-commit # I když lze provést fast-forward merge, provede merge commit git merge --no-ff
Fast-forward vs. 3-way merge
Pokud větev, která je slučování přímo navazuje na výslednou, provede se fast-forward merge. Při tomto kroku git pouze přesune pointery na nová místa. Pokud ale v průběhu byly soubory změněny v obou větvích, je potřeba vytvořit merge commit, někdy označován jako 3-way merge. Většinou není potřeba řešit, kterou možnost je potřeba použít, je tu ale ta možnost specifikovat použitou metodu.
Konflikty při slučování
Pokud je více lidmi provedena změna stejného úseku kódu, git nedokáže provést spojení jednotlivých verzí a je potřeba zásah programátora. V takové případě git upozorní, že v souboru je konflikt, označní tento úsek a ponechá k ruční opravě.
git pull # Zobrazí # Auto-merging functions.php # CONFLICT (content): Merge conflict in functions.php # Automatic merge failed; fix conflicts and then commit the result git status # both modified: functions.php
Kód bude vypadat přibližně takto, když 2 lidé změnili stejný řádek.
<<<<<<< HEAD function myAwesomeFunction($params){ ======= function myAwesomeFunction($format, $params){ >>>>>>> e28fbd0a3b987a0d700a79d1d19ae73bf39eff2d
Pokud je potřeba opravdu ruční opravy, nejjednodušší je otevřít editor, kódem se prokousat a opravit jej. Poté soubory přidat pomocí git add a provést commit.
Někdy ale může nastat konflikt i v souborech, které přímo upraveny nebyly, nebo kdysi dávno. V takovém případě lze použít příkazu git checkout a vybrat naši verzi nebo naopak jejich verzi. Při tomto řešení git ignoruje změny v souborech z jedné, nebo druhé strany a vyřeší konflikt ponecháním pouze jedné verze.
# Zahodí změny v "jeho" verzi a ponechá pouze "mou" git checkout functions.php --ours # Naopak pro ponechání pouze "jeho" git checkout functions.php --theirs
Dnešní díl patřil opět mezi ty delší, kdyby něco nebylo jasné, doptejte se v komentářích. Již se pomalu blížíme do finále s gitem.
K tomuto článku již není možné přidávat další komentáře