…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, 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 pomoct 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 zapomene do
zprávy napsat číslo ticketu. Nebo jste jednoduše perfekcionalista 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 stage, se přidá k předchozímu commitu. Tedy pro změnu pouze commit message musíte mít stage č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 stage 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íc 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 teda 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 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. Spoustu 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 aktualizace 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 pusnout 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 říct, 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 říct 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í.