Git --everything-is-local
Chapters ▾

2.3 Základy práce se systémem Git - Zobrazení historie revizí

Zobrazení historie revizí

Až vytvoříte několik revizí nebo pokud naklonujete repozitář s existující historií revizí, možná budete chtít nahlédnout do historie projektu. Nejzákladnějším a nejmocnějším nástrojem je v tomto případě příkaz git log.

Následující příklady ukazují velmi jednoduchý projekt pojmenovaný simplegit, který pro názornost často používám. Chcete-li si projekt naklonovat, zadejte:

git clone git://github.com/schacon/simplegit-progit.git

Po zadání příkazu git log v tomto projektu byste měli dostat výstup, který vypadá zhruba takto:

$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test code

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700

    first commit

Ve výchozím nastavení a bez dalších parametrů vypíše příkaz git log revize provedené v daném repozitáři v obráceném chronologickém pořadí. Nejnovější revize tak budou uvedeny nahoře. Jak vidíte, tento příkaz vypíše všechny revize s jejich kontrolním součtem SHA-1, jménem a e-mailem autora, datem zápisu a zprávou o revizi.

K příkazu git log je k dispozici velké množství nejrůznějších parametrů, díky nimž můžete zobrazit přesně to, co potřebujete. Ukážeme si některé z nejpoužívanějších možností.

Jedním z nejužitečnějších je parametr -p, který zobrazí rozdíly (diff) provedené v každé revizi. Můžete také použít parametr -2, který omezí výpis pouze na dva poslední záznamy:

$ git log -p -2
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

diff --git a/Rakefile b/Rakefile
index a874b73..8f94139 100644
--- a/Rakefile
+++ b/Rakefile
@@ -5,5 +5,5 @@ require 'rake/gempackagetask'
 spec = Gem::Specification.new do |s|
     s.name      =   "simplegit"
-    s.version   =   "0.1.0"
+    s.version   =   "0.1.1"
     s.author    =   "Scott Chacon"
     s.email     =   "schacon@gee-mail.com

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test code

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index a0a60ae..47c6340 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -18,8 +18,3 @@ class SimpleGit
     end

 end
-
-if $0 == __FILE__
-  git = SimpleGit.new
-  puts git.show
-end
\ No newline at end of file

Tento parametr zobrazí tytéž informace, ale za každým záznamem následuje informace o rozdílech. Tato funkce je velmi užitečná při kontrole kódu nebo k rychlému zjištění, co bylo obsahem série revizí, které přidal váš spolupracovník.

Někdy se změny kontrolují snadněji na úrovni slov než na úrovni řádků. Git nabízí parametr --word-diff, který můžeme přidat za příkaz git log -p. Místo obvyklé detekce rozdílů po řádcích získáme rozdíly po slovech. Zjišťování rozdílů po slovech je u zdrojového kódu celkem k ničemu, ale pokud porovnáváme velké textové soubory -- jako například knihy nebo vaši disertační práci --, pak se tato možnost hodí. Tady máme příklad:

$ git log -U1 --word-diff
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

diff --git a/Rakefile b/Rakefile
index a874b73..8f94139 100644
--- a/Rakefile
+++ b/Rakefile
@@ -7,3 +7,3 @@ spec = Gem::Specification.new do |s|
    s.name      =   "simplegit"
    s.version   =   [-"0.1.0"-]{+"0.1.1"+}
    s.author    =   "Scott Chacon"

Jak vidíte, výstup neobsahuje žádné přidané a odstraněné řádky, jak tomu bývá u běžného zobrazení rozdílů (diff). Místo toho se změny zobrazují uvnitř textu. Přidaná slova jsou uzavřena mezi značkami {+ +} a odstraněná jsou uzavřena v [- -]. Možná byste také rádi zredukovali obvyklé třířádkové okolí změny na pouhý jeden řádek, protože chcete znát okolí slova a ne okolí řádku. Můžeme toho dosáhnout zadáním parametru -U1, jako ve výše uvedeném příkladu.

Ve spojení s příkazem git log můžete použít také celou řadu shrnujících parametrů. Pokud například chcete zobrazit některé stručné statistiky pro každou revizi, použijte parametr --stat:

$ git log --stat
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

 Rakefile |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test code

 lib/simplegit.rb |    5 -----
 1 file changed, 5 deletions(-)

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700

    first commit

 README           |    6 ++++++
 Rakefile         |   23 +++++++++++++++++++++++
 lib/simplegit.rb |   25 +++++++++++++++++++++++++
 3 files changed, 54 insertions(+)

Jak vidíte, parametr --stat vypíše pod každým záznamem revize seznam změněných souborů, kolik souborů bylo změněno (changed) a kolik řádků bylo v těchto souborech vloženo (insertions) a smazáno (deletions). Zároveň vloží na konec výpisu shrnutí těchto informací. Další opravdu užitečnou možností je parametr --pretty. Tento parametr změní výstup logu na jiný než výchozí formát. K dispozici máte několik přednastavených možností. Parametr oneline vypíše všechny revize na jednom řádku. Tuto možnost oceníte při velkém množství revizí. Dále se nabízejí parametry short, full a fuller (zkrácený, plný, úplný). Zobrazují výstup přibližně ve stejném formátu, avšak s více či méně podrobnými informacemi:

$ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 changed the version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test code
a11bef06a3f659402fe7563abf99ad00de2209e6 first commit

Nejzajímavějším parametrem je pak format, který umožňuje definovat vlastní formát výstupu logu. Tato možnost je užitečná zejména v situaci, kdy vytváříte výpis pro strojovou analýzu. Jelikož specifikujete formát explicitně, máte jistotu, že se s aktualizací systému Git nezmění:

$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 11 months ago : changed the version number
085bb3b - Scott Chacon, 11 months ago : removed unnecessary test code
a11bef0 - Scott Chacon, 11 months ago : first commit

Tabulka 2-1 uvádí některé užitečné parametry, které format akceptuje.

Parametr Popis výstupu
%H Otisk (hash) revize
%h Zkrácený otisk revize
%T Otisk stromu
%t Zkrácený otisk stromu
%P Otisky rodičovských revizí
%p Zkrácené otisky rodičovských revizí
%an Jméno autora
%ae E-mail autora
%ad Datum autora (formát je možné nastavit parametrem --date)
%ar Datum autora, relativní
%cn Jméno autora revize
%ce E-mail autora revize
%cd Datum autora revize
%cr Datum autora revize, relativní
%s Předmět

Možná se ptáte, jaký je rozdíl mezi autorem a autorem revize. Autor (author) je osoba, která práci původně napsala, zatímco autor revize (committer) je osoba, která práci zapsala do repozitáře. Pokud tedy pošlete záplatu k projektu a některý z ústředních členů (core members) ji použije, do výpisu se dostanete oba – vy jako autor a core member jako autor revize. K tomuto rozlišení se blíže dostaneme v kapitole 5.

Parametry oneline a format jsou zvlášť užitečné ve spojení s další možností logu – parametrem --graph. Tento parametr vloží pěkný malý ASCII graf, znázorňující historii vaší větve a slučování, kterou si ukážeme na naší kopii repozitáře projektu Grit:

$ git log --pretty=format:"%h %s" --graph
* 2d3acf9 ignore errors from SIGCHLD on trap
*  5e3ee11 Merge branch 'master' of git://github.com/dustin/grit
|\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
*  11d191e Merge branch 'defunkt' into local

To je jen několik základních parametrů k formátování výstupu pro příkaz git log, celkově jich je mnohem více. Tabulka 2-2 uvádí parametry, které jsme už zmínili, a některé další běžné parametry formátování, které mohou být užitečné. Pravý sloupec popisuje, jak který parametr změní výstup logu.

Parametr Popis
-p Zobrazí záplatu vytvořenou s každou revizí.
--word-diff Zobrazí záplatu ve tvaru rozdílu po slovech.
--stat Zobrazí statistiku pro změněné soubory v každé revizi.
--shortstat Zobrazí pouze řádek změněno/vloženo/smazáno z příkazu --stat.
--name-only Za informacemi o revizi zobrazí seznam změněných souborů.
--name-status Zobrazí seznam dotčených souborů spolu s informací přidáno/změněno/smazáno.
--abbrev-commit Zobrazí pouze prvních několik znaků kontrolního součtu SHA-1 místo všech 40.
--relative-date Zobrazí datum v relativním formátu (např. "2 weeks ago", tj. před 2 týdny) místo formátu s úplným datem.
--graph Zobrazí vedle výstupu logu ASCII graf k historii větve a slučování.
--pretty Zobrazí revize v alternativním formátu. Parametry příkazu jsou oneline, short, full, fuller a format (ve kterém uvedete svůj vlastní formát).
--oneline Užitečná zkratka pro --pretty=oneline --abbrev-commit.

Omezení výstupu logu

Kromě parametrů k formátování výstupu lze pro git log použít také celou řadu omezujících parametrů, tj. takových, které zobrazí jen definovanou podmnožinu revizí. My už jsme se s jedním takovým parametrem setkali. Byl to parametr -2, který zobrazí pouze dvě poslední revize. Obecně lze tedy říci, že můžete zadat parametr -<n>, kde n je libovolné celé číslo pro zobrazení posledních n revizí. Je však třeba dodat, že tuto funkci asi nebudete využívat příliš často. Git totiž standardně redukuje všechny výpisy stránkovačem, a proto se vždy najednou zobrazí pouze jedna stránka logu.

Velmi užitečné jsou naproti tomu časově omezující parametry, jako --since a --until („od“ a „do“). Například tento příkaz zobrazí seznam všech revizí pořízených za poslední dva týdny (2 weeks):

$ git log --since=2.weeks

Tento příkaz pracuje s velkým množstvím formátů. Můžete zadat konkrétní datum („2008-01-15“) nebo relativní datum, např. „2 years 1 day 3 minutes ago“ (před 2 roky, 1 dnem a 3 minutami).

Z výpisu rovněž můžete filtrovat pouze revize, které odpovídají určitým kritériím. Parametr --author umožňuje filtrovat výpisy podle konkrétního autora, pomocí parametru --grep můžete ve zprávách k revizím vyhledávat klíčová slova. (Všimněte si, že pokud použijete současně parametry author a grep, bude příkaz vyhledávat záznamy splňující obojí.)

Pokud chcete zadat více parametrů grep, musíte přidat výraz --all-match, jinak se bude hledat kterýkoli z nich.

Posledním opravdu užitečným parametrem, který lze přidat k příkazu git log , je zadání cesty. Jestliže zadáte název adresáře nebo souboru, výstup logu tím omezíte na revize, které provedly změnu v těchto souborech. Cesta je vždy posledním parametrem a většinou jí předcházejí dvě pomlčky (--) , jimiž je oddělena od ostatních parametrů.

Tabulka 2-3 uvádí pro přehlednost zmíněné parametry a několik málo dalších. Tabulka 2.2

Parametr Popis
-(n) Zobrazí pouze posledních n revizí.
--since, --after Omezí výpis na revize provedené po zadaném datu.
--until, --before Omezí výpis na revize provedené před zadaným datem.
--author Zobrazí pouze revize, v nichž autor odpovídá zadanému řetězci.
--committer Zobrazí pouze revize, v nichž autor revize odpovídá zadanému řetězci.

Omezení výstupního logu na určité datum nebo čas

Pokud chcete zjistit, které revize (commit) v repozitáři se zdrojovým kódem Git (git://git.kernel.org/pub/scm/git/git.git) mají datum zápisu (CommitDate) 2014-04-29 -- relativně k vašemu lokálnímu časovému pásmu (takovému, jaké je nastaveno na vašem počítači), použijte příkaz

$ git log --after="2014-04-29 00:00:00" --before="2014-04-29 23:59:59" \
  --pretty=fuller

Protože se výstup bude lišit podle časového pásma v místě spuštění, doporučuje se v argumentech --after a --before vždy používat absolutní čas (například ve formátu ISO 8601, který obsahuje i informaci o časovém pásmu). Činíme tak proto, aby každý, kdo stejný příkaz spustí, obdržel stejné, opakovatelné výsledky.

Pokud chceme získat zápisy z určitého časového okamžiku (například z 29. dubna 2013 v 17:07:22 středoevropského času), můžeme použít příkaz

$ git log  --after="2013-04-29T17:07:22+0200"      \
          --before="2013-04-29T17:07:22+0200" --pretty=fuller

commit de7c201a10857e5d424dbd8db880a6f24ba250f9
Author:     Ramkumar Ramachandra <artagnon@gmail.com>
AuthorDate: Mon Apr 29 18:19:37 2013 +0530
Commit:     Junio C Hamano <gitster@pobox.com>
CommitDate: Mon Apr 29 08:07:22 2013 -0700

    git-completion.bash: lexical sorting for diff.statGraphWidth

    df44483a (diff --stat: add config option to limit graph width,
    2012-03-01) added the option diff.startGraphWidth to the list of
    configuration variables in git-completion.bash, but failed to notice
    that the list is sorted alphabetically.  Move it to its rightful place
    in the list.

    Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
    Signed-off-by: Junio C Hamano <gitster@pobox.com>

Výše uvedené časy (AuthorDate, CommitDate) se zobrazují v základním tvaru (--date=default), který zobrazuje informaci o časovém pásmu autora nebo přispěvatele.

K dalším užitečným formátům patří --date=iso (ISO 8601), --date=rfc (RFC 2822), --date=raw (sekundy od počátku (epoch; 1970-01-01 UTC)), --date=local (časy ve vašem lokálním časovém pásmu) a také --date=relative (jako například "2 hours ago", tj. před dvěma hodinami).

Pokud použijete příkaz git log bez určení času, uvažuje se čas odpovídající okamžiku spuštění na vašem počítači (používá stejný posun vůči UTC).

Pokud například na vašem počítači spustíte git log v 09:00 a vaše časové pásmo je vůči greenwichskému času posunuto o tři hodiny vpřed, pak se výsledek následujících dvou příkazů shoduje:

$ git log --after=2008-06-01 --before=2008-07-01
$ git log --after="2008-06-01T09:00:00+0300" \
    --before="2008-07-01T09:00:00+0300"

A poslední příklad. Pokud chcete zjistit, které revize upravující testovací soubory ve zdrojovém kódu Git zapsal Junio Hamano v říjnu 2008 (relativě k časové zóně New Yorku) a které přitom nebyly sloučením (merge), můžete zadat následující příkaz:

    $ git log --pretty="%h - %s" --author=gitster \
       --after="2008-10-01T00:00:00-0400"         \
      --before="2008-10-31T23:59:59-0400" --no-merges -- t/
5610e3b - Fix testcase failure when extended attribute
acd3b9e - Enhance hold_lock_file_for_{update,append}()
f563754 - demonstrate breakage of detached checkout wi
d1a43f2 - reset --hard/read-tree --reset -u: remove un
51a94af - Fix "checkout --track -b newbranch" on detac
b0ad11e - pull: allow "git pull origin $something:$cur

Z více než 36 tisíc revizí v historii zdrojového kódu Git zobrazí tento příkaz 6 záznamů, které odpovídají zadaným kritériím.

Grafické uživatelské rozhraní pro procházení historie

Chcete-li použít graficky výrazněji zpracovaný nástroj k procházení historie revizí, možná oceníte Tcl/Tk program nazvaný gitk, který je distribuován spolu se systémem Git. Gitk je v zásadě grafická verze příkazu git log a umožňuje téměř všechny možnosti filtrování jako git log. Pokud do příkazového řádku ve svém projektu zadáte příkaz gitk, otevře se okno podobné jako na obrázku 2-2.


Obrázek 2-2. Graficky zpracovaná historie v nástroji „gitk“

V horní polovině okna vidíte historii revizí, doplněnou názorným hierarchickým grafem. Prohlížeč rozdílů v dolní polovině okna zobrazuje změny provedené v každé revizi, na niž kliknete.