Pár poznámek ke commitování do verzovacích systémů

Od Petr Zemek, 2011-08-11

Přináším několik poznámek ke commitování (bez překladu, protože mě žádný vhodný nenapadá) do verzovacích systémů, abych se na ně mohl odkazovat v diskusích apod., měl je pohromadě a nemusel je psát všude od znova. V příspěvku počítám s tím, že jste součástí většího a dlouhodobějšího projektu a máte rádi pořádek. V opačném případě, např. pokud pracujete na něčem vlastním či pracujete na školním projektu v týmu složeném pouze z nepořádných studentů, moje poznámky s klidem ignorujte :).

Každý commit by měl být atomický

Jeden commit by měl obsahovat buď opravu jedné chyby, nebo přidání jedné funkčnosti, nebo refactoring jedné části kódu, apod. Pokud provádíte více nesouvisejících úprav, rozdělte je do více commitů. Představte si, že si při opravě chyby X všimnete, že v komentáři na začátku souboru jsou uvedeny nesprávné informace. Většina lidí tento komentář upraví a pokračuje v opravě chyby X. V horším případě pak na úpravu komentáře ani neupozorní. Problém nastane, pokud později zjistíte, že byste potřebovali vrátit opravy oné chyby X. Jelikož jste ale kromě její opravy ještě upravovali komentář, tak po revertu dojde k tomu, že komentář je zase špatně, a přitom s onou chybou X vůbec nesouvisel. Pokud v jednom commitu bude změn třeba deset, tak bude velice problematické rozlišit, které změny se oné chyby X týkají a které ne.

Když chcete udělat více úprav najednou, rozdělte je do více commitů. Poznačte si, co je špatně, a vraťte se k tomu po opravě chyby, na které právě pracujete. Pokud zjistíte, že před samotnou opravou chyby byste potřebovali kód jistým způsobem upravit (např. si jej předpřipravit), vytvořte si branch či novou kopii repozitáře, proveďte v ní změny, proveďte merge/update, a pokračujte v opravě chyby.

Full disclosure: Dříve jsem vytvářel nehorázně dlouhé commity (např. jsem si během práce značil, co jsem všechno udělal, a pak to copy&pastnul do commitu). Za otevření očí děkuji Liborovi. V současnosti nemám problém provést třeba 50 commitů za den.

Navzájem závislé úpravy by měly být commitovány společně

Pokud commitnete navzájem závislé úpravy ve více commitech, může nastat problém při revertu, kdy revertujete pouze jednu část změny a na ty další zapomenete. Z tohoto důvodu commitujte navzájem závislé úpravy společně. Jestliže to z nějakých dobrých důvodů není možné, alespoň to zmiňte ve zprávě ke commitu (commit message).

Pište kvalitní commit messages

V commit message by mělo být zmíněno (1) co se změnilo a (2) proč se to změnilo. Na bod (2) mnoho lidí zapomíná, ale to je to nejdůležitější, co by měl commit message obsahovat. Je sice fajn, že napíšete "DHT is now used instead of an explicit peer list.", ale co vás k té změně vedlo? Je to oprava nějaké chyby? Zlepšení výkonnosti? Je to feature? Je to úprava z důvodu změny protokolu? Spousta informací lze získat přímo z popisu změn ve zdrojovém kódu, ale důvody ke změně to mnohdy nejsou.

Nejhorší commit messages, které můžete vidět, jsou ty typu "Fixed a bug.", bez dalšího dodatečného vysvětlení. Co to bylo za bug? Jaké jsou důvody, proč byla zvolena právě tato oprava, a ne jiná? Myslete při vytváření commit messages na čtenáře. Třeba to budete právě vy, kteří se k tomuto commitu za půl roku vrátí, a budete si trhat vlasy z toho, že jste se předtím více nerozepsali. Pokud je třeba, tak ať onen commit message klidně obsahuje deset odstavců textu.

Osobně (s ohledem na verzovací systémy a zobrazování logů) většinou vytvářím commit messages v následujícím tvaru:

Část projektu/jeho podčást: Co se změnilo.
 
Proč se to změnilo.

Když nad tím přemýšlím, tak nejhorší commit message (když vynechám prázdný text) bude asi My today's work. :).

Necommitujte zbytečnosti

První zbytečnost jsou nadbytečné bílé znaky na koncích řádků. Kromě velmi speciálních případů (např. zdrojáky pro jazyk whitespace :]) k ničemu nejsou a akorát způsobují potíže při merge či při prohlížení provedených změn. Buď si vhodně nastavte svůj editor, nebo přebytečné bílé znaky ze souborů odstraňte před commitem "ručně" (např. přes sed).

Druhá zbytečnost jsou soubory (většinou binární), které lze vytvořit ze zdrojových souborů. Mezi ně patří např. objektové soubory, binárky či pdf soubory od dokumentace. Každá změna pak způsobí, že kromě zdrojových souborů musíte commitovat i ono "smetí", nehledě na to, že různí vývojaři používají různé operační systémy na různých architekturách apod. Jako výjimku z tohoto pravidla bych zmínil situaci, kdy chcete uživatelům vašeho repozitáře vyjít vstříc v tom smyslu, že si k vygenerování dokumentace nebudou muset instalovat spousty nástrojů, které stejně nepotřebují.

Dávejte si pozor na to, co commitujete

Před každým commitem si zkontrolujte, že (1) projekt je přeložitelný, (2) nezanesli jste do něj zásadní chyby (lze zkontrolovat např. spuštěním sady testů), a (3) commitujete vše, co je potřeba, a na nic jste nezapomněli. Váš kolega, který na stejné části kódu pracuje s vámi, to jistě ocení. Opravdu nemám rád bolesti hlavy, které způsobují vývojaři, kteří zapomínají přidat do správy kódu lokální soubory, kdy projekt pak není přeložitelný.

Pokud máte dojem, že někomu svými commity způsobíte trable, vytvořte si branch, změny proveďte v ní, a až bude vše hotové a funkční, proveďte merge do hlavní větve.

Při úpravách se držte stylu použitém v upravovaném souboru

Tento poslední bod až tolik se samotným commitováním přímo nesouvisí, ale i přesto jsem se ho rozhodl zde uvést. Pokud upravujete cizí zdrojový kód, držte se formátování, které je v tomto kódu použité. V opačném případě dojde časem k situaci, kdy každý kus onoho zdrojáku bude psán jiným stylem, s jiným odsazením, apod., což je pro údržbu velmi nepříjemné.


Odkazy pro další čtení


Otázky na závěr

Co si o mých poznámkách myslíte? Co byste k nim přidali vy? Který zlozvyk při commitování vám nejvíce vadí?

Obsah tohoto pole je soukromý a nebude veřejně zobrazen.

Filtrované HTML (využíváno)

  • Povolené HTML značky: <a href hreflang> <em> <strong> <cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <table>
  • Zvýraznění syntaxe kódu lze povolit přes následující značky: <code>, <blockcode>, <bash>, <c>, <cpp>, <haskell>, <html>, <java>, <javascript>, <latex>, <perl>, <php>, <python>, <ruby>, <rust>, <sql>, <text>, <vim>, <xml>, <yaml>.
  • Řádky a odstavce se zalomí automaticky.
  • Webové a e-mailové adresy jsou automaticky převedeny na odkazy.
CAPTCHA
8 + 6 =
Vyřešte tento jednoduchý matematický příklad a vložte výsledek. Např. pro 1+3 vložte 4.
Nějak se mi tady rozmohl spam, takže poprosím o ověření.

Libor (neověřeno)

12 years 8 months zpět

Díky za pochvalu, aspoň něco jsem tě naučil :D.

K tématu bych doporučil používat git i pro svn repozitáře, protože se v něm snadněji vytvářejí atomické commity.

1. rebase umožňuje změnit pořadí, sloučení apod.
2. add -i řeší řadu různých úprav v jednom souboru
3. stash umožňuje rychlou změnu kontextu, kdy mám rozpracovaný velký celek
4. mnohem lepší podpora pro vytváření a mergování větví. Když si vzpomenu, jaké problémy byly s SVN, tak už se mi nechce nikdy vracet.

A jako bonus je opravdu umění zapomenout v gitu přidat do repozitáře nějaký soubor. Ale zase je potřeba si pohlídat, že se skutečně commit dostane až na server.

Ještě bych čtenářům doporučil se vyhnout v svn externalům, především na plovoucí revize. Dokáží značně znesnadnit práci s repozitářem a u plovoucích se ani nelze jednoduše vrátit do stavu t mínus x.

Za sebe můžu říct, že raději mám neatomické commity s dobrým logem, než atomické s žádným logem (sem počítám i "dnešní práce", "gui", "minerálka" apod.).

Taky je docela zajímavé, jak se verzovací systémy chovají k prázdným adresářům: v CVS už zůstanou navždý (nejdou smazat), svn se k nim chová vcelku podle očekávání, do gitu nejdou samostatně přidat. Existuje různé obezličky, jak "prázdný" adresář v gitu vytvořit. Ale když vám někdo přidá prázdný adresář do svn repozitáře a vy používáte pro přístup k tomu repozitáři git a vidíte jen zprávu "Pokusný commit", tak dá docela zabrat, než příjdete na to, co se stalo.