Přejít k navigační liště

Zdroják » Různé » Jasně, umím Git…

Jasně, umím Git…

Články Různé

Tagování, větvení, opravy commitu, stash a další operace. O tom je dnešní článek.

Nálepky:

Text původně vyšel na autorově blogu.

Jasně, umím Git…

…tak to pěkně kecáš! ;-) Tedy pokud jsi nepoužil Git ve větším týmu s několika aktivními větvemi.

Nejednou jsem slyšel (nebo jen viděl v CV) a určitě ještě hodně krát uslyším, jak někdo „umí Git“. Po otázkách typu „U jakého projektu jste Git používal?“, „Kolik lidí v týmu bylo?“ či „Kolik jste měli přibližně aktivních větví?“ je hned jasno.

Ale nikomu se nedivím. Než jsme u nás v týmu přešli na Git, používal jsem ho jen na své malé projekty, kam jsem přispíval na 99 % pouze já do jediné větve – master. Přečetl jsem si knihu Pro Git (v češtině na knihy.nic.cz), vyzkoušel si téměř vše a občas z toho i něco málo udělal. Samozřejmě jsem se v té době hodnotil, jako že Git umím více než dobře. Po přechodu v našem týmu jsem přesto brzy udělal průšvih a museli jsme repositář opravovat.

Dnes už tedy vím, jak jsem byl mimo. Nechci tím říkat, že byste měli jít a smazat si Git z CVčka (budu ale rád za poznámku, kde a jak jste ho používali!), spíš vám chci pomoci do začátku s užitečnými tipy. Z knih se dočtete většinou teorii a jak vše funguje od A do Z. Ale bude vám chybět, co, kdy, jak, proč použít, což chci napravit následujícím seznamem.

1. Konfigurace

Začneme zlehka. S konfigurací. Přizpůsobíme si prostředí, aby maximálně vyhovovalo.

Barvičky

Nejvíc základní (tedy po nastavení user.name a user.email) jsou barvy. Zobrazit si status nebo diff obarveně rozhodně zvýší efektivitu.

git config --global color.ui yes

Prompt

Je docela šikovné si nakonfigurovat konzolový prompt, abyste vždy měli na očích, ve které větvi jste, a případně také v jakém stavu. Tím se eliminují chyby, kdy zapomenete, ve které větvi se nacházíte a provedete něco… špatného. Jako třeba pushnout vývojovou větev do produkční, protože přeci naposled jsem byl v produkční, sakra!

Osobně používám následující prompt:

[michal@dev] 12:34:56 789 ~/workspace/emptygit
master$

Vždy tedy vidím, ve které větvi jsem, a pokud mám Git ve stavu „nothing to commit“, pak název větve není tučný. Kód, které je potřeba vložit do .bashrc, mám na GitHubu ve svém msh (my or Michael’s shell).

Pokud chcete zajít ještě dál, doporučuji oh-my-git, který zobrazí všechno možné.

Pushování pouze aktuální větve

Příkaz git push automaticky pushuje všechny větve, které jsou svázané s nějakou vzdálenou větví. Pokud máte commity ve dvou větvích a chcete pushnout jen jednu z nich, musíte specifikovat, kam pushovat. Pak se ale může stát, že budete ve větvi new-cool-feature a napíšete ze zvyku git push origin maser. A jéje.

Proto je dobré si nastavit, že git push bude pushovat jen aktuální větev, nikoliv všechny.

git config --global push.default current

Kdybyste náhodou potřebovali poté pushovat všechny větve, najděte si to v manuálu. Tohle si nemusíte pamatovat, protože to stejně nebudete nikdy potřebovat. :-)

Merge changelogů

Jestliže gitujete aplikaci s debianím balením, setkáte se s merge hellem, který nikdo nerad řeší. Sice téměř vždy není co řešit, ale stejně to nikoho nebaví. Naštěstí existuje speciální mód mergování právě pro tyto situace: http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=lib/git-merge-changelog.c

2. Základní operace

Log

Klasický git log odvede svou práci, ale každému prostě sedne něco jiného. Naštěstí lze log konfigurovat. Osobně jsem si oblíbil tento:

git log --pretty=format:"%Cgreen%h%Creset %ad %C(cyan)%an%Creset - %s%C(red)%d%Creset" --graph --date=short

Pokud potřebujete vidět log ze všech větví, pomůže parametr --all. Užitečné, pokud se potřebujete podívat na detail, jak se mergovalo a jaké jsou ve všech větvích aktuální stavy.

Aliasy

Jelikož si ale předchozí příkaz nelze zapamatovat, a i kdyby, nikoho nebude bavit neustále vypisovat, je možné vytvořit aliasy. Aliasy lze udělat na všechno možné, uvedu jen příklad pro předchozí příkazy.

git config --global alias.l 'log --pretty=format:"%Cgreen%h%Creset %ad %C(cyan)%an%Creset - %s%C(red)%d%Creset" --graph --date=short'
git config --global alias.ll 'log --pretty=format:"%Cgreen%h%Creset %ad %C(cyan)%an%Creset - %s%C(red)%d%Creset" --graph --date=short --all'

Prvním příkazem jsem si vytvořil alias git l, což mi provede zmíněný log. Druhý příkaz vytvoří alias git ll, což je ten samý log přes všechny větve.

Tig

I když je Git na příkazové řádce fajnový a lze si různě nakonfigurovat, stále nastane situace, kdy je potřeba něco grafického. Tig je právě jedním takovým programem. Pro konzoli. Používám velice často.

Grafické nástroje

Jako skutečným grafickým nástrojem budiž gitk či gitg, ale s nástrojem tig není potřeba konzoli opouštět.

Oprava commitu

Může se stát, že do commitu zapomenete zahrnout nějaké nové soubory. Nebo ještě najdete jednu chybku a nechcete to ukazovat v logu. Nebo zapomenete do zprávy napsat číslo ticketu. Nebo jste jednoduše perfekcionista a chcete si ve zprávě opravit hrubku. Tak přesně na to všechno tu je parametr --amend. Díky tomuto parametru lze opravit poslední commit.

git commit --amend

Představte si to jako kdybyste udělali další nový commit, ale sloučil se s tím předchozím. Tedy cokoliv přidáte do stashe, se přidá k předchozímu commitu. Tedy pro změnu pouze commit message musíte mít stash čistý, samozřejmě.

Ale pozor! Tímto vlastně starý commit smažete a přestane existovat. Za žádnou cenu nesmíte takovou změnu provést, pokud jste již poslední commit pushnuli. Tím byste kolegům repositář rozbili!

Přidání jen části souboru

Často se mi stává, že při programování featury najdu ve stejném souboru chybu. Nenechám ji tam samozřejmě ležet a opravím ji. Ale nechci ji pak commitnout spolu s novou featurou. Tedy potřebuji commitnout jeden soubor na dvě části. Je možnost nejprve něco odmazat, commitnout, a pak to zase vrátit. Proč to však dělat krkolomně, když mohu využít parametr -p (patch):

git add -p

Tak dostanu na výběr, co chci do stashe přidat.

Proč bych něco takového chtěl dělat? Většinou to asi tolik nevadí, ale pokud ta chyba není nějaký překlep nebo drobnost, lepší je to rozdělit. Pak při zpětném dohledávání je mnohem jasnější, co se dělalo a proč. Pokud už jste to nechtě commitli nebo jste prostě lenoši, je dobré alespoň uvést do commit message, co vše v tom commitu je.

3. Pokročilejší operace

Cherry-pick

Když si vzpomenu, kdy jsem o cherry-picku slyšel poprvé, vybavím si strach. Bál jsem se toho, co mi to provede. Moc jsem tomu nevěřil. Přitom na tom nic není…

Situace: dělali jste featuru a narazili jste na chybu. Tu jste (díky předešlému tipu) commitli zvlášť, ale do vývojové větve. Objeví se u vás produktový manažer a oznámí vám, že to je kritická chyba a musí jít ven co nejrychleji. Nejlépe ihned.

Máte na výběr: buď se přepnete do správné větve a kód tam upravíte ručně a znovu commitnete. Nebo se jednoduše přepnete do správně větve, zavoláte cherry-pick, což znovu aplikuje commit v aktuální větvi a jste hotovi.

git cherry-pick #commithash

Mimochodem lze cherry-picknout také více commitů najednou. Tedy není problém ani pokud situace nebude o malé chybě, ale o celé vetší feature o několika commitech.

Zpětné větvení

Představte si situaci: začnete novou featuru. Uděláte commit. Dva. Tři. Zjistíte, že to bude celé komplikovanější a nechcete ostatním rozbít kód. Jenže už jste začali ve sdílené větvi…

Možná vás teď překvapím. Sice se ta větev jmenuje tak, jako na serveru, ale už jen tím, že jste si ji stáhli k sobě, jste v podstatě začali novou. Proto se říká, že je Git decentrializován. U vás to je jiná větev a vy jen posíláte commity z této větve do té vzdálené, odkud si to všichni synchronizují. Proto se může stát chyba, že pushnete commity z vývojové větve do provozní, jak jsem popisoval v sekci „Pushování pouze lokální větve“. To je hodně důležité si uvědomit. Abych to ještě trochu zkomplikoval: větev je pouze ukazatel na commit.

Když si to uvědomíte, zjistíte, že vlastně Git odvětvil automaticky a situaci o dva odstavce výše lze řešit velice jednoduše. Nejprve vytvořím novou větev s novými commity a poté vrátím ukazatel u mé lokální větve o X commitů zpět.

git branch newfeature
git reset --hard HEAD~x

Kde místo x dosaďte počet commitů.

Stash

Řekněme, že jste procesní šampion ve větvení, ale stále nastávají situace, kdy máte rozdělanou práci a potřebujete na chvíli odskočit udělat něco jiného. Commitovat však ještě nechcete a clonovat si nový Git repozitář vás už také nebaví. Řešení je jednoduché: stash.

stash rozdělané změny jednoduše uloží bokem a vyčistí pracovní kopii. Tím si můžete odskočit udělat fix v jiné větvi a pak se zase vrátit k rozdělané práci příkazem stash pop.

git stash
git stash pop

Dokonce, pokud se po návratu rozhodnete spíše pokračovat v nové větvi, není problém… Tohle tedy patří mezi věci, které použijete asi jednou za uherský rok. :-)

git stash branch newfeature

Edit: Pozor – existuje také git stash drop, což vaši práci zahodí. Doporučuji neplést. Případně lze používat git stash apply, jak doporučuje topa v diskuzi pod článkem.

Submoduly

Hodně lidí na ně nadává, ale to spíš proto, že jim nerozumí. Osobně se mi líbí. Pro BOObook.cz používám například Bootstrap, Font Awesome, Closure Library a další. Mohu buď přijít na jejich stránky a stáhnout si kód. Nebo si dát do mého repositáře odkaz na repositáře těchto komponent na konkrétní commit. Což je to, co submoduly dělají – drží cestu ke Gitu a hash commitu.

Jakou to má výhodu? Jedna, že mohu jednoduše upgradovat. Nemusím znovu stahovat kód a doufat, že jsem stáhl vše, co je potřeba. Dokonce mohu upgradovat podstatně detailněji, mohu upgradovat na konkrétní commit. Klidně i downgradovat, když na to přijde. Druhá, že mi nebobtná můj projekt. Spousta takových komponent není zrovna malých. A třetí, pokud uvidím problém či změnu, mohu se podívat na blame a zjistit, kdy a proč to v tom submodulu vzniklo.

Proto mám submoduly rád. Je ale potřeba s nimi umět pracovat.

Ten, kdo spravuje submodule, ho musí přidat: git submodule add. Poté ostatní, když si aktualizují, si musí ten modul zinicializovat (protože si stáhnou jen odkaz; teď je potřeba vycheckoutovat submoduly): git submodule init.

Ten, kdo spravuje submodule, občas musí upgradovat. Jednoduše vleze do adresáře submodulu a checkoutne se na commit, který chce. Poté se vrátí o úroveň výše do svého repositáře a tam commitne jako jakýkoliv jiný soubor. Ostatní po aktualizaci uvidí, že tam je změna a musí si stáhnout změny (zase se jim stáhl jen update ukazatele), takže musí zadat: git submodule update.

A to je celý zázrak. Ten, kdo nespravuje submodule, si stačí pamatovat pouze init při prvním setkání submodulu (většinou při klonování, nové za běh projektu moc nevznikají) a update po aktualizaci ukazatele.

Pak je tedy ještě jeden příkaz: git submodule sync. To zase musí udělat každý, pokud se změnila adresa submodulu. Buď to a nebo znovu vyklonovat.

4. Týmový duch

Tagování

Ať už v týmu či v projektu o jednom vývojáři, doporučuji tagovat. Tak se dá případně kdykoliv dohledat, co přesně za kód v dané verzi byl. Je pravda, že jsem takhle dohledával pro konkrétní verzi asi jen dvakrát, ale stejně je hezké vidět releasy i v Gitu a ruce přidáním tagu neupadnou. Při vydání verze se stejně musí upravit setup.py, debianí changelog či cokoliv jiného. Stačí tuto změnu otagovat taky verzí. V Gitu se lze pak na tag dostat jednoduše pomocí git checkout tagname.

Merge vs. rebase

Především lidi po přechodu z SVN mají tendenci pushovat po každém commitu. Za prvé – nedělejte to. Za druhé to má neblahé důsledky, protože jak jsme si řekli, jen vyclonování způsobí de facto odvětvení. Pokud potom chcete pushnout a někdo to stihl před vámi, musíte pullnout změny a pushnout znovu. To vytváří nepřehledné „kolejničky“. Co to je?

Většinou takové drobné commitování je u maintenance při opravě bugů a opravdu není nutné takové kolejničky vytvářet. Lepší je pro to použít rebase. Rebase znamená, že vaše commity odebere, fast-forwardne na poslední commit, který ve vzdálené větvi je, a poté vaše commity znovu aplikuje.

Tím se stanou dvě věci – nevytvoří se kolejničky a vytvoří se nové commity. S novým hashem. Tedy je to podobné, jako jsme probírali u ammend, – nesmí se rebasovat pushnuté commity!

Defaultně tedy git pull dělá merge. Jednoduše lze však říci, aby se raději zvolila metoda rebase:

git pull --rebase

Způsob větvení

Mít větev master jako stabilní větev nebo jako vývojovou? Mít pro každý aktivní release jednu aktivní větev? Dělat větev pro každou featuru? Dělat větev dokonce pro každý malý bug? Které všechny větve mít na vzdáleném serveru? Jak to mergovat mezi sebou?

To jsou jsou asi nejdůležitější otázky u začínajícího projektu. Nedokážu vám říci správnou odpověď. Všechny jsou správné. Záleží jen na vás, vašem kolektivu a jak to zapadá do vašeho způsobu releasování. To je krása Gitu – používáte ho tak, jak vám vyhovuje.

A už dost! S tímhle si už vystačíte.

P.S.: Možná se vám bude hodit Git Extras. Šikovná zjednodušovátka. Různé statistiky či mazání vzdálených větví apod. levou zadní.

Komentáře

Subscribe
Upozornit na
guest
23 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
tux.martin

Co delam blbe?

martin:~$ git --version
git version 1.8.3.2
martin:~$ 
martin:~$ git config --global color.* yes
error: invalid key: color.*
martin:~$
Martin Hassman

Upravil jsem to i v textu.

Stano

Veľmi sa mi páči nadstavba nad Git-om Git Flow, ktorá rieši správu vetiev. Sú tam vetvy develop, production, fix vetvy odvodené z produkt vetvy a feuture vetvy odvodené z develop.
Pozrite si úvodný blog.http://nvie.com/posts/a-successful-git-branching-model/ alebo cheatsheet http://danielkummer.github.io/git-flow-cheatsheet/

mstehno

git config –global push.default current .. je obsolete … v git + 2+ je defaultni mod simple

.

git commit –amend imho pracuje se staged changes a na stash vubec nesaha…

Svaťa

Větvení nic nestojí, lokálně klidně pro každý commit :-)

Horší je spravovat 100 větví v centrálním repositáři.

John

No a proto je lepsi pouzivat github flow. Po mergnuti vetve do masteru ji smazat. Tak budete mit jen master vetev (kter by mela byt deploynutelna kdykoliv – tj. prochazi vsechny unit testy a proslo code review) a vetve ve kterych probiha vyvoj. Kazda vetev by nemela zit dele nez par dni (idealne max. 1 den).

Gitflow se spis hodi na projekty, kde mate releasy (trochu zavani waterfallem). Github flow je idealni kdyz releasujete skoro kazdy den (doporucuju).

Bystroushaak

No a proto je lepsi pouzivat github flow. Po mergnuti vetve do masteru ji smazat. Tak budete mit jen master vetev (kter by mela byt deploynutelna kdykoliv – tj. prochazi vsechny unit testy a proslo code review) a vetve ve kterych probiha vyvoj.

+1

Pokud hostujete projekt na githubu, tak to má navíc tu výhodu, že první větev, která se návštěvníkům zobrazí bude vždy release. To je dobré i z hlediska třeba šéfa, který už není s githubem tak dobře obeznámen a jen se občas potřebuje mrknou, že něco děláte.

arron

Což ovšem vyžaduje i poměrně sofistikovanu architekturu aplikace. Ne každý si může dovolit mít v release větvi (v tomto případě master) feature, která se ještě nemá nikde zobrazit, protože napřiklad ještě nenastal ten správný čas, nebo nejsou k dispozici „ostrá“ data apod. Zároveň jsou features, které se prostě vyvíjejí i několik měsíců, je potřeba je testovat u klienta (čili musí se releasovat na nějakou testovací verzi), ale za žádnou cenu se nesmí objevit na produkci (ať už z toho důvodu, že to „všechno rozbije“ nebo i z marketingových důvodů). Pak Tebou popisovaný systém přestává velmi rychle fungovat :-)

Jakub Vrána

Aktivní features je lepší řešit v runtime aplikace než pomocí větví. Podrobněji na https://secure.phabricator.com/book/phabflavor/article/recommendations_on_branching/

arron

A já ve svém příspěvku netvrdím opak. Jenom to, že aby to takhle mohlo fungovat, tak to musí mít podporu v aplikaci, což není IMHO uplně obvyklé.

ZdenekHenek

Zajimave shrnuti. Git pouzivam jiz dlouho, ale vetsinou jsem pouzival jen zakladni prikazy, tig a centralni repozitar s web rozhranim http://www.gitblit.com/ kde si muzu treba nadefinovat, ze kdyz nikdo nemuze odstranit zadny commit, pouze administrator.

Bystroushaak

Tohle tedy patří mezi věci, které použijete asi jednou za uherský rok. :-)

Zvláštní, zrovna stashe používám poměrně často, i když v repozitáři dělám většinou sám.

Jakub Navrátil

Při práci s gitem používám někdy konzoli, ale pro rutinní operace a přehled všech verzovaných projektů se mi osvědčila aplikace SourceTree http://www.sourcetreeapp.com/
Především jednoduchost správy Remotes, GitFlow atd.

Johny Patera

Kdo nezna, tak doporucuji zkusit take ungit
https://github.com/FredrikNoren/ungit#ungit
osobne pouzivam uz na nekolikatem projektu a pomerne spokojenost. Na par veci sice obcas musim do konzole, ale na beznou rutinu je to super.

Bystroushaak

To vypadá super. Zkusím v práci, jak se to osvědčí.

Bystroushaak

Tak jsem zkusil, ale musím říct, že větší krám jsem snad neviděl. Nejen že to má asi milion závislostí, ale navíc je to nenažrané co do paměti i CPU a ještě ke všemu to skoro nic neumí.

Míra

Zdravím,
podle mých zkušeností hodně záleží na tom co si dotyčný představuje pod pojmem v titulku. Jestli to má být schopnost odříkat desítky parametrů zpaměti nebo pochopit systém práce s gitem.
Používáme git na několika projektech v cca 100 lidech. Jde o více repositářů každý obvykle s několika aktivními větvemi. Příkazovou řádku používám minimálně, prakticky vše dělám přes gui (včetně např. branchování a mergování). Pokud dotyčný nechápe co dělá, tak mu ani příkazová řádka nepomůže.

dword

Představte si to jako kdybyste udělali další nový commit, ale sloučil
se s tím předchozím. Tedy cokoliv přidáte do stashe, se přidá k
předchozímu commitu. Tedy pro změnu pouze commit message musíte mít
stash čistý, samozřejmě.

Zde se autorovi plete pojem stash (odkladaci prostor) s pojmem stage (obsahuje veci, ktere se zahrnou do commitu).

Ale pozor! Tímto vlastně starý commit smažete a přestane existovat. Za
žádnou cenu nesmíte takovou změnu provést, pokud jste již poslední
commit pushnuli. Tím byste kolegům repositář rozbili!

To neni pravda, dostanete se jen do konfliktniho stavu, kde to autorita muze vyresit prikazem git push –force, jakmile je vse konzistentni.

dword

oprava:
git push –-force
nebo:
git push -f

dword

no ze ja se vubec snazil, kdyz autor na to sere!

JackHat

Náhrada za většinu grafických udělátek je pro mě alias git tree:

git log --oneline --decorate --all --graph

Taky doporučuju mergtool a difftool – mergetool zavolá nástroj na řešení konfliktů, když se do nich člověk dostane při rebase nebo merge, difftool používám na zjišťování rozdílů mezi větvemi/tagy/commity. U obojího mám nastaveny gvimdiff, a je to paráda.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.