komitTakécommitnout, revize, changesetZákladní

Definice

Commit je zapsání skupiny změn tak, aby se staly trvalou a nedělitelnou součástí systému. Ve verzovacím systému jako Git jde o snímek obsahu repozitáře s odkazem na předchozí commit, autorem a popisem. V databázi commit uzavírá transakci a potvrzuje všechny její zápisy najednou.

Kategorie: Softwarový vývojAktualizováno

Nezaměňujte: Commit označuje v systémech správy verzí zápis snímku změn do historie projektu, zatímco v databázích jde o potvrzení a trvalé uložení transakce.

<h2>Dva světy jednoho slova</h2> <p>Slovo commit se v praxi používá ve dvou oddělených významech, které spojuje jedna myšlenka: rozdělaná práce se v jednom okamžiku stane oficiální. Ve verzovacích systémech commit ukládá stav souborů do historie projektu. V databázích commit ukončuje transakci a zpřístupní její změny ostatním. V obou případech platí, že před commitem je práce soukromá a odvolatelná, po něm je součástí sdíleného stavu.</p> <h2>Co přesně commit v Gitu obsahuje</h2> <p>Commit v <a href="/slovnik/git">Gitu</a> není seznam řádků, které se změnily, ale úplný snímek stromu souborů. Objekt commitu nese odkaz na kořenový strom, jeden nebo více odkazů na rodičovské commity, jméno a čas autora, jméno a čas committera a zprávu. Z tohoto obsahu se spočítá hash (dnes SHA-1, s postupným přechodem na SHA-256), který slouží jako identifikátor.</p> <p>Rozdíl mezi commity, tedy to, co vidíte v <code>git diff</code>, se dopočítává až při zobrazení. Protože hash závisí i na rodiči, změna kteréhokoli staršího commitu změní identitu všech následujících: proto se přepsaná historie po <code>rebase</code> nebo <code>amend</code> chová jako nová větev událostí a vyžaduje vynucený push.</p> <h3>Staging area jako mezikrok</h3> <p>Git mezi pracovní adresář a commit vkládá index (staging area). Příkaz <code>git add</code> do něj vybere, co se má zapsat, a teprve <code>git commit</code> z indexu vytvoří objekt. Tento mezikrok umožňuje z rozpracovaného adresáře poskládat commit, který obsahuje jen jednu logickou změnu, i když jste souběžně sáhli na tři různé věci.</p> <h3>Proč na velikosti a zprávě záleží</h3> <p>Malý commit s jedním záměrem se dá snadno revidovat při <a href="/slovnik/code-review">code review</a>, přenést do jiné větve pomocí <code>cherry-pick</code> a vrátit přes <code>revert</code> bez vedlejších škod. Zpráva by měla vysvětlit důvod změny, protože co se změnilo, si stroj dopočítá sám. Konvence typu Conventional Commits (<code>feat:</code>, <code>fix:</code>) navíc umožňují automaticky generovat changelog a odvozovat verzi vydání.</p> <h2>Commit v databázi: okamžik trvanlivosti</h2> <p>V databázovém světě je commit koncem transakce. Příkaz <code>COMMIT</code> říká, že všechny zápisy od <code>BEGIN</code> mají platit společně, nebo vůbec. Právě zde se naplňuje písmeno D ze zkratky <a href="/slovnik/acid">ACID</a>: databáze potvrdí commit až ve chvíli, kdy je záznam o transakci bezpečně na disku, typicky v write-ahead logu. Do té doby vidí změny jen daná session, po commitu i ostatní.</p> <p>S tím souvisí i cena commitu. Každý commit znamená zápis a synchronizaci na trvalé úložiště, takže tisíc řádků vložených v tisíci transakcích je řádově pomalejší než tentýž objem v jedné dávce. Naopak jedna obří transakce drží zámky a rostoucí undo prostor, což blokuje ostatní. Volba velikosti dávky je proto vědomý kompromis.</p> <h2>Distribuovaný případ</h2> <p>Když transakce sahá do více systémů, commit přestává být okamžikem a stává se protokolem. Two-phase commit nejdřív všechny účastníky připraví a vyžádá si od nich příslib, teprve pak rozešle pokyn k potvrzení. Cenou je, že výpadek koordinátora může nechat účastníky viset v nejistém stavu, což je hlavní důvod, proč se v moderních architekturách místo toho volí sagy a idempotentní kroky.</p>

Příklady z praxe

  1. Rozdělení rozpracované práce do dvou commitů

    Vývojář opravoval chybu ve validaci formuláře a přitom si přejmenoval pomocnou funkci v jiném souboru. Místo jednoho smíšeného commitu použije staging area a zapíše opravu i přejmenování zvlášť. Když se oprava později ukáže jako chybná, dá se vrátit samostatně, aniž by se zrušilo přejmenování.

    git add src/validators/form.ts
    git commit -m "fix: povolit telefonni cislo s predvolbou +420"
    
    git add src/utils/helpers.ts
    git commit -m "refactor: prejmenovat fmt na formatPhone"
    
    git log --oneline -2
  2. Dávkový import s commitem po tisíci řádcích

    Skript nahrává milion řádků do PostgreSQL. Commit po každém řádku by znamenal milion synchronních zápisů do WAL, jedna transakce přes celý import by zase dlouho držela zdroje a při chybě zahodila veškerou práci. Kompromisem je commit po dávkách, kde se při selhání ztratí jen poslední rozpracovaná dávka.

    BEGIN;
    INSERT INTO orders (id, customer_id, total) VALUES (...);
    -- dalších 999 řádků dávky
    COMMIT;

Časté omyly

MýtusCommit v Gitu ukládá jen rozdíl proti předchozí verzi.
Ve skutečnostiCommit odkazuje na kompletní strom souborů, tedy na snímek celého obsahu. Rozdíl se dopočítává až při zobrazení a úspora místa vzniká jinde: shodné soubory sdílejí tentýž objekt a Git obsah dodatečně balí do packfiles.
MýtusCommit znamená, že je změna nahraná na server.
Ve skutečnostiCommit zapisuje do lokálního repozitáře. Dokud neproběhne push, žádný jiný vývojář ani CI o commitu neví a při ztrátě notebooku je práce pryč.
MýtusKdyž databáze vrátí úspěch po INSERTu, data jsou uložená natrvalo.
Ve skutečnostiV transakci se data stanou trvalými až po commitu. Řada klientů sice běží v režimu autocommit, kde se commit provede po každém příkazu automaticky, ale uvnitř explicitního BEGIN platí, že rollback nebo pád spojení všechny zápisy zahodí.

Časté dotazy

Jak opravit poslední commit, když jsem zapomněl soubor?
Poslední commit se opravuje příkazem git commit --amend, který k němu přidá obsah indexu a případně upraví zprávu. Amend ale nemění původní objekt: vytvoří nový commit s jiným hashem a starý zůstane osiřelý. Dokud jste commit nikam neposlali, je to bezpečná operace. Pokud už byl publikovaný do sdílené větve, museli byste použít force push a ostatní vývojáři by si museli srovnat historii. Ve sdílených větvích je proto obvykle lepší doplnit opravu novým commitem.
Co dělá git revert oproti git reset?
Git revert vytvoří nový commit, který věcně ruší změny vybraného staršího commitu, takže historie zůstává nedotčená a operace je bezpečná i ve sdílené větvi. Git reset naopak posune ukazatel větve zpět a podle režimu (soft, mixed, hard) zachová nebo zahodí změny v indexu a pracovním adresáři. Reset se hodí na lokální úklid před publikováním, revert na nápravu něčeho, co už ostatní stáhli.
Proč databáze při hromadném importu doporučují méně commitů?
Každý commit v databázi vynutí zápis a synchronizaci transakčního logu na trvalé úložiště, aby přežil pád serveru. Tato synchronizace je řádově dražší než samotné vložení řádku do paměti, takže commit po každém řádku import několikanásobně zpomalí. Sloučení řádků do dávek po stovkách až tisících tuto režii rozpustí. Přehnaně velká transakce má ale opačný problém: dlouho drží zámky, brzdí úklid starých verzí řádků a při chybě se zahodí celá.
Jak má vypadat dobrá commit message?
Dobrá commit message má krátký první řádek v rozkazovacím způsobu, který shrnuje záměr, prázdný řádek a pak volitelný odstavec s vysvětlením, proč změna vznikla a jaké alternativy byly zvažovány. Seznam změněných řádků do zprávy nepatří, ten si nástroj zobrazí sám. Týmy často přidávají prefix podle konvence Conventional Commits, například feat nebo fix, aby se z historie dal automaticky sestavit changelog a odvodit číslo verze.

Zdroje

  1. git-commit Documentation(otevře se v novém okně)Git
  2. Pro Git(otevře se v novém okně)Chacon, Straub / Apress, 2014
  3. PostgreSQL Documentation: COMMIT(otevře se v novém okně)PostgreSQL Global Development Group
  4. PostgreSQL Documentation: Reliability and the Write-Ahead Log(otevře se v novém okně)PostgreSQL Global Development Group
  5. Commit (data management)(otevře se v novém okně)Wikipedia

Související pojmy

Potřebujete to vyřešit v praxi?

Poradíme, jak na to ve vašem projektu

Vysvětlit pojem je jedna věc, navrhnout kolem něj funkční řešení druhá. Ozvěte se a probereme, co dává smysl u vás.