Git

Z Wikiknih
Přejít na: navigace, hledání

Git je systém správy verzí – slouží k udržování informací, jak byly v průběhu času měněny zdrojové soubory ve stromě adresářů, který odpovídá určitému softwarovému projektu. Některé systémy správy verzí umožňují efektivně sledovat změny pouze jednoho souboru, ale získání stavu projektu v minulosti je velmi pomalé; git je naproti tomu schopen velmi efektivně nastavit obsah celého pracovního stromu na stav po provedení libovolného commitu.

Repozitář je informační struktura, ve které jsou uloženy veškeré informace o historii projektu.

Jednou z výhod gitu je, že vytváří plnohodnotné kopie repozitářů. O tom, který repozitář určitého projektu je hlavní, tak rozhoduje pouze dohoda účastníků konkrétního projektu. Velmi často existuje na serveru jeden hlavní repozitář projektu, do kterého má právo zapisovat pouze správce projektu nebo skupina vybraných osob, a repozitáře pro jednotlivé účastníky projektu, do kterých mají právo zapisovat jejich vlastníci (správu repozitářů zajišťuje např. GitHub). Uživatel si pak pro práci může udržovat jeden nebo více lokálních repozitářů.

Slovníček pojmů[editovat]

Commit[editovat]

Commit je sada změn v jednom nebo více souborech (patch) uložená do verzovacího systému příkazem git commit. V gitu je každý commit jednoznačně identifikován pomocí SHA1 haše, což je 40ciferné šestnáctkové číslo. K identifikaci commitu lze použít i několik prvních znaků haše (pokud jednoznačně určují jeden commit).

Větev[editovat]

Větev (anglicky branch) by měla být uživatelem pojmenovaná sada commitů vyčleněných pro implementaci určité vlastnosti nebo opravy; v repozitáři bývá jedna nebo více „hlavních“ větví, do kterých se shromažďují příspěvky od jednotlivých účastníků projektu. „Nejhlavnější hlavní“ větev se jmenuje master a obvykle reprezentuje nejnovější stabilní větev projektu. Další „hlavní“ větve mohou být vývojové, pro starší releasy projektu a podobně. Základem úspěšné týmové práce v gitu je neměnit soubory v hlavních větvích, ale pro své úpravy vytvářet nové větve.

Větev v Gitu je pouhý pojmenovaný odkaz na (nejnovější) commit (hlava větve); další commity ve větvi jsou určeny předchůdci hlavy. Při provedení nového commitu do větve se jednoduše nastaví hlava větve na tento přidaný commit a jako jeho předchůdce se nastaví původní hlava. V Gitu nemá smysl hledat nejstarší commit větve; v podstatě je to nejstarší commit celého projektu; pro dvě větve je však možné určit jejich posledního (nejnovějšího) společného předka, tedy místo, kde se tyto větve rozdělily. Protože si git pamatuje, ve kterém okamžiku (po kterém commitu) bylo provedeno rozvětvení, není dobré se pokoušet používat staré větve pro nové úpravy; pokud je třeba navázat na starší úpravy, je vhodné provést přerovnání větve (git rebase) nebo převzít požadované starší úpravy příkazem git cherry-pick.

Fork[editovat]

Fork je rozdělení repozitáře pro různé release nebo uživatele; typicky se používá pro vytvoření vzdáleného repozitáře pro určitého uživatele, do kterého má tento uživatel právo zápisu, což mu dovoluje přispívat do projektu; fork není funkcí samotného gitu, ale nějaké jeho nadstavby (např. GitHub), proto se obvykle provádí na WWW stránce provozovatele vzdálených repozitářů; přebíráním větví z různých forků se kumulují výsledky paralelní práce více vývojářů.

Clone[editovat]

Clone vytvoří (příkazem git clone URL) lokální kopii vzdáleného repozitáře. S lokální kopií můžete provádět jakékoli operace; zda budete moci své úpravy přenést do vzdáleného repozitáře, záleží na nastavení práv ve vzdáleném repozitáři. Obvykle do společného vzdáleného repozitáře nemůžete zapisovat, ale můžete zapisovat do svého forku tohoto repozitáře.

Pull request[editovat]

Pull request je žádost o přetažení větve (tj. zkopírování úprav provedených v této větvi) do jiného forku (obvykle z mého soukromého do společného). Pull request je záležitost některé z nadstaveb systému git. Vedoucí projektu určuje, za jakých okolností se pull requestu vyhoví (Code review, úspěšné testy, schválení vedoucím), a jak má začlenění větve do projektu vypadat (jeden nebo více commitů, prosté sloučení nebo sloučení po přeskládání s viditelným nebo bez viditelného slučovacího commitu).

První kroky[editovat]

Načtení obsahu vzdáleného repozitáře[editovat]

První načtení dat ze vzdáleného repozitáře provedeme pomocí příkazů:

git clone -v adresa_repozitáře
cd adresář

adresa_repozitáře je např. git://git.kernel.org/pub/scm/git/git.git; v programu stash firmy Atlassian se adresa repozitáře zjistí kliknutím na ... -> Clone. Příkaz git clone vytvoří v aktuálním adresáři podadresář, jehož jméno stanovil tvůrce repozitáře, a do tohoto adresáře zkopíruje klonovaný strom; nové verze programu git vypisují jméno zmíněného podadresáře vždy, starší verze pouze pokud je použit parametr -v. Pro další práci s repozitářem pomocí příkazu git je nutné se přepnout do tohoto adresáře (případně nějakého jeho podadresáře). Pro pozdější načtení změn ve vzdáleném repozitáři používáme příkaz

git pull

Získání vlastní kopie vzdáleného repozitáře[editovat]

Na levém obrázku je znázorněn výsledek po klonování společného repozitáře projektu. Příkaz git clone vytvoří lokální kopii repozitáře. Kromě kopie databáze obsahuje i pracovní strom (working tree), v němž git zpřístupňuje soubory a adresáře zvolené verze projektu a oblast změn (staging area), která slouží pro přípravu commitu. Do společného vzdáleného repozitáře však běžný uživatel zpravidla nemůže zapisovat.

Uspořádání, které umožňuje uživateli do projektu přispívat, je znázorněno na pravém obrázku. Uživatel si musí nejdříve vytvořit (fork) vlastní kopii repozitáře na vzdáleném serveru (zpravidla nazývanou origin) a klonovat tuto kopii. Pro přenesení změn do společného repozitáře (blessed) se používají pull requesty.

Příkaz git clone adresa vytvoří na lokálním počítači kopii zadaného vzdáleného repozitáře; vytvoří i prázdnou stage area a vytvoří pracovní strom, který obsahuje nejnovější stav větve master.
Příkaz git clone adresa vytvoří na lokálním počítači kopii zadaného vzdáleného repozitáře; vytvoří i prázdnou stage area a vytvoří pracovní strom, který obsahuje nejnovější stav větve master.

Vytvoření lokálního repozitáře[editovat]

Chceme-li použít git pro svůj vlastní projekt, pro který zatím neexistuje vzdálený repozitář, vytvoříme lokální repozitář z adresářového stromu na lokálním disku následujícím postupem:

mkdir adresář
cd adresář
git init

První příkaz vytvoří prázdný adresář, do kterého se druhým příkazem přepneme. Poslední příkaz vytvoří v aktuálním adresáři podstrom se jménem .git, který obsahuje vše nezbytné pro repozitář. Repozitář je ale zatím prázdný; teprve commitem se do něj přidají soubory.

Konfigurace[editovat]

GIT má 3 úrovně konfigurace:

  • systémovou (pro všechny uživatele na počítači); příkaz git config je nutné použít s parametrem --system; konfigurace je v souboru /etc/gitconfig
  • uživatelskou (pro všechny projekty daného uživatele); příkaz git config je nutné použít s parametrem --global; konfigurace je v souboru ~/.gitconfig (ve Windows C:\Users\$USER\.gitconfig); tento soubor je vhodný pro nastavení uživatelského jména a e-mailové adresy
  • lokální (pro jeden projekt); konfigurace je v souboru .git/config; v tomto souboru jsou mimo jiné definovány vztahy mezi jmény a adresami vzdálených repozitářů a mezi lokálními a vzdálenými větvemi

Jméno a e-mailová adresa uživatele je typickou ukázkou konfiguračních informací na uživatelské úrovni, proto se provádí s parametrem --global:

git config --global user.name "John Doe"
git config --global user.email johndoe@example.com

– zapíše do ~/.gitconfig

git config --list

– vypíše všechna nastavení

git config user.name

– vypíše zadané nastavení; lze používat ve skriptech.

Pokud jste nuceni používat starou verzi Gitu (nižší než 2.0) je vhodné v globální konfiguraci nastavit, že příkaz git push má přenášet do vzdáleného repozitáře pouze změny v aktuální větvi:

git config --global push.default current

Soubor .gitignore[editovat]

Soubor .gitignore obsahuje seznam jmen souborů, které nemá git při své činnosti brát v úvahu. Jednotlivé řádky souboru obsahují buď komentáře začínající znakem křížek (#), nebo jméno souboru, které může obsahovat i jména adresářů a žolíkové znaky. V souboru je vhodné uvést jména záložních souborů, které vytvářejí editory a další programy pro vytváření a úpravu zdrojových souborů, stejně jako jména souborů, které jsou produkovány ze zdrojových souborů. Například *.o soubory vytvářené překladači, jména souborů vytvářených programy Lex a Yacc; při generování HTML souborů z XML, může být v .gitignore uvedeno

*.htm
*.html

pokud však jsou HTML soubory zdrojovými soubory, v .gitignore je neuvádíme.

Podobný význam mají soubory .git/info/exclude (pro jeden projekt) a $HOME/.config/git/ignore (pro všechny projekty daného uživatele na daném stroji).

Nápověda[editovat]

git
git help

– vypíše témata nápovědy

git help téma
git téma --help
man git-téma

– vypíše nápovědu k zadanému tématu

Lokální repozitář[editovat]

Lokální repozitář vytvořený příkazy git clone nebo git init umožňuje prohlížení i úpravy souborů. Můžeme si představovat, že se skládá ze 3 oblastí:

  • pracovní adresář nebo strom (working directory, working tree) – skutečný adresář nebo strom adresářů na disku
  • oblast připravených změn (staging area, index) – jedná se o seznam souborů (včetně obsahu v okamžiku, kdy se na soubor provedl příkaz git add), které budou příkazem git commit uloženy do repozitáře; soubory se do ní přidávají příkazem git add, odebírají git reset
  • repozitář (repository) – vlastní repozitář se mění pomocí git commit, do vzdáleného repozitáře se změny propagují pomocí git push

Soubory v pracovním stromě, které nejsou součástí staging area, jsou untracked, ostatní jsou buď tracked nebo modified; pomocí git add cesta/soubor se převede untracked nebo modified soubor do seznamu souborů, které se budou příkazem git commit ukládat do repozitáře (tzv. staged soubory), opakem git add soubor je git reset -- soubor.

Informace o repozitářích[editovat]

K nejčastěji používaným příkazům patří příkaz

git status

který vypíše jméno aktuální větve, její stav podle informací uložených v lokálním repozitáři, soubory ve staging area, změněné (modified) soubory a přidané (untracked) soubory.

Lokální repozitář vytvořený příkazem git clone je spojen se vzdáleným repozitářem, který lze zjistit příkazem

git remote -v

Nástrahy Gitu[editovat]

Git jakožto nástroj pro verzování souborů by měl přispívat k lepší ochraně dat, která jsou pomocí něho udržována. Tuto úlohu plní velmi dobře, ale protože se jedná o podstatně komplikovanější nástroj než je kopírování, přemísťování a mazání souborů v adresářové struktuře, mohou se začátečníkovi přihodit některé nepříjemnosti. Díky vlastnostem Gitu jsou tyto nepříjemnosti omezeny na dvě oblasti:

  • uživatel přijde o vlastní práci
  • uživatel zkomplikuje práci týmu

Likvidace práce jiných členů týmu je při rozumném nastavení prostředí téměř vyloučena.

Aby se uživatel nepřipravil o vlastní práci, stačí trocha obezřetnosti a zapamatování si, které akce ji mohou způsobit. Hlavním zdrojem potíží může být fakt, že pracovní strom slouží jak k úpravě souborů uživatelem, tak k zobrazení stavu projektu. Každý příkaz git checkout může změnit obsah pracovního stromu a mohl by vést k přepsání změn, které uživatel provedl. Proti takto jednoduchému přepsání souborů je však Git zabezpečen, a pokud soubor s určitým obsahem nepatří do aktuální verze uložené v repozitáři a byl by přepsán jiným obsahem, vypíše varování a akci neprovede. Existuje však několik příkazů, které vás mohou o nearchivované verze souborů připravit:

  • git checkout -- cesta – před provedením tohoto příkazu je nutné si být jistý, že zadané soubory nebudeme potřebovat, případně, že je máme bezpečně zkopírované (např. mimo pracovní stromu projektu)
  • git reset --hard – tento příkaz provádět pouze pokud nemáme žádné untracked soubory a pokud máme poznamenané číslo aktuálního commitu
  • git branch -D větev – tento příkaz raději odložit na dobu, kdy budeme mít jistotu, že mazaná větev neobsahuje nic užitečného (pokud byla větev zkopírována jinam pomocí git cherry-pick, zkontrolujte, že byly zkopírovány všechny potřebné úpravy)
  • na git push -f nebo --force raději zapomeňte; bezpečnější je uvedení + před jménem větve – při některých postupech (git commit --amend větve, která už byla pushnuta do vzdáleného repozitáře, používání git rebase bez git merge) se bez některé z uvedených variant neobejdeme; rozhodně by se neměl používat pro společný repozitář, nejvýše jako náprava chyby; tuto nápravu byl měl provést uživatel s výbornou znalostí Gitu

Jakmile je jednou proveden commit souboru, uplatní se základní vlastnost Gitu, že do databáze se pouze připisuje. Proto je možné obnovit i smazaný commit. Git však po určité době nereferencované objekty maže, proto je nutné co nejrychleji vytvořit například větev odkazující se na smazaný commit, který budeme ještě potřebovat.

Zkomplikování práce týmu nevhodným zásahem do verzovacího systému lze zabránit technicky (zálohování) organizačně (neposkytováním práva zápisu do společného repozitáře) nebo dobrým proškolením uživatelů. Pokud by došlo k poškození hlavního repozitáře, je možné využít distribuovanosti Gitu a repozitář obnovit z jiné kopie.

Postup při změnách souborů[editovat]

Git data flow simplified.svg

Při změnách souborů je vhodné dodržovat následující postup:

  1. Aktualizace informací v lokálním repozitáři ze vzdálených repozitářů
  2. Vytvoření a úpravy zdrojových souborů pomocí obvyklých nástrojů
  3. Vytvoření větve pro začlenění úprav s případným nastavením výchozí verze
  4. Vytvoření seznamu změn
  5. Uložení změn do lokálního repozitáře příkazem git commit
  6. Přenesení změn do vzdáleného repozitáře příkazem git push

Aktualizace informací v lokálním repozitáři[editovat]

První z příkazů

git fetch --all -v
git status

načte informace o změnách ze všech vzdálených repozitářů, ale neprovede žádné změny v lokálním stromě. Následující příkaz vypíše, jak se změny ve vzdáleném repozitáři slučují se stavem lokálního repozitáře a pracovního stromu.

Pokud nemáme v pracovním stromě žádné změněné soubory, lze příkazem

git pull --ff-only

aktualizovat obsah lokálního stromu – příkaz lze použít i bez parametru --ff-only. Pokud však byla rozštěpena lokální a vzdálená větev (například tím, že někdo zahodil jeden nebo více commitů pomocí git reset následovaného forced push), pull bude provádět slučování (merge) obou větví se všemi případnými problémy (konflikty atd.). Použití --ff-only nám dá možnost rozmyslet si, jestli chceme opravdu provést slučování; pokud by se například jednalo o cizí větev, ve které nemáme co mergovat, bude lepší přesunout lokální hlavu na pozici vzdálené hlavy příkazem

git reset --hard plné_jméno_vzdálené_větve

Pokud máme v pracovním stromě změněné soubory a nechceme o tyto změny přijít, můžeme použít příkaz git stash, což však znamená učit se další příkaz, který ne vždy splňuje naše představy. Snazší může být použití bodů 3 až 5 výše popsaného postupu: vytvoříme si pracovní větev, zadáme všechny změněné soubory do seznamu změn a provedeme commit. Pokud by nám později nevyhovovalo, kde takto vytvořená větev začíná, lze ji uplatnit na jiném místě pomocí git cherry-pick.

Aktualizace informací provádíme, abychom svoje změny aplikovali na nejnovější verzi souborů v projektu. Pokud naopak potřebujeme udělat úpravu starší verze, použijeme příkaz git checkout identifikace_commitu.

Vytvoření a úpravy zdrojových souborů[editovat]

Soubory z projektu jsou přístupné v pracovním stromě, proto je možné je jednoduše prohlížet, upravovat a vytvářet pomocí editorů a dalších nástrojů. Mnoho použití příkazu git mění soubory v pracovním stromě, proto před jejich použitím změněné soubory uložte provedením commitu nebo zkopírujte na bezpečné místo (např. mimo pracovní strom).

Práce s větvemi[editovat]

Větev je sada commitů. Commity jsou spolu svázány pomocí svých předchůdců (úplně první commit nemá žádného, běžný commit má jednoho, slučovací commit má dva nebo více předchůdců). Git neumožňuje, aby větev obsahovala vzájemně nesouvisející commity, takže větev je jednoduše odkaz na její nejnovější commit. Vzhledem k tomuto pojetí větve lze těžko stanovit, jaký je druhý konec větve (nejstarší commit), lze však určit, který commit je poslední (nejnovější) společný předek dvou větví.

Pro zjištění existujících větví lze použít příkaz

git branch

– který vypíše větve v lokálním repozitáři, před jménem aktuální je hvězdička. Pokud doplníme parametr -r, vypíše větve ve vzdálených repozitářích spojených s projektem; s parametrem -a vypíše větve v lokálním i ve vzdálených repozitářích.

Přepínání větví[editovat]

Pro změnu aktuální větve (přepnutí větve) slouží následující příkaz:

git checkout větev

Důležité je, že změna větve způsobí změnu souborů v pracovním stromě. Pokud se soubory v pracovním stromě pracujeme, mohou nastat různé problémy, ale git se v tomto případě chová slušně a bezpečně:

  • Pokud jsou v pracovním stromě změněné necommitnuté soubory, které by byly přepsány, git vypíše varování a změnu větve neprovede:
$ git checkout treti-radek-a-druhy-soubor
error: Your local changes to the following files would be overwritten by checkout:
        druhy_soubor.txt
Please, commit your changes or stash them before you can switch branches.
Aborting
  • Stejně je tomu v případě, že by došlo k přepsání dříve untracked souboru souborem, který je v nové verzi přítomen:
$ git checkout treti-radek-a-druhy-soubor
error: The following untracked working tree files would be overwritten by checkout:
        druhy_soubor.txt
Please move or remove them before you can switch branches.
Aborting
  • Problémy mohou také nastat, pokud jsou zdrojové soubory otevřeny v editoru nebo nějakém jiném programu. Některé programy vůbec změnu souboru nezaregistrují, a uživatel tak může editovat špatnou verzi souboru. Jiné nechají uživateli vybrat, jestli chce nahrát novou verzi nebo pokračovat v práci s původní. Jiné programy mohou dokonce zabránit gitu, aby soubory změnil.

Místo jména větve lze použít libovolnou identifikaci commitu. Pokud používáme značky (anglicky tags), lze přepnout na zadanou značku:

git checkout tags/jméno_tagu

Vytvoření větve[editovat]

Provedením následujících dvou příkazů vytvoříme větev zadaného jména v aktuálním místě aktuální větve a nově vytvořenou větev nastavíme jako aktuální:

git branch jméno_větve
git checkout jméno_větve

Oba příkazy lze sloučit do jednoho:

git checkout -b jméno_větve

Každý z následujících příkazů vytvoří větev v lokálním repozitáři duplikováním větve ze vzdáleného repozitáře:

git checkout -b jméno_větve origin/jméno_větve
git checkout --track origin/větev

Pokud je potřeba vytvořit větev začínající v určitém místě, lze zadat jméno commitu, za kterým má větev začínat:

git branch jméno_větve odkaz_na_commit
git checkout -b jméno_větve odkaz_na_commit

Zrušení větve[editovat]

Následující příkaz zruší větev:

git branch -d jméno_větve

Pokud větev nebyla namergovaná do jiné větve, příkaz vypíše varování a větev nezruší. Pokud chceme větev opravdu zrušit, použijeme místo -d velké -D.

Vytvoření seznamu změn[editovat]

Přidání aktuálního stavu souboru do seznamu změn:

git add cesta/soubor [ cesta2/soubor2 ... ]

Pokud byl soubor znovu změněn, stačí příkaz git add zopakovat (pro každý soubor v seznamu změn se pamatuje stav při posledním přidání). Pokud byl soubor zařazen do seznamu změn omylem, lze to napravit příkazem

git reset -- cesta/soubor [ cesta2/soubor2 ... ]

Přejmenování a rušení souborů v repozitáři[editovat]

Seznam změn ovlivňují také příkazy pro přejmenování a zrušení souboru.

Přejmenování souboru (lze použít i pro přemístění do jiného adresáře):

git mv cesta1/soubor cesta2/jméno

Odstranění souboru z projektu:

git rm cesta/soubor

Zrušení úprav souboru[editovat]

Pokud jste nějaký soubor změnili, nezanesli tuto změnu ani do indexu ani neprovedli commit, a úpravu souboru chcete zrušit, lze použít následující postup:

cp cesta/soubor cesta/soubor_zaloha
git checkout -- cesta/soubor

Druhý příkaz přepíše zadaný soubor verzí z aktuální větve lokálního repozitáře. Přitom nevypisuje žádná varování a původní soubor už nejde obnovit, proto je prvním příkazem naznačeno, že je vhodné si vytvořit jeho zálohu, pro případ, že byste přeci jenom chtěli upravenou verzi použít.

Další příkaz zruší všechny změny v souborech v pracovní oblasti:

git checkout -- .

Uložení změn do lokálního repozitáře[editovat]

Příkaz

git commit -m "Popis commitu"

uloží aktuální seznam změn do aktuální větve lokálního repozitáře.

Pokud nebyly přidány žádné soubory, lze spojit vytvoření seznamu změn a uložení změn do lokálního repozitáře použitím parametru -a:

git commit -a -m "Popis commitu"

V tomto případě se před commitem do seznamu změn automaticky přidají všechny modified soubory.

Modifikace commitu[editovat]

Pokud jste po provedení commitu zjistili, že jste zapomněli provést nějakou „malou“ úpravu, lze právě provedený commit dodatečně upravit. Nejdříve pomocí git add zadejte jména všech dodatečně upravených souborů, a pak příkazem git commit s parametrem --amend upravte poslední commit:

git add cesta/soubor [ cesta2/soubor2 ... ]
git commit --amend

Pokud jste již stihli na upravený commit provést git push, bude nutné použít git push se znakem plus před jménem větve, protože se nebude jednat o pouhé přidávání do vzdáleného repozitáře.

Přenesení změn do vzdáleného repozitáře[editovat]

Příkaz

git push

přenese změny z lokálního repozitáře do vzdáleného repozitáře. Pokud je pracovní strom propojen s více vzdálenými repozitáři, přenesou se změny do repozitáře origin. Pokud se mají přenést do jiného repozitáře, je nutné zadat jeho jméno použité v příkazu git remote add:

git push jméno

Pokud větev ve vzdáleném repozitáři neexistuje, příkaz vypíše varování a je třeba nastavit upstream, přesně podle textu, který je součástí varování:

git push --set-upstream origin jméno_větve

Slučování změn[editovat]

Pokud na jednom projektu pracuje více osob nebo pokud vytvoříme více větví, neobejdeme se bez slučování větví. Následující příkaz zamerguje zadanou větev do aktuální větve; proto je potřeba se předem přepnout do větve, do které se má mergovat; mohou nastat potíže, pokud existují necommitované změny, proto je třeba mergování provádět s čistým pracovním stromem.

git merge větev

Pokud byl soubor změněn pouze v jedné ze slučovaných větví, použije se změněná verze. Pokud byl soubor změněn v obou větvích, pokusí se git aplikovat změny, ke kterým v souboru došlo v zadané větvi, na soubor v aktuální větvi (jako příkaz patch). Pokud patch selže, je ohlášen konflikt:

$ git merge pro-posledni-radek
Auto-merging pokus.txt
CONFLICT (content): Merge conflict in pokus.txt
Automatic merge failed; fix conflicts and then commit the result.

do souboru jsou umístěny obě verze vyznačené řetězci <<<<<<<, ======= a >>>>>>>:

Nejaky text.
<<<<<<< HEAD
Druhy radek.
Toto je posledni radek.
=======
Zmeneny druhy radek.
>>>>>>> jina

a sloučení je potřeba provést ručně. Pro ruční sloučení je možné použít běžný textový editor nebo speciální nástroj. Seznam dostupných nástrojů pro slučování souborů vypíše příkaz

git mergetool --tool-help

Zvolený nástroj nastavíme příkazem

git config --global merge.tool gvimdiff

Vlastní slučování pak lze provést příkazem

git mergetool cesta/soubor

Gvimdiff zobrazuje nahoře ve třech sloupcích soubor z výchozí větve, společného předchůdce a soubor ze slučované větve, dole pak text s oběma variantami, jak je ukázáno výše.

Gvimdiff2 zobrazuje pouze tři sloupce, přičemž v prostředním je text s oběma variantami; gvimdiff3 zobrazuje pouze jedno okno s oběma variantami textu.

Složitější akce[editovat]

Přemístění commitů do jiné větve[editovat]

Často se stává, že člověk začne upravovat soubory v nesprávné větvi. Pokud ještě neprovedl commit, stačí pomocí git checkout -b jméno_větve vytvořit novou větev (větve jsou složeny z commitů, takže před provedením commitu jsme ještě žádnou větev nezměnili). Pokud byla větev už vytvořena, ale neobsahuje žádný commit, lze použít git checkout jméno_větve.

Pokud už byl proveden jeden nebo více commitů, je rozhodně vhodné vytvořit novou větev a úpravy přesunout do ní. Nejdříve provedeme commit všech rozpracovaných souborů, pak řekneme, že nová větev končí právě zde (vytvoříme novou větev) a nakonec příkazem git reset --hard vyhodíme nechtěné commity z původní větve (novou větev jsme vytvořili, ale přepnuti jsme stále v původní, teprve git checkout nás přepne do nové větve):

git add cesta/soubor [ cesta2/soubor2 ... ]
git commit -m "Uložení rozpracovaných souborů"
git branch nová_větev
git reset --hard odkaz_na_commit
git checkout nová_větev

Rebase[editovat]

Rebase (do češtiny překládané jako přeskládání) je alternativou ke slučování pomocí merge. Pokud byla větev, ve které se provedly změny, oddělena z jiné větve před delší dobou, takže v původní větvi došlo ke změnám, můžeme chtít místo viditelného sloučení větví aplikovat změny ze své větve na hlavní větev. Příkazy

git checkout moje_větev
git rebase hlavní_větev

zkopírují se všechny úpravy z větve moje_větev od místa, kde se oddělila od větve hlavní_větev, na konec hlavní větve. Původní commity sice zůstanou zachovány, ale jejich kopie se objeví ještě jednou na konci hlavní větve. Pokud byl některý ze souborů upraven v obou větvích takovým způsobem, že algoritmus slučování není schopen určit, jak má vypadat výsledek, je ohlášen konflikt, který musíme vyřešit, jak je popsáno v části Slučování změn. Git také informuje o možnosti příslušný patch přeskočit pomocí git rebase --skip, nebo přeskládání odvolat příkazem git rebase --abort. Pokud se rozhodneme pro řešení konfliktů, je nutné po jejich odstranění všechny upravené soubory zadat do seznamu změn pomocí příkazu git add cesta/soubor jako před provedením commitu a zadat příkaz

git rebase --continue

V ideálním případě se rebase dokončí; může se však stát, že rebase narazí na konflikt v některém z dalších commitů v přeskládávané větvi. Pak se celý kolotoč opakuje, ale nebojte se, jste o další krůček blíž k cíli. Pokud však jsou obě větve dlouhé a obsahují mnoho konfliktů, může být lepší místo rebase zamergovat hlavní větev do naší, zejména, když máme představu, jak má vypadat konečný výsledek a nestojíme o postupné úpravy souborů. Jinou možností je sloučit commity ve svojí větvi do jednoho, a tento souhrnný commit pomocí rebase zkopírovat na konec větve, do které má být začleněn.

Protože se provedením rebase přesune lokální hlava rebasované větve na konec její nově vytvořené kopie, dojde k rozštěpení lokální a vzdálené větve. Pro jejich spojení je nutné provést forced push, který lze vynutit uvedením znaku + před jménem větve:

git push origin +rebasovaná_větev

kde origin je jméno repozitáře a znak plus před jménem rebasované větve zajistí, že se provede push pouze pro zadanou větev. Vhodnější je vytvořit si ještě před rebase kopii rebasované větve, která nebude ve vzdáleném repozitáři a rebase provést s ní:

git checkout -b kopie_větve
git rebase hlavní_větev

Výběr změn bez historie[editovat]

Každý commit obsahuje odkaz na předchozí commit (případně na dva, pokud vznikl pomocí merge). Pokud je potřeba začlenit do určité větve změny z jiné větve bez odkazů na jejich historii, lze použít následující příkaz:

git cherry-pick odkaz_na_commit [ ... ]

Příkaz git cherry-pick dovádí do extrému přístup z git rebase: na aktuální větev aplikuje pouze změny provedené ve vybraných commitech.

Používání více repozitářů pro jeden projekt[editovat]

Lokální repozitář může být propojen s více vzdálenými repozitáři téhož projektu. Další vzdálené repozitáře lze přidávat příkazem

git remote add jméno adresa_repozitáře

Zadané jméno slouží k pozdějším odkazům na vzdáleným repozitář v příkazech git fetch, git pull a git push. Repozitář, který byl použit v příkazu git clone, má jméno origin; společnému repozitáři se obvykle dává jméno blessed.

Sloučení commitů[editovat]

Při vývoji softwaru se často stává, že sada úprav tvořících jeden logický celek je rozložena do několika commitů. Mohou to být commity provedené na konci každého dne, commity způsobené postupnými opravami, úpravy provedené jako reakce na review, apod. Pokud jejich autor nechce, aby byl vidět bolestný proces vzniku jeho díla, může sloučit commity do jednoho nebo do menšího počtu, které tvoří určité logické celky. Preferovaným postupem je použití interaktivního režimu příkazu git rebase:

git rebase -i starý_commit

kde starý_commit je commit, po němž se mají commity slučovat (v tomto případě lze s výhodou použít operátor vlnka pro n-tého předchůdce: např. pro sloučení posledních 5 commitů použít HEAD~5). Po zadání příkazu se otevře editor, ve kterém je seznam commitů od nejnovějšího po nejstarší vypadající takto:

pick 69248ac Popis prvního commitu
pick d70002a Popis druhého commitu
...
pick 49f2d10 Popis posledního commitu

# Rebase 1949c51..49f2d10 onto 1949c51 (7 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

Řádky začínající znakem křížek napovídají, že interaktivní rebase má mnoho dalších možností; pro sloučení všech vypsaných commitů do jednoho je třeba slovo pick v prvním řádku ponechat a všechna ostatní nahradit slovem squash (nebo písmenem s) a soubor uložit; otevře se další soubor, do kterého je třeba napsat popis souhrnného commitu. Výsledkem jsou všechny změny v jediném commitu. Stejně jako při běžném rebase dojde k rozvětvení lokální a vzdálené hlavy větve, takže je potřeba provést push s plusem před jménem větve:

git push origin +rebasovaná_větev

Anulování commitů[editovat]

Pokud chcete zrušit (odvolat) jeden nebo více commitů, závisí postup na tom, kam až se nežádoucí commity dostaly, a jestli po nich byly provedeny další (žádoucí) commity. Ve svém soukromém repozitáři (ať lokálním nebo vzdáleném) můžete klidně zrušit několik posledních commitů zkrácením větve příkazy:

git checkout větev
git reset --hard poslední_správný_commit

následovaném

git push origin +větev

Pokud se ale nejedná o poslední commity a především pokud byly nežádoucí commity již zpropagovány do společného repozitáře, je třeba použít jemnější způsob jejich zrušení:

git revert seznam_commitů

Tento příkaz zjistí změny provedené v uvedených commitech, v aktuálních souborech aplikuje úpravy, kterými se tyto změny vezmou zpět. Pokud dojde ke konfliktům, je třeba je vyřešit obdobným způsobem jako v případě příkazu rebase. Pokud se vše podařilo, vznikne v lokálním repozitáři nový commit obsahující soubory, které byly změněny. Tento commit je nutné přenést do vašeho vzdáleného repozitáře a začlenit do společného repozitáře.

Podrobnější informace[editovat]

Hledání v historii[editovat]

Historii aktuální větve lze zobrazit příkazem

git log

Příkaz vypisuje jednotlivé commity s jejich haši. U každého commitu je autor, datum změny a informace zadaná v příkazu git commit za parametrem -m. Slučování (merge) jsou zvlášť označeny. S parametrem --name-only nebo --name-status se bude vypisovat, jaké soubory se měnily v jednotlivých commitech.

Pro nalezení změn určitého souboru lze použít příkaz:

git log -- cesta/soubor

Pro barevné zobrazení historie celého projektu, včetně ASCII znázornění větví a vypsání jmen větví a tagů, lze použít grafický příkaz gitk & nebo

git log --all --decorate --graph --oneline --name-status

Poslední parametr použijeme, pokud se mají vypisovat i jména souborů.

Porovnávání commitů[editovat]

Pro porovnávání commitů slouží příkaz git diff. Bez parametrů zobrazí změny mezi working tree a staging area. Příkaz lze doplnit dalšími parametry; volby začínající znakem mínus předává přímo příkazu diff, takže pro porovnání s ignorováním změn v počtu mezer lze použít příkaz

git diff -b -w

Dalšími parametry lze zadat jeden nebo dva commity, které se mají porovnávat:

git diff -b master SMSC-1079-5.4

– vypíše rozdíl mezi větví master a SMSC-1079-5.4; -b se předává příkazu diff, aby ignoroval rozdíly v mezerách

git diff HEAD
git diff --staged

– oba příkazy vypíšou rozdíly v souborech, na které se provedlo git add

git diff --staged číslo_commitu_z_pull_requestu
git diff číslo_commitu_z_pull_requestu

– první příkaz vypíše rozdíly mezi zadaným commitem a staging area, druhý rozdíly mezi commitem a working tree; diff obsahuje řádky tvaru index 358c9f8..8740525 100644

git diff 358c9f8..8740525

– vypíše diff daného souboru v příslušném commitu. Další možností, jak omezit diff vybrané soubory je doplnit příkaz dvěma pomlčkami následovanými jmény souborů i cestami:

git diff popis_commitu -- cesta/soubor [ cesta2/soubor2 ... ]

Pokud nás zajímá diff pouze z jednoho commitu, lze na unixových systémech použít:

git diff 9883d27d0b302a2e0f4f04c2d072f52c186ad18a{^,}

– vypíše diff commitu 9883d27d0b302a2e0f4f04c2d072f52c186ad18a (shell expanduje xxx{^,} na xxx^ xxx; xxx^ je předchůdce xxx); stačí zadat i několik prvních znaků SHA haše.

Pro zjištění, jaké soubory byly změněny v posledním commitu v aktuální větvi, lze použít příkaz:

git diff --name-only HEAD^

Kompletní informace o commitu[editovat]

Více informací o commitu v příkazech git log a git show lze získat použitím volby --pretty=fuller. S touto volbou se zobrazí autor, datum a čas nejen původního commitu, ale i jeho začlenění do větve po git rebase:

commit edb9342985b443443eb0266d8418c3e62851d1d0
Author:     Jan Vyvojar <Jan.Vyvojar@domena.top>
AuthorDate: Fri Apr 21 10:20:48 2017 +0200
Commit:     Karel Reviewer <Karel.Reviewer@domena.top>
CommitDate: Wed May 10 09:22:16 2017 +0200

    Fix of the bug #123456

Synchronizace lokální a vzdálené větve[editovat]

Při použití parametru --track v příkazu git checkout nebo parametru --set-upstream v příkazu git push se pro lokální větev aktivuje sledování (trackování) vzdálené větve. Při zapnutém trackování vás příkaz git status upozorní, že lokální větev je pozadu (behind) za vzdálenou větví, před (ahead) vzdálenou větví (což znamená, že jste provedli jeden nebo více commitů a neprovedli git push), že se větve rozešly (Your branch and 'jméno_větve' have diverged), nebo že jsou synchronizované (Your branch is up-to-date with 'jméno_větve'). Git si informaci o trackování větve uchovává v souboru .git/config v sekci [branch "jméno_větve"] v podobě parametrů remote = vzdálený_repozitář a merge = odkaz_na_větev, přičemž odkaz na větev je tvaru refs/heads/jméno_větve.

Pokud nejsou synchronizované větve, které by synchronizované být měly, lze synchronizaci aktuální větve zapnout příkazem

git branch --set-upstream-to=repozitář/jméno_větve

Pokud naopak chcete z nějakého důvodu synchronizaci vypnout, použijte příkaz

git branch --unset-upstream

Odkazy[editovat]

Literatura[editovat]

Externí odkazy[editovat]

  • Encyklopedický článek Git ve Wikipedii