Zobrazují se příspěvky se štítkemversion control. Zobrazit všechny příspěvky
Zobrazují se příspěvky se štítkemversion control. Zobrazit všechny příspěvky

30. června 2018

Správa proprietárních závislostí v Golang

Se změnou zaměstnání přišly nové výzvy - prototypujeme teď nový produkt a jako primární technologie byl zvolen Golang. Myslím si, že vzhledem k povaze produktu (smečka mikro-servis) a cílové infrastruktuře (IaaS) je to dobrá volba.

Golang není zas až tak nový jazyk (je tady s námi nějakých 9 let), a ačkoliv se v něm příjemně píše, má vývoj v Golangu určitá úskalí a výzvy - to buď v případě, že vám úplně nevyhovuje, jak v Googlu vymysleli vývojový proces, anebo pokud očekáváte vlastnosti běžné na některé zralejší platformě.

Jak já, tak celý tým máme silné Java zázemí a je tedy možné, že náš přístup ke Golang infrastruktuře není úplně adekvátní. Nicméně poslední tři měsíce jsem se tématu verzování, závislostí, reprodukovatelnosti a automatizaci Go buildů intenzivně věnoval a řekl bych, že to soudruzi z U.S.A "nedotáhli úplně dokonce".

Požadavky

Pro náš projekt jsme měli, řekl bych, celkem běžné nároky:
  1. Privátní Git repository za firemní proxy. Kvůli legálním záležitostem a firemním politikám nemůžeme dát projektový kód na GitHub.
  2. Samostatná projektová repozitory. OK, chápu, že v Googlu milují monorepo, ale většina z nás v Googlu nepracuje...
  3. Reprodukovatelný build. To je samozřejmost, k tomu asi není co dodat.
  4. Spolehlivá správa závislostí a jejich verzí. V Javě, nebo na Linuxu je to no-brainer - stačí mít package manager a repozitory, ne?
  5. Plně automatizované. Zase by se řeklo samozřejmost, ale pořád a pořád potkávám lidi, kteří smolí (klidně i produkční) buildy ručně.

Problémy

Pokud budete chtít výše zmíněné požadavky naimplementovat v Golangu, narazíte na problém: out-of-the-box to nejde vůbec a pokud nebudete ochotni část nároků oželet, čeká vás world-class hackování. (Teda ne, že bych byl takovej hustej hacker... spíš jsme narazili na hluché místo.)

Esenciální potíž je, že celý Golang ekosystém je navržený jako jedno velké open-source monorepo (a.k.a. GitHub). Pokud nechcete/nemůžete mít svůj kód na GitHubu, máte problém. Protože:
  • Golang nemá jednotný/dominantní nástroj na automatizaci. Většina projektů na GitHubu builduje makem. make je fajn na kompilaci, ale dělat v něm komplexnější automatizaci je masochismus.
  • Golang nemá dořešený verzování dependencí. Člověk by řekl, že po těch letech to už bude nějak usazený, ale stačí nahlédnout do oficiální wiki stránky, nazvané lapidárně Package Management Tools a zjistit, že pro správu dependencí a verzí existuje nějakejch 20-30 nástrojů. Naštěstí se od loňského léta masivně prosazuje nástroj dep a velmi slibně to vypadá s oficiálním návrhem vgo, který by se snad měl cca na podzim dostat do Go verze 1.11.
  • Oficiální Golang nástroje neumí pracovat se závislostmi, které nejsou ve veřejných repozitářích (GitHub, Bitbucket, GitLab). Jediný podporovaný způsob je nastavit na repozitory HTML meta tag go-import. Což většinou(?) nemáte pod kontrolou.

GOPATH odbočka

Malé vysvětlení pro čtenáře, kteří nejsou Gophers (fanoušci Golangu). Proč jsou výše zmíněné problémy reálnými problémy? Všechny Golang nástroje předpokládají, že vaše zdrojáky jsou soustředeny pod tzv. GOPATH - což je fakticky lokální monorepo.

Protože v Golangu se všechno linkuje a kompiluje staticky, je potřeba mít všechny zdrojové kódy na jednom místě, neexistují binární závislosti. Pro stažení externích závislostí (v Go nazývaných package import) slouží nástroj go get, který de facto naklonuje Git repository dané závislosti do adresářové struktury pod GOPATH.

Pokud bychom pominuli verzování a reprodukovatelnost a soustředili se jenom na kompilaci, máme tady dva základní konflikty:
  • go get neumí klonovat z non-public repozitářů.
  • Pokud nemáte váš projekt pod GOPATH, budete muset s GOPATH nějak manipulovat, aby Go nástroje vůbec fungovaly.


Řešení

Protože jsem husto-krutej drsňák, před kterým bledne jak Phil Marlowe, tak Dirty Harry, tak jsem se nezaleknul, zatnul zuby a všechny problémy vyřešil. Svým způsobem...

Pravdou je, že řešení, ke kterému jsme prozatím doiterovali, byl průzkum bojem - tj. paralelně řešit business požadavky (proč vlastně ten prototyp děláme) a zároveň vyřešit automatizaci buildů (nebo minimálně aspoň kompilaci Golang projektů).

Když začnu s výše popsanými požadavky od konce - pro automatizaci jsme zvolili Gradle. Původně jsme počítali s nějakým polyglot řešením (něco v Javě, něco v Golang), ale nakonec jsme skončili s čistě Golang moduly.

Ironií je, že v celém řešení víceméně žádná Java není (výjimkou jsou Gradle pluginy). Každopádně, Gradle se výborně osvědčil - buildujeme v něm Go, RPM balíčky, Docker image, stahujeme a re-packagujeme binárky z internetu, pouštíme integrační testy, deployujeme do repozitářů a do cloudu atd.

To všechno je hezké, jak ale v Gradlu skompilovat Golang zdrojáky? Samozřejmě, vezmu nějaký hotový plugin. Bohužel, výše naznačené problémy s verzováním Golang závislostí způsobily, že nám žádný plugin úplně nevyhovoval.

A tak jsem si napsal svůj plugin. Řekl jsem si, že základní nástroje v Go fungují dobře a tak je jenom zorchestruju. Takže můj plugin není nic jiného než: wrapper + orchestrátor + lifecycle. Plugin řeší následující věci:
  1. Manipulace s GOPATH, aby fungovaly nástroje, které očekávají zdrojáky v... GOPATH.
  2. Stažení externích závislostí z public repozitářů (pomocí nástroje dep).
  3. Stažení externích závislostí z non-public repozitářů (pomocí Git klonování).
  4. Spuštění testů.
  5. Kompilace binárky.

O správu verzí public závislostí se stará nástroj dep. O správu verzí non-public závislostí se stará plugin (task proprietaryVendors). V případě, že non-public závislosti mají tranzitivní závislosti na public závislostech, je to kombinace obojího. Technický popis je trochu komplexnější, takže zájemce odkazuji do dokumentace: How to handle proprietary vendors; nicméně použití by mělo být (v rámci možností) jednoduché.

Sekvenční diagram build life-cyclu godep pluginu


Problem solved?

Takže... problém vyřešen? Nový Gradle plugin splňuje všechny v úvodu uvedené požadavky a za ty tři měsíce má za sebou stovky úspěšných buildů (build se v GitLab Pipelině pouští pro každý git push). Tudíž zatím ano, funguje to k naší spokojenosti.

Otázkou ale je, jak dlouho to vydrží - verzování závislostí je žhavé téma jak Golang komunity, tak core vývojářů Go. Všichni s očekáváním vzhlížejí ke zmíněnému vgo a tak za půl roku možná bude všechno jinak a nějaký Gradle plugin už nebude potřeba.

Ale nijak se tím netrápím - pár takových Gradle pluginů už jsem napsal: v daný moment vyřešily mou situaci, avšak časem přestaly být potřeba. A to se mi líbí - nástroje, které jsou dostatečně flexibilní a zároveň mají hezký a moderní design. A dobře se v nich dělá. A to jak Golang, tak Gradle splňují.

Externí odkazy


Mind Map


13. listopadu 2017

vimdiff, nástroj drsňáků


Musím se vám k něčemu přiznat... Už patnáct let je Vim můj nejoblíbenější textový editor. A občas, čas od času, i hlavní nástroj na programování.

Umím si poeditovat vimrc, který po léta udržuju a vylepšuju. Dokonce jsem se i naučil trochu Vim script/VimL a napsal dva zanedbatelné a nedotažené pluginy (pro Gradle a WSDL).

Ale vždycky jsem se jako čert kříži vyhýbal jedné věci - používání vimdiff. Nicméně na každého jednou dojde. Z určitých (pro článek nepodstatných) důvodů jsem si nemohl pro nové vývojové prostředí nastavit P4Merge a tak jsem vstoupil do zapovězené komnaty.

Disclaimer: Tenhle článek píšu jako shrnutí toho, jak jsem práci s vimdiff pochopil. Pokud máte víc zkušeností, budu rád, když se podělíte v komentářích.

2-way merge

Nejjednodušší způsob, jak používat vimdiff - pokud pomineme, že umí dělat i "plain old" diff - je 2-way merge: máme vedle sebe dvě okna se zvýrazněnými rozdíly a chceme mezi nimi tyto změny propagovat.

vimdiff, 2-way merge

Stav na předešlém obrázku, který je výchozí pro merge, se dá dosáhnout několika způsoby:
  • Příkazem: vimdiff myFile.txt theirFile.txt
  • Příkazem: vim -d myFile.txt theirFile.txt
  • Kombinací příkazů:
    • vim myFile.txt
    • :diffsplit theirFile.txt
  • Kombinací příkazů
    • vim -O myFile.txt theirFile.txt (vsplit obou souborů)
    • :diffthis (zapne diff na aktuálním bufferu)
    • Ctrl-W Ctrl-W (skok do druhého bufferu)
    • :diffthis(zapne diff v druhém bufferu)

Základní příkazy

Tak, diff máme zobrazený, co s ním? První věc - je potřeba se v diffu umět pohybovat. Kromě toho, že můžete použít jakýkoli skok, který znáte z běžného Vimu, jsou tu dva příkazy, které umožňují skákat po jednotlivých rozdílech:
  • ]c skočí na následující diff
  • [c skočí na předcházející diff

Za druhé - chceme propagovat změny z/do aktuálního bufferu: skočíme na diff, který chceme upravit a:
  • do, nebo :diffget natáhne změny z "druhého" bufferu do toho aktuálního.
  • dp, nebo :diffput propaguje změny z aktuálního bufferu do "toho druhého".

Za třetí - změny uložíme. Kromě příkazů na standardní ukládání (:w, ZZ atd.) se může hodit:
  • :only zavře všechny ostatní buffery kromě toho aktuálního
  • :qall zavře všechny otevřené buffery
  • :only | wq zavře ostatní buffery + uloží stávající + ukončí Vim. Cool!

Eventuálně začtvrté - pokud věci nejdou hladce, může se šiknout:
  • :diffupdate znovu proskenuje a překreslí rozdíly (u komplikovanějších mergů nemusí Vim správně pochopit danou změnu)
  • :set wrap nastavení zalamování řádků (hodí se při velmi dlouhých řádcích, typicky některá XML)
  • zo/zc otevře/zavře skryté (folded) řádky

3-way merge

Nemusím vám říkat, že 2-way merge je pro školáky - profíci makaj v Gitu, či v Mercurialu a tam je dvoucestný merge nedostačující. Ke slovu přichází 3-way merge. Co to je?

Schéma 3-way merge

3-way merge není nic složitého. V podstatě jde o to, že máme dvě verze, které mají společného předka. V mergovacím nástroji pak vidíme všechny tři verze vedle sebe a většinou máme k dispozici ještě čtvrté okno s aktuálním výsledkem merge.

3-way merge v aplikaci


Nastavení Gitu

Nastavení spolupráce Gitu a vimdiff je jednoduché - stačí spustit z příkazové řádky následující sadu příkazů:
$ git config --global merge.tool vimdiff
$ git config --global merge.conflictstyle diff3
$ git config --global mergetool.prompt false
$ git config --global mergetool.keepBackup false

Pokud se podíváte do ~/.gitconfig, měli byste tam vidět:


Nastavení Mercurialu

Nastavení Mercurialu je podobně jednoduché. Otevřeme soubor ~/.hgrc příkazem
$ hg config --edit
a vložíme následující řádky


Sekce [extensions] a [extdiff] nejsou pro merge nutné, ale hodí se, pokud chceme vimdiff používat jako dodatečný externí diff nástroj. Sekundární diff spustíme příkazem hg vimdiff.

Základní příkazy

Základní příkazy jsou stejné jako v sekci 2-way merge, s výjimkou příkazů dp/do (:diffput/:diffget) - pokud bychom je nyní použili, vimdiff nám zahlásí chybu:
More than two buffers in diff mode, don't know which one to use
To je v pořádku: u 3-way merge se ve vimdiff otevřou 4 buffery, všechny v diff módu. Takže do té doby, než se vimdiff naučí komunikovat telepaticky, je potřeba mu říct, ze kterého bufferu chceme danou změnu natáhnout.

vimdiff, 3-way merge v Gitu

Klasické merge flow vypadá následovně:
  1. Začínáme v dolním "výsledkovém" bufferu.
  2. ]c (skočit na následující diff, který chceme mergovat)
  3. :diffget <identifikace-bufferu> získáme změnu z daného bufferu (viz dále)
  4. Opakujeme 2-3.
  5. :only | wq uložíme merge.

Obecně, identifikátor bufferu získáme příkazem :ls. To je ale dost nepraktické a nepřehledné. Další možnost je identifikovat buffer částečným názvem souboru. Tady přichází na pomoc jak Git, tak Mercurial, který přidávají k názvům souborů příhodný suffix.

Merge v Gitu

Git přidává do názvů mergovaných souborů následující suffixy, v pořadí zleva doprava: LOCAL (vlevo), BASE (uprostřed), REMOTE (vpravo). Pro natažení změny z (levého) bufferu LOCAL můžeme použít příkaz :diffg LO.

Výpis bufferů pro Git:
:ls
  1 #a   "./myFile_LOCAL_7424.txt"      line 1
  2  a   "./myFile_BASE_7424.txt"       line 0
  3  a   "./myFile_REMOTE_7424.txt"     line 0
  4 %a   "myFile.txt"                   line 12

Merge v Mercurialu


vimdiff, 3-way merge v Mercurialu

Mercurial přidává do názvů mergovaných souborů následující suffixy, v pořadí zleva doprava: orig (vlevo), base (uprostřed), other (vpravo). Pro natažení změny z (levého) bufferu orig můžeme použít příkaz :diffg orig.

Výpis bufferů pro Mercurial:
:ls
  1 %a   "myFile.txt"                   line 2
  2  a-  "myFile.txt.orig"              line 0
  3  a-  "/tmp/myFile.txt~base.iZwwuA"  line 0
  4  a-  "/tmp/myFile.txt~other.km9Itr" line 0

Co mi (zatím) schází?

Musím říct, že potom, co jsem si vimdiff osahal, pochopil jeho logiku a naučil se jeho příkazy, jsem si ho docela oblíbil.

Jediná výtka zatím jde za jeho neschopností skákat přímo po konfliktech - Git i Mercurial dělají výborně automatické merge a ty jsou samozřejmě vidět ve vimdiffu taky, jako pouhá změna bez konfliktu. Mít nějaký příkaz, který rozlišuje pouhý diff a konflikt, by bylo fajn.

Související články


26. srpna 2014

Mercurial, strategie branch-by-feature


Mercurial je skvělý, distribuovaný Version Control System (VCS, či DVCS), který nabízí velkou míru volnosti, jak s nakládat s verzováním zdrojových kódů. Svobodu většinou chápeme jako pozitivní věc, někdy je ale přílišná nespoutanost na škodu. A tak definování nějaké verzovací strategie prospěje týmu i projektu.

Proč mít verzovací strategii?

Verzovací strategii branch-by-feature jsme s úspěchem použili na stávajícím projektu. Důvody, proč jsme si něco takového definovali byly dva:
  • Když jsem se mihnul na předcházejícím projektu (taky Mercurial), žádná strategie, či konvence definovaná nebyla . Člověk pak slýchal řeči jako: "Proč to furt merguješ?", "Vznikaj ti tam anonymní branche." a "Tam by's měl používat rebase.". Prostě klasický, tohle-tady-všichni-ví a takhle-to-děláme-ale-tobě-jsme-to-neřekli.
  • Chtěli jsme mít na nadcházejícím projektu formalizované code review.

Takže jsme se zamysleli, chvilku nad tím špekulovali a pak jsme, spolu s podporou dalších nástrojů, došli k následující strategii.

Strategie branch-by-feature

Princip téhle strategie je jednoduchý a dá se popsat jednou větou: Pro každou novou feature (nebo bug) se založí nový branch. Hotovo, vymalováno.

A teď trochu obšírněji. Na počátku je v repozitory pouze jeden permanentní branch. Zpravidla se mu říká development branch. Z něj se odlamují další branche pro vývoj - feature branche. Co přesně tyto branche představují, záleží na granularitě položek, do kterých jsme si práci rozdrobili. Může to být user story, feature, requirement, task. Ideálně je to něco, co evidujeme v issue tracking systému (ITS).

Probíhá běžný vývoj a všechny komity jdou do (odpovídajícího) feature branche. Když je vývoj hotový, proběhne code review a pokud jsou změny akceptovány, zamergují se do development branche a feature branch se zavře. Pokud jsou změny zamítnuty, provede se náprava, komitne se do feature branche, následuje code review atd.

Pokud jsou v této fázi nalezeny nějaké bugy, přistupujeme k nim stejně jako k feature. To jest, bug branch -> code review -> merge do development branche.

Verzovací strategie branch by feature

Po nějakém čase vznikne release branch. Pokud jsou v něm nalezeny chyby, vzniká bug branch a po code review přichází merge jak do release, tak do development branche.

Celý postup se dá shrnout do následujících bodů:
  1. Vytvoření nového feature/bug branche.
  2. Development.
  3. Změny projdou code review.
  4. Uzavření feature/bug branche.
  5. (Bugfixy jsou zamergovány do release branche.)
  6. Změny jsou zamergovány do development branche.

Z pohledu příkazové řádky vypadá proces takto:
$ hg branche fb-logging
$ hg commit -m 'Logging feat. has been developed.'
$ hg commit -m 'Close branch fb-logging.' --close-branch
$ hg update default
$ hg merge fb-logging
$ hg commit -m 'Merge branch fb-logging -> default.'

Zcela záměrně se vyhýbám popisu code review. To proto, abych nekradl materiál svému kolegovi Banterovi, který již jistě brzy napíše článek, o tom, jak to děláme (je to fakt cool, tak se těšte). Nicméně, ve vztahu k Mercurialu si nemůžu odpustit, jak to vypadá procesně. Přepokládám, že všichni čtete plynně BPMN ;-)  takže dalších slov netřeba. Mercurial aktivity jsou v oranžovém rámečku.

Code Review proces (oranžové jsou aktivity v Mercurialu, modré v RhodeCode)

Drobná a příjemná vylepšení

Což o to, proces, jako takový, je pěkný. Na někoho je ale možná trochu komplexní. Přece jenom, když mastíte celý život všechno jenom do trunku, může to být trochu moc věcí najednou. Tady je pár věcí, které nám to o něco usnadnili.

Konvence

Konvence jsme měli nastavené jednak pro názvy branchů a jednak pro komitovací komentáře. Název nového branche se skládal z prefixu a čísla issue v ITS. Prefix byl buď fb- (feature branch), nebo bb- (bug branch). Např. fb-42, bb-1024.

Konvence pro komentáře by se daly rozdělit do tří skupin: běžné komentáře, při zavírání branche a při vytváření releasu. Konvence samotná by se v Mercurialu dala pohlídat pomocí hooku, ale nedokopal jsem se k tomu, ho napsat. Pro "běžné", vývojové komentáře jsme měli konvenci WIP #nnn; some comment. WIP je zkratka pro Work In Progress, nnn je id issue v ITS. Např. WIP #1561; Payment button has been removed.

Zavření branche se skládá ze čtyř Mercurial příkazů (commit, update, merge, commit, viz výše) a obsahuje dva komentáře ve formátu:
  • Close branch <branch-name>.
  • Merge branch <branch-name> -> default.

Za zmínku stojí mergovací komentář, ze kterého by mělo být jasné, odkud kam merge proběhnul.

Komentáře při zavírání branche

Releasovací komentáře byly celkem čtyři a obsahovaly klíčové slovo [Release].

Komentáře při vytváření releasu

V předešlém popisu vás možná zarazilo, že jak pro zavření branche, tak pro vytvoření releasu je potřeba spustit čtyři Mercurial příkazy. Dělat to ručně by byla značná otrava a hlavně by celá konvence brzo erodovala do chaosu. Šťastni kdož používají automatizaci, neboť jen ti vejdou do křemíkového nebe.

Mercurial alias

S používáním aliasu přišel kolega Banter, takže mu za to patří dík a rád ho zde zvěčním. Alias samotný vypadá dost ošklivě, zato jeho použití je elegantní. Jedinou vadou na kráse je, že jsme nepřišli, jak alias spustit z grafických nástojů, jako je SourceTree, nebo TortoiseHg, takže ještě budeme muset zapracovat na tom, aby tuto fičurku mohli používat i kolegové, kteří ještě nepřišli na to, jak cool je používat command line ;-)

Alias stačí přidat do souboru ~/.hgrc a spouští se jednoduchým příkazem hg close-feature nnn, kde nnn je (v našem případě) čístlo issue v ITS, tj. to, co je za prefixem fb-.
[alias]
close-feature = ![ -z "$1" ] && echo "You didn't specify a branch!" && exit 1; \
                if hg branches | grep -q "fb-$1"; \
                    then $HG up fb-$1; \
                         $HG commit -m 'Close branch fb-$1.' --close-branch; \
                         $HG pull; \
                         $HG up default; \
                         $HG merge fb-$1; \
                         $HG commit -m 'Merge branch fb-$1 -> default.'; \
                    else echo "The branch fb-$1 does NOT exist!"; \
                fi

Gradle release task

Náš projekt buildujema Mavenem. Chvilku jsem se snažil napasovat Maven Release plugin na naši branchovací strategii, ale pořád to nějak nebylo ono - je to prostě moc šitý na SVN. Pak jsem ztratil trpělivost a odpovídající chování si napsal jako Gradle task. Časem se z toho snad vyklube Gradle plugin.

Task samotný tady uvádět nebudu, protože je asi tak na tři stránky. A taky potřebuje ještě trochu poladit. Zkrátka ještě není zralý na to, abych ho dal z ruky. V podstatě ale dělá pouze to, že přepíná branche, šolichá s Mercurialem a manipuluje s verzí v pom.xml. A dělá to ty hezké komentáře, co jsem uváděl výše.

Pros & Cons

Celý výše popsaný koncept jsme vymysleli ještě před projektem. Pak přišel projekt a emotivně musím říct, že nám to krásně fungovalo. Jako hlavní benefit vidím, že jsme si formalizovali proces code review a s výše uvedenou branchovací strategií to bylo velice efektivní. Dalším plusem byla, "úhledná" práce s Mercurialem, kdy byla radost se prohrabávat verzovanou historií.

K negativům bych zařadil komplexnost. Pokud by nám nešlo o code review, asi by tato strategie byla zbytečná. Zatím mi taky chybí nějaká podpora v grafických a automatizačních nástrojích. Jako milovníkovi CLI mi to osobně nijak nevadí, ale musím myslet taky na ostatní členy týmu (bývalý kolega jim říkal "makáči" :-)  pro které by mělo být používání nástrojů co nejsnadnější.

Je to všechno?

Abyste dostali plný obrázek, jak to celé fungovalo, chybí nám jeden velký dílek skládanky - jo, code review. Takže pokud vám něco nedává smysl, tak je to možná proto, že jsem v tomto článku celkem důsledně odpáral použití dalších dvou nástrojů, které byly s branchovací strategii organicky provázané - issue tracking system a RhodeCode, nástroj, ve kterém jsme, pomocí pull requestů, řešili code review.

Popis code review je na samostatný článek. Tak snad ho Banter brzo napíše a já sem pak lísknu odkaz. A jinak doufám, že vám zmiňovaná strategie branch-by-feature přijde inspirativní.

Happy branching! :-)

Mind Map



Související články

20. května 2013

Mercurial, jak nastavit P4Merge jako nástroj pro vizuální merge a diff

Mercurial je výborný distribuovaný verzovací systém (DVCS). Je free a má spoustu zajímavých vlastností. Perforce (P4) je centralizovaný verzovací systém. Má převážně komerční licenci a výborné nástroje na mergování a branchování. Co můžou mít tyto dva systémy společného?

P4Merge

P4Merge je grafický nástroj pro merge a diff. Je jednou ze silných zbraní P4. Já jsem ho vždycky rád používal. Jeho výhodou je, že akceptuje parametry z příkazové řádky, takže jej lze použít i mimo rámec P4 a to buď úplně samostatně, nebo jako externí nástroj z jiné aplikace. Třeba Mercurialu :-)

Diff pomocí P4Merge

Podle toho, kolik parametrů se zadá na příkazové řádce, se spustí buď diff (2 parametry), nebo merge (3-4 parametry). Každý parametr je cesta k porovnávanému souboru.

Parametry příkazové řádky P4Merge

P4Merge sice není open source, ale je free, takže nic nebrání jeho zakomponování do jiného nástroje.

Konfigurace Mercurialu

Mercurial neobsahuje nástroj na vizuální merge. Pokud je potřeba zmergovat konfliktní změny a žádný nástroj není nakonfigurovaný, tak Mercurial vloží do sloučeného souboru mergovací značky (takový to <<<<<<<<<<< something). To asi nechceme :-)

Mergovacích nástrojů existuje spousta, každý si určitě vybere. Já jsem si oblíbil P4Merge - přece jenom, když něco s oblibou používáte dva roky, tak vám to trochu přiroste k srdci. Jak teda Mercurialu podstrčíme P4Merge?

Konfigurace merge nástroje je v souboru ~/.hgrc v sekci [merge-tools]:
[merge-tools]
p4.priority = 60
p4.premerge = True
p4.executable = p4merge
p4.gui = True
p4.args = $base $other $local $output
p4.binary = False

[extensions]
hgext.extdiff =

[extdiff]
cmd.p4diff = p4merge
cmd.meld = meld
Jak je vidět, nastavil jsem si kromě merge nástroje i externí diff. Takže když pustím příkaz hg p4diff file1 file2, spustí se mi také P4Merge, tentokrát jako diff nástroj.

Merge pomocí P4Merge

Je to opravdu taková idyla?

Není. Abych byl maximálně spokojený, chybí mi (zatím) dvě věci. Jednak bych rád, abych mohl provést hromadný merge - Mercurial totiž dělá to, že pro každý mergovaný soubor sekvenčně spustí P4Merge. A já bych chtěl např. hromadně přijmout příchozí, nebo své změny. Což je věc, kterou P4 normálně umí. Ale asi je to zajištěno přes P4V klienta.

Druhá vada na kráse je, že P4Merge neumí diff více souborů (např. příkaz hg p4diff -r 12:tip). Takže ho nemůžu použít pro vizuální diff mezi revizemi. To je důvod, proč mám v souboru .hgrc jako další externí diff nástroj Meld, který diff adresářů umí.

Meld, vizuální diff mezi revizemi

Máte nějaké tipy na používání P4Merge, nebo jiného vizuálního nástroje na merge v Mercurialu? Budu rád, když se podělíte o své zkušenosti v komentářích.

Související články


29. dubna 2013

Perforce best practices

Po více jak dvou letech se končí moje soupoutničení s verzovacím systémem Perforce (P4). Z počátku nebylo naše soužití zcela harmonické. Ale poté, co jsem přijal pravidla hry (které P4 nastavuje) jsem si tento systém oblíbil. A nyní bych se chtěl o své zkušenosti podělit.

Počáteční rozčarování a zklidnění

Srážka nepřipraveného vývojáře s P4 může být dost nepříjemná a frustrující. Vývojáři mají dost často rutinní zkušenost s SVN a podobnými nástroji. P4 má v některých aspektech jinou filozofii, která (z hlediska třeba SVN) nemusí být intuitivní. Když člověk nepochopí principy, které se za tím skrývají, může dopadnout podobně, jako evropský řidič v Anglii (Irsku, Austrálii, ...) - nadává, jak to "ty pitomý Angláni blbě vymysleli".

Pokud se člověk rozhodne nepřijmout filozofii P4, tak může skončit jako někteří z mých kolegů, kteří pořád trousí hlášky o "debilním Perforsu". Holt rok je asi příliš krátká doba na to, naučit se to pořádně ;-)

Mě zkušenost naučila číst (v) dokumentaci. Rád totiž dělám věci správně a (dobrá či dokonce kvalitní) dokumentace mi přijde jako efektivní způsob jak zjistit, jak věci fungují. A navíc si člověk zbytečně nepřenáší zlozvyky odjinud. Takže než s P4 bojovat, přijde mi lepší přijmout jeho pravidla hry. On se vám za to odvděčí a rozkvete vám pod rukama :-)

Možná teď čekáte, že napíšu něco o té filozofii a o věcech, které jsou "jinak". Ale nenapíšu. Nechci se pouště do nějaké srovnávací studie, kterou by to asi skončilo. Prostě jen teď uvedu, jak P4 používám já.

Typický lifecycle

Následující lifecycle mi vykrystalizoval během těch dvou let používání a osvědčil se mi, jako účinný prostředek proti některým nástrahám P4.
  1. Check Out (Ctrl+E)    konkrétního projektu (nebo jeho části) do nového changelistu (Alt+N -> Alt+C).
  2. Editace zdrojových kódů.
  3. Na changelistu, který chci komitovat: Revert Unchanged Files   .
  4. Na adresáři, který jsem původně checkoutoval: Reconcile Offline Work a přidat eventuální soubory do changelistu.
  5. Kontrola souborů v changelistu. Pokud byly soubory modifikované, tak Diff Against Have Revision (Ctrl+D).
  6. Submit (Ctrl+S -> Alt+S)   .
Z tohoto seznamu bych vypíchnul body 3 a 4. Revert Unchanged Files je důležitý, aby se nekomitovaly nezměněné soubory. Reconcile Offline Work zajistí přidání (Mark for Add   ) nových souborů do changelistu.

Changelisty

Changelist je v P4 seskupením souborů, které chci komitovat. Já si vytvářím nový changelist pro každý kousek práce, typicky jedna položka v issue tracking systému. Novému changelistu pak nejčastěji dávám popis ve stylu: <issue ID>; <issue name>, <description>. Např.: SWS-12; Gradle tutorial, Jetty initial implementation.

Pending Changelists
Na záložku Pending Chagelists, která zobrazuje moje chagelisty, se přepnu klávesovou zkratkou Ctrl+1, nebo ikonou   .

P4 nabízí také tzv. default changelist, který ale používám pouze v jediném případě - pokud v changelistu potřebuju mít něco, co nechci komitovat a později to revertnu. Pokud bych to náhodou přesto potřeboval, vždy se to dá převést do jiného changelistu. Důvod, proč něco nekomitovat a mít to v changelistu je prostý - pokud si natáhnu do lokálního workspace nějakou revizi z depotu, P4 všechny soubory nastaví na read-only. A to může některým editorům vadit. Takže to šupnu do defaultu.

Shelved Files

Aneb soubory na poličce. Někdy mám něco rozpracovaného, ale nechci to ještě komitovat. Zároveň ale nechci, aby úpravy byly pouze u mne na lokálním počítači. Tak je přesunu z changelistu do poličky na serveru.

Shelved Files

Bookmarks

Souborová struktura v rámci daného depotu může být velmi rozsáhlá (na aktuálním projektu je to přes 10 000 souborů). Proto jsem si oblíbil záložky (Bookmarks) s nastavenými klávesovými zkratkami.

Bookmarks

Klávesové zkratky

P4 má výborného grafického klienta: P4V. A tak jako u každé grafiky, i zde se hodí (a efektivitě napomůžou) klávesové zkratky. Tyhle jsem si oblíbil:
  • Get Latest Revision: Ctrl+Shift+G
  • Check Out: Ctrl+E
  • Submit: Ctrl+S -> Alt+S
  • Revert Files: Ctrl+R
  • Diff Agains the Have Revision: Ctrl+D
  • Next Diff (P4Merge): Ctrl+2
  • Previous Diff (P4Merge): Ctrl+1
  • Close (P4Merge): Ctrl+W
  • Pending Changelists: Ctrl+1
  • Submitted Changelists: Ctrl+2
  • Skok na zazáložkovaný soubor/adresář: Ctrl+Shift+1 (až n)
  • Skok do file browseru z daného adresáře/souboru: Ctrl+Shift+S
K dokonalé spokojenosti mi chybí absence dvou zkratek: Revert Unchanged Files a Reconcile Offline Work.

Závěr

Myslím, že dobrá znalost (aktuálně používaného) verzovacího systému patří ke ctnostem každého vývojáře. Za ty dva roky jsme se s P4 docela skamarádili a pokud bych ho někdy v budoucnu zase potkal, tak se rozhodně nebudu zlobit.

A co vy, máte nějakou oblíbenou P4 vlastnost? Nebo vás naopak na něm něco rozčiluje? ;-)

Související články


Externí odkazy

26. června 2012

Perforce, ignorování souborů a adresářů ve streamu

Jak se nám tak rozrůstá aktuální projekt (a postupuje k nasazování na další prostředí), vyvstala nám potřeba branchovat zdrojový kód. V Perforce (P4) se dá jednak klasicky branchovat, nebo se dají používat streamy. Protože streamy poskytují pro správu kódu daleko větší komfort, vybrali jsme si právě tento způsob.

Pro používání streamů je potřeba mít vytvořený streamovaný depot. Ten jsme vytvořili, naimportovali data a ... bylo ještě potřeba nastavit ignore list, protože způsob popsaný v minulém zápisku pro streamovaný depot nefunguje. OK, jak na to?
  1. V menu View -> Streams, nebo ikona .
  2. Kliknout pravým tlačítkem na daný stream (obvykle mainline) -> Edit stream <stream>.
  3. Na záložce Advanced nastavit sekci Ignore.
P4 stream s nastaveným ignore-listem
Jednou z výhod streamovaného depotu je, že ignore list je nastavený na úrovni streamu. Není tedy potřeba jej nastavovat pro každý workspace zvlášť, tak jako v případě nestreamovaného depotu.

4. června 2012

Perforce, instalace serveru P4D

Prozatím jsem byl pouhým uživatelem Perforce (P4). Používám ho už na druhém projektu a začínám mu přicházet na chuť :-)  Chtěl jsem si něco nastudovat ohledně streamů, které asi začneme brzy používat, ale protože nemám na projektu administrátorský práva, který jsou pro založene stream depotu potřeba, nainstaloval jsem si P4 lokálně. O streamech určitě napíšu někdy příště, nyní něco k jednoduché instalaci.

Instalace Perforce Serveru

Instalace Perfoce Serveru (P4D) je velmi rychlá a jednoduchá. Popíšu instalaci pro vývojářské účely - do domovského adresáře. Pro "opravdový" nasazení by přibyly pouze dva kroky: vytvoření uživatele (a ev. skupiny), pod kterým P4D poběží a vytvoření root adresáře pro depot.

Instalaci zahájíme stažením serveru (P4D) a řádkového klienta (P4) z download stránky. Doporučuji stáhnou i grafického klienta (P4V).
  1. Vytvoříme pracovní adresář (root depotu).
  2. Zkopírujeme soubory p4d a p4 do $PATH a nastavíme spustitelný příznak.
  3. Nastavíme proměnnou P4PORT, port na kterém P4D naslouchá. (P4PORT je důležitá i pro klienta a nastavuje se v ní host i port.)
  4. Nastavíme proměnnou P4ROOT, root adresář depotu.
  5. Spustíme server jako daemon příkazem p4d -d.
  6. Server můžeme zastavit příkazem p4 admin stop.
Instalace P4D

Přidání souborů do depotu

Pokud se poprvé přihlásíme grafickým klientem P4V k serveru, který má prázdný depot, nabídne nám možnost tam nějaké soubory umístit:

Přidání souborů do depotu

Hotovo! Server běží, soubory máme naimportovány. Můžeme začít vyšívat...

P4 depot

29. května 2012

Perforce, ignorování souborů a adresářů

Perforce (P4) je komerční version control system (VCS) se spoustou zajímavých vlastností. Jeho asi nejsilnější stránkou jsou vizuální nástroje na správu branchů/streamů a mergování souborů. Největším úskalím, na které může narazit vývojář se zkušeností s "běžnými" open source VCS nástroji àla SVN, je "trochu jiná" filozofie, se kterou Perfoce ke správě verzí přistupuje. Jednou takovou věcí je vytvoření ignore-listu souborů/adresářů, které nechceme komitovat do repository (depot v řeči P4).

Jako hlavní klient pro P4 je určen Perforce Visual Client (P4V), v aktuální verzi 2012.1, která ignore-list umí. Jelikož ale starší verze P4V klasický ignore-list, jak ho známe např. z CVS, SVN, Gitu apod., neumějí a vzhledem k tomu, že je P4 komerční (a tak se ve firmách/na projektech jen tak upgradovat nebude), nebude na škodu si říct, jak ignore-list "vyrobit" ve starších verzích. Následující popis je pro verzi 2011.1.

Ignorování souborů/adresářů se v P4V nastavuje na úrovni workspace a to pomocí mapování depotu (repository) na lokální workspace. Funguje to dobře, ale má to dvě nevýhody - jednak je potřeba ignorování nastavit pro každý workspace (kterých můžu mít víc, např. pro branchování) a jednak nejde ignorování sdílet mezi vývojáři, tj. nastavit je pouze jednou pro daný projekt. Pokud tedy máme tyto skutečnosti na paměti, můžeme se pustit do nastavení:
  1. V menu View -> Workspaces, nebo ikona .
  2. Kliknout pravým tlačítkem na daný worskpace -> Edit workspace <workspace>.
  3. V sekci Workspace Mappings kliknout na View workspace mapping as a text.
  4. Přidat řádky pro ignorování. Důležitý je znak mínus před rootem depotu (-//). Tři tečky (...) znamenají libovolnou hierarchii adresářů.
-//mw/.../SCA-INF/...  //<workspace>/mw/.../SCA-INF/...
-//mw/.../deploy/...   //<workspace>/mw/.../deploy/...
-//mw/.../classes/...  //<workspace>/mw/.../classes/...
Pokud si pohled překlikneme zpátky pomocí View workspace mapping as a tree, měli bychom vidět něco takového:

P4 workspace s ignorovanými adresáři