Větvení v Gitu

Takže, Git už znáš! Teď to začne být trošičku složitější :)

Programátorky občas potřebují pracovat na dvou věcech zároveň. V projektu do práce se objeví se chyba, která musí být opravená ještě dnes, tak programátorka opustí, co zrovna dělá, vrátí se k nějaké „stabilní” verzi, opraví chybu a odešle ji zákazníkům. A pak se vrátí k tomu, co dělala předtím – jen ještě musí zakomponovat opravu chyby i do verze, na které pracuje dlouhodobě.

Git na to má takzvané větve (angl. branches). Na jedné „větvi” se pracuje, ale je možné se přepnout do jiné (třeba starší) větve, udělat pár změn a pak se zase přepnout do nové větve a pokračovat dál nebo sloučit změny.

Větvení využijeme i při spolupráci více lidí – každý dělá na vlastní větvi a když přijde čas, tak se různé změny sloučí dohromady.

Podívej se, jaké máš větve ve svém repozitáři. K tomu slouží příkaz git branch:

$ git branch
* master

Je tam jenom jedna a jmenuje se master – to je tradičně jméno „hlavní” větve.

K vytvoření nové větve znovu použiješ git branch, jen tomu příkazu dáš navíc jméno nové větve. Třeba budeš chtít k básničce doplnit jméno autora, tak větev pojmenuješ doplneni-autora.

$ git branch doplneni-autora
$ git branch
  doplneni-autora
* master

Tenhle příkaz sice udělal novou větev, ale nepřepnul do ní. Hvězdička ve výstupu z git branch ukazuje, že stále pracuješ v master. Na přepnutí budeš potřebovat další příkaz:

$ git checkout doplneni-autora
Switched to branch 'doplneni-autora'
$ git branch
* doplneni-autora
  master

Tak. Teď jsi „ve” větvi doplneni-autora. Doplň nějaké jméno do souboru basnicka.txt, a pomocí git add a git commit udělej novou revizi. Pak koukni na gitk --all, jak to vypadá:

Výstup programu `gitk` s větví doplneni-autora

Aktuální větev – doplneni-autora – je zvýrazněná tučně a starší master je stále na původní revizi.

Opusťme teď na chvíli práci na doplňování autora. Vrať se do větve master a vytvoř z ní větev doplneni-jmena. Pak se na tuhle novou větev přepni.

$ git checkout master
Switched to branch 'master'
$ git branch doplneni-jmena
$ git checkout doplneni-jmena
Switched to branch 'doplneni-jmena'
$ git branch
  doplneni-autora
* doplneni-jmena
  master

Doplň do souboru jméno básně a pomocí git add, git commit ulož revizi. Všechno zkontroluj přes gitk --all.

Výstup programu `gitk` s větvemi doplneni-autora a doplneni-nazvu

Takhle nějak se dá postupovat v situaci popsané v úvodu: opuštění rozpracované verze, přechod na „stabilní” verzi master a začátek práce v jiné části projektu.

Mezi jednotlivými větvemi se dá podle libosti přepínat, jen je vždycky dobré před přepnutím udělat novou revizi (git commit) a pomocí git status zkontrolovat, jestli je všechno uložené v Gitu.

Na stejném principu funguje i spolupráce několika lidí na jednom projektu: je nějaký společný základ (master) a každý dělá na vlastní větvi, dokud není se svými změnami spokojený.

A až je některá větev hotová, může se začlenit zpátky do master. Podívejme se jak na to.

Sloučení

Nedávalo by smysl historii projektu rozdvojovat, kdyby pak jednotlivé větve nešly zase sloučit dohromady. Naštěstí je v Gitu slučování poměrně jednoduché.

Přepni se zpátky na master a použij příkaz git merge, který sloučí jinou větev s tou aktuální. Příkazu musíš dát jméno větve, kterou chceš sloučit.

$ git checkout master
Switched to branch 'master'
$ git merge doplneni-jmena
Updating e929fb0..c982a81
Fast-forward
 basnicka.txt | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

Sloučeno! Ono „Fast-forward” znamená, že vlastně nebylo co slučovat – jen se do větve master přidaly nové změny. Zkontroluj v gitk --all, jak to vypadá.

A pak zkus sloučit i druhou větev: git merge doplneni-autora. Tady to bude složitější: Může se stát, že změny nepůjdou automaticky sloučit a ve výstupu se objeví hláška merge conflict (konflikt při slučování). V tom případě se na soubor podívej v editoru: objeví se v něm obsah z obou konfliktních verzí, společně se značkami, které upozorňují na místo kde konflikt nastal. Soubor uprav ho tak, jak by měl vypadat, ulož a zadej git commit.

Ať nastal konflikt nebo ne, vytvoří se „slučovací revize“ (angl. merge commit), které – jako každé revizi – můžeš dát popisek.

$ git merge doplneni-autora
Auto-merging basnicka.txt
Merge made by the 'recursive' strategy.
 basnicka.txt | 2 ++
 1 file changed, 2 insertions(+)

Povedlo se?

Výstup programu `gitk` s větvemi doplneni-autora a doplneni-nazvu sloučenými do master

Pokud ano, můžeš staré větve vymazat – všechny jejich změny jsou v master a nemá na nich cenu pracovat dál.

$ git branch -d doplneni-autora
Deleted branch doplneni-autora (was 0e213cd).
$ git branch -d doplneni-jmena
Deleted branch doplneni-jmena (was c982a81).
$ git branch
* master

Gratuluji, už umíš větvení a slučování!

{
  "data": {
    "sessionMaterial": {
      "id": "session-material:2019/brno-jaro-2019-ut:def:2",
      "title": "Větvení v Gitu",
      "html": "\n          \n    \n\n    <h1>V&#x11B;tven&#xED; v Gitu</h1>\n<p>Tak&#x17E;e, Git u&#x17E; zn&#xE1;&#x161;!\nTe&#x10F; to za&#x10D;ne b&#xFD;t tro&#x161;i&#x10D;ku slo&#x17E;it&#x11B;j&#x161;&#xED; :)</p>\n<p>Program&#xE1;torky ob&#x10D;as pot&#x159;ebuj&#xED; pracovat na dvou\nv&#x11B;cech z&#xE1;rove&#x148;.\nV&#xA0;projektu do pr&#xE1;ce se objev&#xED; se chyba,\nkter&#xE1; mus&#xED; b&#xFD;t opraven&#xE1;\nje&#x161;t&#x11B; dnes, tak program&#xE1;torka opust&#xED;, co zrovna d&#x11B;l&#xE1;,\nvr&#xE1;t&#xED; se k n&#x11B;jak&#xE9; &#x201E;stabiln&#xED;&#x201D; verzi, oprav&#xED; chybu\na ode&#x161;le ji z&#xE1;kazn&#xED;k&#x16F;m.\nA pak se vr&#xE1;t&#xED; k&#xA0;tomu, co d&#x11B;lala p&#x159;edt&#xED;m &#x2013; jen je&#x161;t&#x11B;\nmus&#xED; zakomponovat opravu chyby i do verze, na kter&#xE9;\npracuje dlouhodob&#x11B;.</p>\n<p>Git na to m&#xE1; takzvan&#xE9; <em>v&#x11B;tve</em> (angl. <em>branches</em>).\nNa jedn&#xE9; &#x201E;v&#x11B;tvi&#x201D; se pracuje, ale je mo&#x17E;n&#xE9; se p&#x159;epnout do\njin&#xE9; (t&#x159;eba star&#x161;&#xED;) v&#x11B;tve, ud&#x11B;lat p&#xE1;r zm&#x11B;n\na pak se zase p&#x159;epnout do nov&#xE9; v&#x11B;tve a\npokra&#x10D;ovat d&#xE1;l nebo slou&#x10D;it zm&#x11B;ny.</p>\n<p>V&#x11B;tven&#xED; vyu&#x17E;ijeme i p&#x159;i spolupr&#xE1;ci v&#xED;ce lid&#xED; &#x2013; ka&#x17E;d&#xFD;\nd&#x11B;l&#xE1; na vlastn&#xED; v&#x11B;tvi a kdy&#x17E; p&#x159;ijde &#x10D;as,\ntak se r&#x16F;zn&#xE9; zm&#x11B;ny slou&#x10D;&#xED; dohromady.</p>\n<p>Pod&#xED;vej se, jak&#xE9; m&#xE1;&#x161; v&#x11B;tve ve sv&#xE9;m repozit&#xE1;&#x159;i.\nK tomu slou&#x17E;&#xED; p&#x159;&#xED;kaz <code>git branch</code>:</p>\n<div class=\"highlight\"><pre><code><span style=\"color: #00aaaa\">$</span> git branch\n* <span style=\"color: #00aa00\">master</span></code></pre></div><p>Je tam jenom jedna a jmenuje se <code>master</code>\n&#x2013; to je tradi&#x10D;n&#x11B; jm&#xE9;no &#x201E;hlavn&#xED;&#x201D; v&#x11B;tve.</p>\n<p>K vytvo&#x159;en&#xED; nov&#xE9; v&#x11B;tve znovu pou&#x17E;ije&#x161;\n<code>git branch</code>, jen tomu p&#x159;&#xED;kazu d&#xE1;&#x161; nav&#xED;c\njm&#xE9;no nov&#xE9; v&#x11B;tve.\nT&#x159;eba bude&#x161; cht&#xED;t k b&#xE1;sni&#x10D;ce doplnit jm&#xE9;no autora,\ntak v&#x11B;tev pojmenuje&#x161; <code>doplneni-autora</code>.</p>\n<div class=\"highlight\"><pre><code><span style=\"color: #00aaaa\">$</span> git branch doplneni-autora\n<span style=\"color: #00aaaa\">$</span> git branch\n  doplneni-autora\n* <span style=\"color: #00aa00\">master</span></code></pre></div><p>Tenhle p&#x159;&#xED;kaz sice ud&#x11B;lal novou v&#x11B;tev,\nale nep&#x159;epnul do n&#xED;.\nHv&#x11B;zdi&#x10D;ka ve v&#xFD;stupu z&#xA0;<code>git branch</code> ukazuje,\n&#x17E;e st&#xE1;le pracuje&#x161; v&#xA0;<code>master</code>.\nNa p&#x159;epnut&#xED; bude&#x161; pot&#x159;ebovat dal&#x161;&#xED; p&#x159;&#xED;kaz:</p>\n<div class=\"highlight\"><pre><code><span style=\"color: #00aaaa\">$</span> git checkout doplneni-autora\nSwitched to branch &apos;doplneni-autora&apos;\n<span style=\"color: #00aaaa\">$</span> git branch\n* <span style=\"color: #00aa00\">doplneni-autora</span>\n  master</code></pre></div><p>Tak. Te&#x10F; jsi &#x201E;ve&#x201D; v&#x11B;tvi <code>doplneni-autora</code>.\nDopl&#x148; n&#x11B;jak&#xE9; jm&#xE9;no do souboru <code>basnicka.txt</code>,\na pomoc&#xED; <code>git add</code> a <code>git commit</code> ud&#x11B;lej novou revizi.\nPak koukni na <code>gitk --all</code>, jak to vypad&#xE1;:</p>\n<p><span class=\"figure\"><a href=\"/2019/brno-jaro-2019-ut/git/branching/static/branch1.png\"><img src=\"/2019/brno-jaro-2019-ut/git/branching/static/branch1.png\" alt=\"V&#xFD;stup programu `gitk` s&#xA0;v&#x11B;tv&#xED; doplneni-autora\"></a></span></p>\n<p>Aktu&#xE1;ln&#xED; v&#x11B;tev &#x2013; <code>doplneni-autora</code> &#x2013; je\nzv&#xFD;razn&#x11B;n&#xE1; tu&#x10D;n&#x11B; a star&#x161;&#xED; <code>master</code> je st&#xE1;le\nna p&#x16F;vodn&#xED; revizi.</p>\n<p>Opus&#x165;me te&#x10F; na chv&#xED;li pr&#xE1;ci na dopl&#x148;ov&#xE1;n&#xED; autora.\nVra&#x165; se do v&#x11B;tve <code>master</code> a vytvo&#x159; z n&#xED;\nv&#x11B;tev <code>doplneni-jmena</code>.\nPak se na tuhle novou v&#x11B;tev p&#x159;epni.</p>\n<div class=\"highlight\"><pre><code><span style=\"color: #00aaaa\">$</span> git checkout master\nSwitched to branch &apos;master&apos;\n<span style=\"color: #00aaaa\">$</span> git branch doplneni-jmena\n<span style=\"color: #00aaaa\">$</span> git checkout doplneni-jmena\nSwitched to branch &apos;doplneni-jmena&apos;\n<span style=\"color: #00aaaa\">$</span> git branch\n  doplneni-autora\n* <span style=\"color: #00aa00\">doplneni-jmena</span>\n  master</code></pre></div><p>Dopl&#x148; do souboru jm&#xE9;no b&#xE1;sn&#x11B; a pomoc&#xED;\n<code>git add</code>, <code>git commit</code> ulo&#x17E; revizi.\nV&#x161;echno zkontroluj p&#x159;es <code>gitk --all</code>.</p>\n<p><span class=\"figure\"><a href=\"/2019/brno-jaro-2019-ut/git/branching/static/branches.png\"><img src=\"/2019/brno-jaro-2019-ut/git/branching/static/branches.png\" alt=\"V&#xFD;stup programu `gitk` s&#xA0;v&#x11B;tvemi doplneni-autora a doplneni-nazvu\"></a></span></p>\n<p>Takhle n&#x11B;jak se d&#xE1; postupovat v&#xA0;situaci popsan&#xE9; v &#xFA;vodu:\nopu&#x161;t&#x11B;n&#xED; rozpracovan&#xE9; verze, p&#x159;echod na &#x201E;stabiln&#xED;&#x201D;\nverzi <code>master</code> a za&#x10D;&#xE1;tek pr&#xE1;ce v&#xA0;jin&#xE9;\n&#x10D;&#xE1;sti projektu.</p>\n<p>Mezi jednotliv&#xFD;mi v&#x11B;tvemi se d&#xE1; podle libosti p&#x159;ep&#xED;nat,\njen je v&#x17E;dycky dobr&#xE9; p&#x159;ed p&#x159;epnut&#xED;m ud&#x11B;lat novou revizi\n(<code>git commit</code>) a pomoc&#xED; <code>git status</code> zkontrolovat, jestli je v&#x161;echno\nulo&#x17E;en&#xE9; v Gitu.</p>\n<p>Na stejn&#xE9;m principu funguje i spolupr&#xE1;ce n&#x11B;kolika lid&#xED;\nna jednom projektu: je n&#x11B;jak&#xFD; spole&#x10D;n&#xFD; z&#xE1;klad\n(<code>master</code>) a ka&#x17E;d&#xFD; d&#x11B;l&#xE1; na vlastn&#xED; v&#x11B;tvi, dokud nen&#xED; se sv&#xFD;mi zm&#x11B;nami spokojen&#xFD;.</p>\n<p>A a&#x17E; je n&#x11B;kter&#xE1; v&#x11B;tev hotov&#xE1;, m&#x16F;&#x17E;e se za&#x10D;lenit\nzp&#xE1;tky do <code>master</code>. Pod&#xED;vejme se jak na to.</p>\n<h2>Slou&#x10D;en&#xED;</h2>\n<p>Ned&#xE1;valo by smysl historii projektu rozdvojovat,\nkdyby pak jednotliv&#xE9; v&#x11B;tve ne&#x161;ly zase slou&#x10D;it dohromady.\nNa&#x161;t&#x11B;st&#xED; je v Gitu slu&#x10D;ov&#xE1;n&#xED; pom&#x11B;rn&#x11B; jednoduch&#xE9;.</p>\n<p>P&#x159;epni se zp&#xE1;tky na <code>master</code>\na pou&#x17E;ij p&#x159;&#xED;kaz <code>git merge</code>, kter&#xFD;\nslou&#x10D;&#xED; jinou v&#x11B;tev s tou aktu&#xE1;ln&#xED;.\nP&#x159;&#xED;kazu mus&#xED;&#x161; d&#xE1;t jm&#xE9;no v&#x11B;tve, kterou chce&#x161; slou&#x10D;it.</p>\n<div class=\"highlight\"><pre><code><span style=\"color: #00aaaa\">$</span> git checkout master\nSwitched to branch &apos;master&apos;\n<span style=\"color: #00aaaa\">$</span> git merge doplneni-jmena\nUpdating e929fb0..c982a81\nFast-forward\n basnicka.txt | 6 <span style=\"color: #00aa00\">+++++</span><span style=\"color: #aa0000\">-</span>\n 1 file changed, 5 insertions(+), 1 deletion(-)</code></pre></div><p>Slou&#x10D;eno! Ono &#x201E;<code>Fast-forward</code>&#x201D; znamen&#xE1;, &#x17E;e\nvlastn&#x11B; nebylo co slu&#x10D;ovat &#x2013; jen se do v&#x11B;tve\n<code>master</code> p&#x159;idaly nov&#xE9; zm&#x11B;ny.\nZkontroluj v&#xA0;<code>gitk --all</code>, jak to vypad&#xE1;.</p>\n<p>A pak zkus slou&#x10D;it i druhou v&#x11B;tev: <code>git merge doplneni-autora</code>.\nTady to bude slo&#x17E;it&#x11B;j&#x161;&#xED;: M&#x16F;&#x17E;e se st&#xE1;t, &#x17E;e zm&#x11B;ny nep&#x16F;jdou\nautomaticky slou&#x10D;it a ve v&#xFD;stupu se objev&#xED; hl&#xE1;&#x161;ka\n<code>merge conflict</code> (konflikt p&#x159;i slu&#x10D;ov&#xE1;n&#xED;).\nV tom p&#x159;&#xED;pad&#x11B; se na soubor pod&#xED;vej v editoru: objev&#xED;\nse v n&#x11B;m obsah z obou konfliktn&#xED;ch verz&#xED;,\nspole&#x10D;n&#x11B; se zna&#x10D;kami, kter&#xE9; upozor&#x148;uj&#xED; na m&#xED;sto\nkde konflikt nastal.\nSoubor uprav ho tak, jak by m&#x11B;l vypadat, ulo&#x17E; a zadej\n<code>git commit</code>.</p>\n<p>A&#x165; nastal konflikt nebo ne, vytvo&#x159;&#xED; se &#x201E;slu&#x10D;ovac&#xED; revize&#x201C;\n(angl. <em>merge commit</em>), kter&#xE9; &#x2013; jako ka&#x17E;d&#xE9; revizi &#x2013; m&#x16F;&#x17E;e&#x161; d&#xE1;t popisek.</p>\n<div class=\"highlight\"><pre><code><span style=\"color: #00aaaa\">$</span> git merge doplneni-autora\nAuto-merging basnicka.txt\nMerge made by the &apos;recursive&apos; strategy.\n basnicka.txt | 2 <span style=\"color: #00aa00\">++</span>\n 1 file changed, 2 insertions(+)</code></pre></div><p>Povedlo se?</p>\n<p><span class=\"figure\"><a href=\"/2019/brno-jaro-2019-ut/git/branching/static/merge.png\"><img src=\"/2019/brno-jaro-2019-ut/git/branching/static/merge.png\" alt=\"V&#xFD;stup programu `gitk` s&#xA0;v&#x11B;tvemi doplneni-autora a doplneni-nazvu slou&#x10D;en&#xFD;mi do master\"></a></span></p>\n<p>Pokud ano, m&#x16F;&#x17E;e&#x161; star&#xE9; v&#x11B;tve vymazat &#x2013; v&#x161;echny jejich\nzm&#x11B;ny jsou v&#xA0;<code>master</code> a nem&#xE1; na nich cenu\npracovat d&#xE1;l.</p>\n<div class=\"highlight\"><pre><code><span style=\"color: #00aaaa\">$</span> git branch -d doplneni-autora\nDeleted branch doplneni-autora (was 0e213cd).\n<span style=\"color: #00aaaa\">$</span> git branch -d doplneni-jmena\nDeleted branch doplneni-jmena (was c982a81).\n<span style=\"color: #00aaaa\">$</span> git branch\n* <span style=\"color: #00aa00\">master</span></code></pre></div><p>Gratuluji, u&#x17E; um&#xED;&#x161; v&#x11B;tven&#xED; a slu&#x10D;ov&#xE1;n&#xED;!</p>\n\n\n        "
    }
  }
}