Obsah
1. Programovací jazyk Clojure a práce s Gitem (3)
2. Použití funkce clj-jgit.porcelain/git-blame
3. Zdrojový kód demonstračního příkladu git-test12
5. Zdrojový kód demonstračního příkladu git-test13
7. Zdrojový kód demonstračního příkladu git-test14
8. Vytvoření naformátovaného patche s využitím funkce clj-jgit.querying/changed-files-with-patch
9. Zdrojový kód demonstračního příkladu git-test15
10. Repositář s dnešními demonstračními příklady
11. Odkazy na předchozí části tohoto seriálu
1. Programovací jazyk Clojure a práce s Gitem (3)
V dnešním článku o programovacím jazyce Clojure i o vybraných užitečných knihovnách, které jsou pro tento jazyk vytvořeny, se opět (již potřetí) budeme zabývat způsobem využití knihovny nazvané clj-jgit. Navážeme tak na sedmnáctou a osmnáctou část tohoto seriálu, v nichž jsme si nejprve řekli základní informace o knihovně clj-jgit a následně jsme si na celkem jedenácti demonstračních příkladech ukázali, jakým způsobem je možné získat obsah vzdáleného repositáře, jak se přečtou informace o lokálních i vzdálených větvích a taktéž jsme si předvedli způsoby přepínání mezi větvemi, přidávání a změnu souborů v repositáři, commit provedených změn a zjištění stavu repositáře v jakémkoli okamžiku (těsně po naklonování, po přepnutí větve, po přidání nového souboru do repositáře, změně souboru, commitu provedených změn apod.).
Prozatím jsme se však neseznámili se způsobem přečtení informací o všech provedených commitech ani o postupu, kterým je možné získat patch (změnový soubor) obsahující informace o tom, jaké změny byly ve vybraném commitu vlastně provedeny. S funkcemi a makry knihovny clj-jgit, které tyto operace implementují, se seznámíme v dnešním článku a především si ukážeme způsob jejich použití na čtveřici demonstračních příkladů. Popsány budou následující funkce a makra:
| # | Funkce/makro | Stručný popis |
|---|---|---|
| 1 | clj-jgit.porcelain/git-blame | obdoba příkazu git blame |
| 2 | clj-jgit.porcelain/rev-list | vrací seznam všech provedených změn v repositáři |
| 3 | clj-jgit.querying/commit-info | získání podrobnějších informací o zvoleném commitu |
| 4 | clj-jgit.querying/branches-for | informace o větvích, kterých se commit týká |
| 5 | clj-jgit.querying/changed-files | informace o změněných souborech ve zvoleném commitu |
| 6 | clj-jgit.querying/changed-files-with-patch | naformátování patche pro zvolený commit |
2. Použití funkce clj-jgit.porcelain/git-blame
První funkcí, s níž se dnes seznámíme, je funkce nazvaná clj-jgit.porcelain/git-blame, kterou je možné použít pro zjištění informací o autorech změn provedených v libovolném souboru, který je součástí repositáře. Této funkci se předávají dva argumenty – reference na repositář, tj. hodnota vrácená například funkcí clj-jgit.porcelain/with-repo a jméno souboru, o jehož změnách potřebujeme získat potřebné informace. Funkce clj-jgit.porcelain/git-blame vrací seznam změn, přičemž informace o každé změně je reprezentována následující datovou strukturou složenou z vnořených hashmap:
{
:author {
:name
:email
:timezone
}
:commit
:committer {
:name
:email
:timezone
}
:line
:source-path
}
Pro zajímavost – zdrojový kód funkce clj-jgit.porcelain/git-blame vypadá následovně:
(defn git-blame
([^Git repo ^String path]
(git-blame repo path false))
([^Git repo ^String path ^Boolean follow-renames?]
(-> repo
.blame
(.setFilePath path)
(.setFollowFileRenames follow-renames?)
.call
blame-result))
([^Git repo ^String path ^Boolean follow-renames? ^AnyObjectId start-commit]
(-> repo
.blame
(.setFilePath path)
(.setFollowFileRenames follow-renames?)
(.setStartCommit start-commit)
.call
blame-result)))
Poznámka: pravděpodobně kvůli chybě v knihovně JGit, konkrétně ve funkci getSourceCommit(), dochází k výjimce typu ArrayIndexOutOfBoundsException při snaze o přečtení posledního záznamu v sekvenci.
3. Zdrojový kód demonstračního příkladu git-test12
V dnešním prvním demonstračním příkladu nazvaném git-test12 je ukázáno využití výše popsané funkce clj-jgit.porcelain/git-blame pro získání informací o změně provedené v souboru README.md umístěného v testovacím repositáři https://github.com/tisnik/testrepo. Vypíše se pouze první změna ze získané sekvence; při snaze o čtení dalších změn nezapomeňte celou smyčku uzavřít do makra try kvůli zpracování výše zmíněné výjimky typu ArrayIndexOutOfBoundsException.
Vytvoření kostry demonstračního příkladu:
lein new app git-12
Úprava projektového souboru project.clj:
(defproject git-test12 "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.6.0"]
[clj-jgit "0.8.0"]
[clj-rm-rf "1.0.0-SNAPSHOT"]]
:main ^:skip-aot git-test12.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
Zdrojový kód souboru src/git_test12/core.clj:
(ns git-test12.core
(:gen-class))
(require '[clojure.pprint :as pprint])
(require '[clj-jgit.porcelain :as jgit])
(require '[clj-jgit.querying :as jgit-query])
(require '[hozumi.rm-rf :as rm-rf])
(def repository-url
"Adresa GIT repositare vcetne specifikace protokolu."
"https://github.com/tisnik/testrepo.git")
(def directory-name
"Jmeno adresare, do ktereho se GIT repositar naklonuje."
"repo")
(defn clone-repository
"Naklonovani GIT repositare do specifikovaneho adresare."
[url directory]
(jgit/git-clone url directory))
(defn delete-directory
"Smazani adresare vcetne podadresaru a souboru."
[directory]
(rm-rf/rm-r (java.io.File. directory)))
(defn print-customized-log
"Vypis logovacich informaci ve zvolenem formatu."
[repository]
(println "\nLog:")
(doseq [log-entry (jgit/git-log repository)]
(let [info (jgit-query/commit-info repository log-entry)]
(println (:author info) ":" (:message info)))))
(defn print-local-branches
"Vypis vsech lokalnich vetvi pro vybrany repositar."
[repo]
(println "\nLocal branches")
(doseq [branch (jgit/git-branch-list repo)]
(println (.getName branch))))
(defn print-remote-branches
"Vypis vsech vzdalenych vetvi pro vybrany repositar."
[repo]
(println "\nRemote branches")
(doseq [branch (jgit/git-branch-list repo :remote)]
(println (.getName branch))))
(defn print-git-blame
"Ukazka pouziti funkce git-blame."
[repo filename]
(println "\nGit blame " filename)
(let [blamelist (jgit/git-blame repo filename)
first-blame (first blamelist)]
; ukazka pristupu ke vnorenemu prvku vracene struktury
(println "Committer:" (:name (:committer first-blame)))
; vypis cele struktury
(pprint/pprint first-blame)
))
(defn git-test-12
"Naklonovani repositare, nacteni informaci
z vytvoreneho adresare a vypis podrobnejsiho logu."
[repository-url directory-name]
; naklonovani repositare do specifikovaneho adresare
(clone-repository repository-url directory-name)
; nacteni informaci o repositari z lokalniho adresare
; povsimnete si pouziti "automagicky" vytvorene promenne,
; ktera se jmenuje 'repo'
(try (jgit/with-repo directory-name
(print-customized-log repo)
(print-local-branches repo)
(print-remote-branches repo)
(print-git-blame repo "README.md"))
(finally
; vymazani adresare s naklonovanym repositarem
(delete-directory directory-name))))
(defn -main
"Funkce zavolana po zadani prikazu 'lein run'."
[& args]
(git-test-12 repository-url directory-name))
Ukázka výstupu demonstračního příkladu po jeho spuštění (repositář ve stavu se třemi větvemi):
Log:
Pavel Tisnovsky : Added garbage
Pavel Tisnovsky : Updated README.md
Pavel Tišnovský : Initial commit
Local branches
refs/heads/master
Remote branches
refs/remotes/origin/branch-1
refs/remotes/origin/branch-2
refs/remotes/origin/master
Git blame README.md
Committer: Pavel Tišnovský
{:author
{:name "Pavel Tišnovský",
:email "ptisnovs@redhat.com",
:timezone
#<ZoneInfo sun.util.calendar.ZoneInfo[id="GMT-04:00",offset=-14400000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]>},
:commit
#<RevCommit commit badf2b12f9281a8581009bfa068a5147c4cbc87a 1434722046 -----p>,
:committer
{:name "Pavel Tišnovský",
:email "ptisnovs@redhat.com",
:timezone
#<ZoneInfo sun.util.calendar.ZoneInfo[id="GMT-04:00",offset=-14400000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]>},
:line 0,
:source-path "README.md"}
Ukázka výstupu demonstračního příkladu po jeho spuštění (repositář ve stavu se čtyřmi větvemi, spojením větví a merge konfliktem):
Log:
Pavel Tisnovsky : Updated README.md
Pavel Tisnovsky : Added file-in-branch-3 into branch-3
Pavel Tisnovsky : Added garbage
Pavel Tisnovsky : Updated README.md
Pavel Tišnovský : Initial commit
Local branches
refs/heads/master
Remote branches
refs/remotes/origin/branch-1
refs/remotes/origin/branch-2
refs/remotes/origin/branch-3
refs/remotes/origin/master
Git blame README.md
Committer: Pavel Tišnovský
{:author
{:name "Pavel Tišnovský",
:email "ptisnovs@redhat.com",
:timezone
#<ZoneInfo sun.util.calendar.ZoneInfo[id="GMT-04:00",offset=-14400000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]>},
:commit
#<RevCommit commit badf2b12f9281a8581009bfa068a5147c4cbc87a 1434722046 -----p>,
:committer
{:name "Pavel Tišnovský",
:email "ptisnovs@redhat.com",
:timezone
#<ZoneInfo sun.util.calendar.ZoneInfo[id="GMT-04:00",offset=-14400000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]>},
:line 0,
:source-path "README.md"}
4. Použití funkcí clj-jgit.porcelain/rev-list a clj-jgit.querying/commit-info pro získání informací o commitech
Další informací, kterou je možné při práci s GITovskými repositáři relativně jednoduše přečíst, jsou informace o jednotlivých commitech, tj. o změnách provedených v průběhu historie existence aktivně používaného repositáře. V této kapitole si popíšeme dvojici funkcí, které lze využít pro přečtení podobných informací, jaké se z příkazového řádku získají příkazem git log (ve skutečnosti dále popsané funkce vrátí ještě více informací). První užitečnou funkcí je clj-jgit.porcelain/rev-list, jejíž zdrojový kód vypadá následovně:
(defn rev-list
([^Git repo]
(rev-list repo (new-rev-walk repo)))
([^Git repo ^RevWalk rev-walk]
(.reset rev-walk)
(mark-all-heads-as-start-for! repo rev-walk)
(doto (RevCommitList.)
(.source rev-walk)
(.fillTo Integer/MAX_VALUE))))
V nejjednodušším případě se do této funkce předá pouze jediný parametr: reference na repositář. Následně se vrátí seznam změn provedených v repositáři, ovšem my musíme mít možnost informace o jednotlivých změnách smysluplně zpracovat. Právě pro tento účel se používá druhá funkce nazvaná clj-jgit.querying/commit-info, která pro předaný objekt typu RevCommit (ten si můžeme představit jako otisk commitu, tj. jeho hešovací kód, ten je mimochodem uložený pod klíčem :id) vrátí mapu se strukturovanými informacemi. Zdrojový kód funkce clj-jgit.querying/commit-info je poněkud komplikovanější, neboť se podporuje různý typ (a počet) parametrů použitý při jejím volání:
(defn commit-info
([^Git repo, ^RevCommit rev-commit]
(commit-info repo (new-rev-walk repo) rev-commit))
([^Git repo, ^RevWalk rev-walk, ^RevCommit rev-commit]
(merge (commit-info-without-branches repo rev-walk rev-commit)
{:branches (branches-for repo rev-commit)}))
([^Git repo ^RevWalk rev-walk ^HashMap commit-map ^RevCommit rev-commit]
(merge (commit-info-without-branches repo rev-walk rev-commit)
{:branches (map #(.getName ^Ref %) (or (.get commit-map rev-commit) []))})))
Z vrácené mapy lze získat důležité hodnoty uložené pod těmito klíči:
| 1 | :id |
| 2 | :author |
| 3 | :message |
| 4 | :changed_files |
5. Zdrojový kód demonstračního příkladu git-test13
Výše popsané funkce clj-jgit.porcelain/rev-list a clj-jgit.querying/commit-info jsou použity v dnešním druhém demonstračním příkladu, kde se s jejich využitím získají informace o historii změn provedených v testovacím repositáři https://github.com/tisnik/testrepo.git.
Vytvoření kostry demonstračního příkladu:
lein new app git-13
Úprava projektového souboru project.clj:
(defproject git-test13 "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.6.0"]
[clj-jgit "0.8.0"]
[clj-rm-rf "1.0.0-SNAPSHOT"]]
:main ^:skip-aot git-test13.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
Zdrojový kód souboru src/git_test13/core.clj:
(ns git-test13.core
(:gen-class))
(require '[clojure.pprint :as pprint])
(require '[clj-jgit.porcelain :as jgit])
(require '[clj-jgit.querying :as jgit-query])
(require '[hozumi.rm-rf :as rm-rf])
(def repository-url
"Adresa GIT repositare vcetne specifikace protokolu."
"https://github.com/tisnik/testrepo.git")
(def directory-name
"Jmeno adresare, do ktereho se GIT repositar naklonuje."
"repo")
(defn clone-repository
"Naklonovani GIT repositare do specifikovaneho adresare."
[url directory]
(jgit/git-clone url directory))
(defn delete-directory
"Smazani adresare vcetne podadresaru a souboru."
[directory]
(rm-rf/rm-r (java.io.File. directory)))
(defn rev-list
[repo]
(println "\nList of all revision objects\n")
(let [rev-list (jgit-query/rev-list repo)]
(doseq [rev rev-list]
(let [info (jgit-query/commit-info repo rev)]
(println "commit" (:id info))
(println "Author: " (:author info))
(println "Files: " (:changed_files info))
(println "\n" (:message info) "\n\n")))))
(defn git-test-13
"Naklonovani repositare, nacteni informaci
z vytvoreneho adresare a vypis podrobnejsiho logu."
[repository-url directory-name]
; naklonovani repositare do specifikovaneho adresare
(clone-repository repository-url directory-name)
; nacteni informaci o repositari z lokalniho adresare
; povsimnete si pouziti "automagicky" vytvorene promenne,
; ktera se jmenuje 'repo'
(try (jgit/with-repo directory-name
(rev-list repo))
(finally
; vymazani adresare s naklonovanym repositarem
(delete-directory directory-name))))
(defn -main
"Funkce zavolana po zadani prikazu 'lein run'."
[& args]
(git-test-13 repository-url directory-name))
Ukázka výstupu demonstračního příkladu po jeho spuštění (repositář ve stavu se třemi větvemi):
List of all revision objects commit 07f9a94593ec3e065a7eeaedbbc5220ffe5c5722 Author: Pavel Tisnovsky Files: ([file-in-branch-2 :add]) Added file-in-branch-2 commit f84564ce7fa81f865e60d3d2e18f5789539a237a Author: Pavel Tisnovsky Files: ([file-in-branch-1 :add]) Added file-in-branch-1 commit 394ce42cb3bcf44ff4e9a94949814bacddcdfe9b Author: Pavel Tisnovsky Files: ([garbage :add]) Added garbage commit 0fd398ab16e53ea0b783aef2413d75b75c6462cd Author: Pavel Tisnovsky Files: ([README.md :edit]) Updated README.md commit badf2b12f9281a8581009bfa068a5147c4cbc87a Author: Pavel Tisnovsky Files: [[README.md :add]] Initial commit
Ukázka výstupu demonstračního příkladu po jeho spuštění (repositář ve stavu se čtyřmi větvemi, spojením větví a merge konfliktem):
List of all revision objects
commit ebffda7b2832c220e591d077ba448a0983fb1a47
Author: Pavel Tisnovsky
Files: ([README.md :edit])
Merge branch 'master' into branch-3
Conflicts:
README.md
commit 19be06f06b8c5cb4a0dee5969d9a30c17f2cbc7d
Author: Pavel Tisnovsky
Files: ([README.md :edit])
Change in README.md
commit 4be57bb203050da628b66a045610bb6e0e7b243f
Author: Pavel Tisnovsky
Files: ([README.md :edit])
Updated README.md
commit 038bdf4191194b78fc683e40493c1ecace4f1e40
Author: Pavel Tisnovsky
Files: ([file-in-branch-3 :add])
Added file-in-branch-3 into branch-3
commit 07f9a94593ec3e065a7eeaedbbc5220ffe5c5722
Author: Pavel Tisnovsky
Files: ([file-in-branch-2 :add])
Added file-in-branch-2
commit f84564ce7fa81f865e60d3d2e18f5789539a237a
Author: Pavel Tisnovsky
Files: ([file-in-branch-1 :add])
Added file-in-branch-1
commit 394ce42cb3bcf44ff4e9a94949814bacddcdfe9b
Author: Pavel Tisnovsky
Files: ([garbage :add])
Added garbage
commit 0fd398ab16e53ea0b783aef2413d75b75c6462cd
Author: Pavel Tisnovsky
Files: ([README.md :edit])
Updated README.md
commit badf2b12f9281a8581009bfa068a5147c4cbc87a
Author: Pavel Tisnovsky
Files: [[README.md :add]]
Initial commit
6. Podrobnější informace o změnách získané s využitím funkcí clj-jgit.querying/branches-for a clj-jgit.querying/changed-files
Knihovna clj-jgit nabízí svým uživatelům i několik dalších funkcí, které je možné využít pro získání podrobnějších informací o jednotlivých commitech. Některé z dále zmíněných funkcí se používají interně (tj. dalšími funkcemi z knihovny clj-jgit), ovšem díky tomu, že se nepoužívá žádný režim „skrývání“ těchto funkcí před programátory, lze je přímo volat i z vyvíjených aplikací. Jedná se především o následující funkce:
| # | Funkce | Stručný popis |
|---|---|---|
| 1 | branches-for | větev či větve, kterých se commit týká |
| 2 | changed-files | soubory změněné v rámci jednoho commitu |
| 3 | changed-files-between-commits | soubory změněné mezi libovolnými dvěma commity |
| 4 | changed-files-with-patch | změny provedené v rámci commitu naformátované jako patch |
Funkce clj-jgit.querying/branches-for vrací sekvenci větví, kterých se daný commit týká:
(defn branches-for
[^Git repo ^ObjectId rev-commit]
(let [rev-walk (new-rev-walk repo)
bound-commit (bound-commit repo rev-walk rev-commit)
branch-list (branch-list-with-heads repo rev-walk)]
(->>
(for [[^ObjectIdRef branch-ref ^RevCommit branch-tip-commit] branch-list
:when branch-tip-commit]
(do
(when (commit-in-branch? repo rev-walk branch-tip-commit bound-commit)
(.getName branch-ref))))
(remove nil?)
doall)))
Význam funkce clj-jgit.querying/changed-files je jednoduchý – lze ji použít pro přečtení změněných, smazaných či naopak vytvořených souborů pro jeden commit:
(defn changed-files
[^Git repo ^RevCommit rev-commit]
(if-let [parent (first (.getParents rev-commit))]
(changed-files-between-commits repo parent rev-commit)
(changed-files-in-first-commit repo rev-commit)))
V některých případech je užitečné zjistit změny mezi libovolnými dvěma commity (ty spolu nemusí nijak souviset). Tehdy přichází na řadu funkce clj-jgit.querying/changed-files-between-commits, které se předá reference na repositář a reference na dva commity:
(defn changed-files-between-commits
[^Git repo ^RevCommit old-rev-commit ^RevCommit new-rev-commit]
(let [df ^DiffFormatter (diff-formatter-for-changes repo)
entries (.scan df old-rev-commit new-rev-commit)]
(map parse-diff-entry entries)))
Funkce vrátí kumulativní změny.
7. Zdrojový kód demonstračního příkladu git-test14
Dvojici výše zmíněných funkcí clj-jgit.querying/branches-for a clj-jgit.querying/changed-files použijeme v dnešním předposledním demonstračním příkladu nazvaném git-test14. Tento příklad je vlastně pouhým (velmi jednoduchým) rozšířením příkladu předchozího, což je ostatně patrné i při pohledu na jeho zdrojový kód, protože byly přidány pouze tyto dva nové řádky:
(println "Branches: " (jgit-query/branches-for repo (:raw info))) (println "Changed files: " (jgit-query/changed-files repo (:raw info)))
Vytvoření kostry demonstračního příkladu:
lein new app git-14
Úprava projektového souboru project.clj:
(defproject git-test14 "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.6.0"]
[clj-jgit "0.8.0"]
[clj-rm-rf "1.0.0-SNAPSHOT"]]
:main ^:skip-aot git-test14.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
Zdrojový kód souboru src/git_test14/core.clj:
(ns git-test14.core
(:gen-class))
(require '[clojure.pprint :as pprint])
(require '[clj-jgit.porcelain :as jgit])
(require '[clj-jgit.querying :as jgit-query])
(require '[hozumi.rm-rf :as rm-rf])
(def repository-url
"Adresa GIT repositare vcetne specifikace protokolu."
"https://github.com/tisnik/testrepo.git")
(def directory-name
"Jmeno adresare, do ktereho se GIT repositar naklonuje."
"repo")
(defn clone-repository
"Naklonovani GIT repositare do specifikovaneho adresare."
[url directory]
(jgit/git-clone url directory))
(defn delete-directory
"Smazani adresare vcetne podadresaru a souboru."
[directory]
(rm-rf/rm-r (java.io.File. directory)))
(defn rev-list
[repo]
(println "\nList of all revision objects\n")
(let [rev-list (jgit-query/rev-list repo)]
(doseq [rev rev-list]
(let [info (jgit-query/commit-info repo rev)]
(println "commit" (:id info))
(println "Author: " (:author info))
(println "Files: " (:changed_files info))
(println "\n" (:message info) "\n")
(println "Branches: " (jgit-query/branches-for repo (:raw info)))
(println "Changed files: " (jgit-query/changed-files repo (:raw info)))
(println)
))))
(defn git-test-14
"Naklonovani repositare, nacteni informaci
z vytvoreneho adresare a vypis podrobnejsiho logu."
[repository-url directory-name]
; naklonovani repositare do specifikovaneho adresare
(clone-repository repository-url directory-name)
; nacteni informaci o repositari z lokalniho adresare
; povsimnete si pouziti "automagicky" vytvorene promenne,
; ktera se jmenuje 'repo'
(try (jgit/with-repo directory-name
(rev-list repo))
(finally
; vymazani adresare s naklonovanym repositarem
(delete-directory directory-name))))
(defn -main
"Funkce zavolana po zadani prikazu 'lein run'."
[& args]
(git-test-14 repository-url directory-name))
Ukázka výstupu demonstračního příkladu po jeho spuštění (repositář ve stavu se třemi větvemi):
List of all revision objects commit 07f9a94593ec3e065a7eeaedbbc5220ffe5c5722 Author: Pavel Tisnovsky Files: ([file-in-branch-2 :add]) Added file-in-branch-2 Branches: () Changed files: ([file-in-branch-2 :add]) commit f84564ce7fa81f865e60d3d2e18f5789539a237a Author: Pavel Tisnovsky Files: ([file-in-branch-1 :add]) Added file-in-branch-1 Branches: () Changed files: ([file-in-branch-1 :add]) commit 394ce42cb3bcf44ff4e9a94949814bacddcdfe9b Author: Pavel Tisnovsky Files: ([garbage :add]) Added garbage Branches: (refs/heads/master) Changed files: ([garbage :add]) commit 0fd398ab16e53ea0b783aef2413d75b75c6462cd Author: Pavel Tisnovsky Files: ([README.md :edit]) Updated README.md Branches: (refs/heads/master) Changed files: ([README.md :edit]) commit badf2b12f9281a8581009bfa068a5147c4cbc87a Author: Pavel Tisnovsky Files: [[README.md :add]] Initial commit Branches: (refs/heads/master) Changed files: [[README.md :add]]
Ukázka výstupu demonstračního příkladu po jeho spuštění (repositář ve stavu se čtyřmi větvemi, spojením větví a merge konfliktem):
List of all revision objects
commit ebffda7b2832c220e591d077ba448a0983fb1a47
Author: Pavel Tisnovsky
Files: ([README.md :edit])
Merge branch 'master' into branch-3
Conflicts:
README.md
Branches: ()
Changed files: ([README.md :edit])
commit 19be06f06b8c5cb4a0dee5969d9a30c17f2cbc7d
Author: Pavel Tisnovsky
Files: ([README.md :edit])
Change in README.md
Branches: ()
Changed files: ([README.md :edit])
commit 4be57bb203050da628b66a045610bb6e0e7b243f
Author: Pavel Tisnovsky
Files: ([README.md :edit])
Updated README.md
Branches: (refs/heads/master)
Changed files: ([README.md :edit])
commit 038bdf4191194b78fc683e40493c1ecace4f1e40
Author: Pavel Tisnovsky
Files: ([file-in-branch-3 :add])
Added file-in-branch-3 into branch-3
Branches: (refs/heads/master)
Changed files: ([file-in-branch-3 :add])
commit 07f9a94593ec3e065a7eeaedbbc5220ffe5c5722
Author: Pavel Tisnovsky
Files: ([file-in-branch-2 :add])
Added file-in-branch-2
Branches: ()
Changed files: ([file-in-branch-2 :add])
commit f84564ce7fa81f865e60d3d2e18f5789539a237a
Author: Pavel Tisnovsky
Files: ([file-in-branch-1 :add])
Added file-in-branch-1
Branches: ()
Changed files: ([file-in-branch-1 :add])
commit 394ce42cb3bcf44ff4e9a94949814bacddcdfe9b
Author: Pavel Tisnovsky
Files: ([garbage :add])
Added garbage
Branches: (refs/heads/master)
Changed files: ([garbage :add])
commit 0fd398ab16e53ea0b783aef2413d75b75c6462cd
Author: Pavel Tisnovsky
Files: ([README.md :edit])
Updated README.md
Branches: (refs/heads/master)
Changed files: ([README.md :edit])
commit badf2b12f9281a8581009bfa068a5147c4cbc87a
Author: Pavel Tisnovsky
Files: [[README.md :add]]
Initial commit
Branches: (refs/heads/master)
Changed files: [[README.md :add]]
8. Vytvoření naformátovaného patche s využitím funkce clj-jgit.querying/changed-files-with-patch
Poslední funkcí z knihovny clj-jgit, kterou si dnes popíšeme, je funkce nazvaná clj-jgit.querying/changed-files-with-patch. Této funkci je nutné předat dva parametry: referenci na repositář a referenci na commit. Hodnotou, kterou tato funkce vrátí, je textová (řetězcová) podoba patche (změnového souboru), kterou je možné například s využitím standardní clojurovské funkce spit (http://clojuredocs.org/clojure.core/spit) uložit do externího textového souboru pro další použití, například pro pozdější aplikaci s využitím příkazů patch či git apply. Důležité je, že funkce clj-jgit.querying/changed-files-with-patch vrací skutečně pouze změny provedené v rámci specifikovaného commitu a nikoli rozdíl mezi libovolnými dvěma commity (i když i to by bylo užitečné).
Opět se pro zajímavost podívejme na zdrojový kód funkce clj-jgit.querying/changed-files-with-patch:
(defn changed-files-with-patch
[^Git repo ^RevCommit rev-commit]
(if-let [parent (first (.getParents rev-commit))]
(let [rev-parent ^RevCommit parent
out ^ByteArrayOutputStream (new ByteArrayOutputStream)
df ^DiffFormatter (byte-array-diff-formatter-for-changes repo out)]
(.format df rev-parent rev-commit)
(.toString out))))
9. Zdrojový kód demonstračního příkladu git-test15
V dnešním posledním demonstračním příkladu nazvaném git-test15 je ukázáno použití funkce clj-jgit.querying/changed-files-with-patch v praxi. Vlastně se jedná o rozšíření předchozího příkladu s tím, že se kromě informací o jednotlivých commitech na standardní výstup vypíše i příslušný patch (který by samozřejmě bylo možné funkcí spit uložit do textového souboru).
Vytvoření kostry demonstračního příkladu:
lein new app git-15
Úprava projektového souboru project.clj:
(defproject git-test15 "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.6.0"]
[clj-jgit "0.8.0"]
[clj-rm-rf "1.0.0-SNAPSHOT"]]
:main ^:skip-aot git-test15.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
Zdrojový kód souboru src/git_test15/core.clj:
(ns git-test15.core
(:gen-class))
(require '[clojure.pprint :as pprint])
(require '[clj-jgit.porcelain :as jgit])
(require '[clj-jgit.querying :as jgit-query])
(require '[hozumi.rm-rf :as rm-rf])
(def repository-url
"Adresa GIT repositare vcetne specifikace protokolu."
"https://github.com/tisnik/testrepo.git")
(def directory-name
"Jmeno adresare, do ktereho se GIT repositar naklonuje."
"repo")
(defn clone-repository
"Naklonovani GIT repositare do specifikovaneho adresare."
[url directory]
(jgit/git-clone url directory))
(defn delete-directory
"Smazani adresare vcetne podadresaru a souboru."
[directory]
(rm-rf/rm-r (java.io.File. directory)))
(defn rev-list
[repo]
(println "\nList of all revision objects\n")
(let [rev-list (jgit-query/rev-list repo)]
(doseq [rev rev-list]
(let [info (jgit-query/commit-info repo rev)]
(println "commit" (:id info))
(println "Author: " (:author info))
(println "Files: " (:changed_files info))
(println "\n" (:message info) "\n")
(println "Branches: " (jgit-query/branches-for repo (:raw info)))
(println "Changed files: " (jgit-query/changed-files repo (:raw info)))
(println)
(println (jgit-query/changed-files-with-patch repo (:raw info)))
(println)
))))
(defn git-test-15
"Naklonovani repositare, nacteni informaci
z vytvoreneho adresare a vypis podrobnejsiho logu."
[repository-url directory-name]
; naklonovani repositare do specifikovaneho adresare
(clone-repository repository-url directory-name)
; nacteni informaci o repositari z lokalniho adresare
; povsimnete si pouziti "automagicky" vytvorene promenne,
; ktera se jmenuje 'repo'
(try (jgit/with-repo directory-name
(rev-list repo))
(finally
; vymazani adresare s naklonovanym repositarem
(delete-directory directory-name))))
(defn -main
"Funkce zavolana po zadani prikazu 'lein run'."
[& args]
(git-test-15 repository-url directory-name))
Ukázka výstupu demonstračního příkladu po jeho spuštění (repositář ve stavu se třemi větvemi):
List of all revision objects commit 07f9a94593ec3e065a7eeaedbbc5220ffe5c5722 Author: Pavel Tisnovsky Files: ([file-in-branch-2 :add]) Added file-in-branch-2 Branches: () Changed files: ([file-in-branch-2 :add]) diff --git a/file-in-branch-2 b/file-in-branch-2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/file-in-branch-2 commit f84564ce7fa81f865e60d3d2e18f5789539a237a Author: Pavel Tisnovsky Files: ([file-in-branch-1 :add]) Added file-in-branch-1 Branches: () Changed files: ([file-in-branch-1 :add]) diff --git a/file-in-branch-1 b/file-in-branch-1 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/file-in-branch-1 commit 394ce42cb3bcf44ff4e9a94949814bacddcdfe9b Author: Pavel Tisnovsky Files: ([garbage :add]) Added garbage Branches: (refs/heads/master) Changed files: ([garbage :add]) diff --git a/garbage b/garbage new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/garbage commit 0fd398ab16e53ea0b783aef2413d75b75c6462cd Author: Pavel Tisnovsky Files: ([README.md :edit]) Updated README.md Branches: (refs/heads/master) Changed files: ([README.md :edit]) diff --git a/README.md b/README.md index 6edd528..04aafb8 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # testrepo testrepo +hello! commit badf2b12f9281a8581009bfa068a5147c4cbc87a Author: Pavel Tisnovsky Files: [[README.md :add]] Initial commit Branches: (refs/heads/master) Changed files: [[README.md :add]] nil
Ukázka výstupu demonstračního příkladu po jeho spuštění (repositář ve stavu se čtyřmi větvemi, spojením větví a merge konfliktem):
List of all revision objects
commit ebffda7b2832c220e591d077ba448a0983fb1a47
Author: Pavel Tisnovsky
Files: ([README.md :edit])
Merge branch 'master' into branch-3
Conflicts:
README.md
Branches: ()
Changed files: ([README.md :edit])
diff --git a/README.md b/README.md
index a999387..50943b6 100644
--- a/README.md
+++ b/README.md
@@ -2,5 +2,9 @@
testrepo
hello!
+<<<<<<< HEAD
change incompatible with master
+=======
+update
+>>>>>>> master
commit 19be06f06b8c5cb4a0dee5969d9a30c17f2cbc7d
Author: Pavel Tisnovsky
Files: ([README.md :edit])
Change in README.md
Branches: ()
Changed files: ([README.md :edit])
diff --git a/README.md b/README.md
index 04aafb8..a999387 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
# testrepo
testrepo
hello!
+
+change incompatible with master
+
commit 4be57bb203050da628b66a045610bb6e0e7b243f
Author: Pavel Tisnovsky
Files: ([README.md :edit])
Updated README.md
Branches: (refs/heads/master)
Changed files: ([README.md :edit])
diff --git a/README.md b/README.md
index 04aafb8..a2e71dd 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
# testrepo
testrepo
hello!
+
+update
commit 038bdf4191194b78fc683e40493c1ecace4f1e40
Author: Pavel Tisnovsky
Files: ([file-in-branch-3 :add])
Added file-in-branch-3 into branch-3
Branches: (refs/heads/master)
Changed files: ([file-in-branch-3 :add])
diff --git a/file-in-branch-3 b/file-in-branch-3
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/file-in-branch-3
commit 07f9a94593ec3e065a7eeaedbbc5220ffe5c5722
Author: Pavel Tisnovsky
Files: ([file-in-branch-2 :add])
Added file-in-branch-2
Branches: ()
Changed files: ([file-in-branch-2 :add])
diff --git a/file-in-branch-2 b/file-in-branch-2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/file-in-branch-2
commit f84564ce7fa81f865e60d3d2e18f5789539a237a
Author: Pavel Tisnovsky
Files: ([file-in-branch-1 :add])
Added file-in-branch-1
Branches: ()
Changed files: ([file-in-branch-1 :add])
diff --git a/file-in-branch-1 b/file-in-branch-1
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/file-in-branch-1
commit 394ce42cb3bcf44ff4e9a94949814bacddcdfe9b
Author: Pavel Tisnovsky
Files: ([garbage :add])
Added garbage
Branches: (refs/heads/master)
Changed files: ([garbage :add])
diff --git a/garbage b/garbage
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/garbage
commit 0fd398ab16e53ea0b783aef2413d75b75c6462cd
Author: Pavel Tisnovsky
Files: ([README.md :edit])
Updated README.md
Branches: (refs/heads/master)
Changed files: ([README.md :edit])
diff --git a/README.md b/README.md
index 6edd528..04aafb8 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
# testrepo
testrepo
+hello!
commit badf2b12f9281a8581009bfa068a5147c4cbc87a
Author: Pavel Tisnovsky
Files: [[README.md :add]]
Initial commit
Branches: (refs/heads/master)
Changed files: [[README.md :add]]
nil
10. Repositář s dnešními demonstračními příklady
Všechny čtyři dnes popsané demonstrační příklady byly, podobně jako v předchozích částech tohoto seriálu, uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/clojure-examples. V tabulce zobrazené pod tímto odstavcem naleznete na zdrojové kódy jednotlivých demonstračních příkladů přímé odkazy:
| # | Příklad | Github |
|---|---|---|
| 1 | git-test12 | https://github.com/tisnik/clojure-examples/tree/master/git-test12 |
| 2 | git-test13 | https://github.com/tisnik/clojure-examples/tree/master/git-test13 |
| 3 | git-test14 | https://github.com/tisnik/clojure-examples/tree/master/git-test14 |
| 4 | git-test15 | https://github.com/tisnik/clojure-examples/tree/master/git-test15 |
11. Odkazy na předchozí části tohoto seriálu
Stalo se již zvykem uvést odkazy na všechny předchozí části tohoto seriálu. Tento zvyk samozřejmě dodržíme i dnes:
- Leiningen: nástroj pro správu projektů napsaných v Clojure
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (2)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-2/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (3)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-3/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (4)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-4/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (5)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-5/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (6)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-6/ - Programovací jazyk Clojure a databáze (1.část)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/ - Pluginy pro Leiningen
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (dokončení)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-dokonceni/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (2)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (3)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-3/ - Programovací jazyk Clojure a práce s Gitem
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/ - Programovací jazyk Clojure a práce s Gitem (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/
12. Odkazy na Internetu
- Seriál o Gitu: 1. díl – Git – Historie a principy
http://www.itnetwork.cz/git-tutorial-historie-a-principy - 2. díl – Git – Instalace a vytvoření repositáře
http://www.itnetwork.cz/git-tutorial-instalace-a-stazeni-repositare - 3. díl – Git – Základy
http://www.itnetwork.cz/git-tutorial-zaklady - 4. díl – Git – Zkoumání historie
http://www.itnetwork.cz/git-tutorial-historie - 5. díl – Git – Rozděluj a panuj
http://www.itnetwork.cz/git-tutorial-vetve - 6. díl – Git – práce se vzdáleným repositářem
http://www.itnetwork.cz/git-prace-se-vzdalenym-repositarem - 3.1 Git Branching – What a Branch Is
http://git-scm.com/book/en/v1/Git-Branching-What-a-Branch-Is - Building User Interfaces with Seesaw (slajdy k přednášce)
http://darevay.com/talks/clojurewest2012/#/title-slide - Seesaw na GitHubu
https://github.com/daveray/seesaw - Seesaw API Documentation
http://daveray.github.io/seesaw/ - Seesaw wiki
https://github.com/daveray/seesaw/wiki - seesaw-repl-tutorial.clj
https://gist.github.com/daveray/1441520 - Témata o Seesaw na Google groups
https://groups.google.com/forum/#!forum/seesaw-clj - Threading macro (dokumentace k jazyku Clojure)
https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/-> - Understanding the Clojure → macro
http://blog.fogus.me/2009/09/04/understanding-the-clojure-macro/ - Clisk
https://github.com/mikera/clisk - clojars: net.mikera/clisk
https://clojars.org/net.mikera/clisk - clojure.inspector
http://clojure.github.io/clojure/clojure.inspector-api.html - Clisk: wiki
https://github.com/mikera/clisk/wiki - Dokumentace vygenerovaná pro knihovnu core.matrix
https://cloojure.github.io/doc/core.matrix/index.html - Size and Dimensionality
https://groups.google.com/forum/#!topic/numerical-clojure/zebBCa68eTw/discussion - Towards core.matrix for Clojure?
https://clojurefun.wordpress.com/2013/01/05/towards-core-matrix-for-clojure/ - The Clojure Toolbox
http://www.clojure-toolbox.com/ - Neanderthal
http://neanderthal.uncomplicate.org/ - Hello world project
https://github.com/uncomplicate/neanderthal/blob/master/examples/hello-world/project.clj - vectorz-clj
https://github.com/mikera/vectorz-clj - vectorz – Examples
https://github.com/mikera/vectorz-clj/wiki/Examples - gloss
https://github.com/ztellman/gloss - HTTP client/server for Clojure
http://www.http-kit.org/ - Array Programming
https://en.wikipedia.org/wiki/Array_programming - Discovering Array Languages
http://archive.vector.org.uk/art10008110 - no stinking loops – Kalothi
http://www.nsl.com/ - Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
http://www.vector.org.uk/ - APL Interpreters
http://www.vector.org.uk/?area=interpreters - APL_(programming_language
http://en.wikipedia.org/wiki/APL_(programming_language - APL FAQ
http://www.faqs.org/faqs/apl-faq/ - APL FAQ (nejnovější verze)
http://home.earthlink.net/~swsirlin/apl.faq.html - A+
http://www.aplusdev.org/ - APLX
http://www.microapl.co.uk/ - FreeAPL
http://www.pyr.fi/apl/index.htm - J: a modern, high-level, general-purpose, high-performance programming language
http://www.jsoftware.com/ - K, Kdb: an APL derivative for Solaris, Linux, Windows
http://www.kx.com - openAPL (GPL)
http://sourceforge.net/projects/openapl - Parrot APL (GPL)
http://www.parrotcode.org/ - Learning J (Roger Stokes)
http://www.jsoftware.com/help/learning/contents.htm - Rosetta Code
http://rosettacode.org/wiki/Main_Page - Why APL
http://www.acm.org/sigapl/whyapl.htm - java.jdbc API Reference
https://clojure.github.io/java.jdbc/ - Hiccup
https://github.com/weavejester/hiccup - Clojure Ring na GitHubu
https://github.com/ring-clojure/ring - A brief overview of the Clojure web stack
https://brehaut.net/blog/2011/ring_introduction - Getting Started with Ring
http://www.learningclojure.com/2013/01/getting-started-with-ring.html - Getting Started with Ring and Compojure – Clojure Web Programming
http://www.myclojureadventure.com/2011/03/getting-started-with-ring-and-compojure.html - Unit Testing in Clojure
http://nakkaya.com/2009/11/18/unit-testing-in-clojure/ - Testing in Clojure (Part-1: Unit testing)
http://blog.knoldus.com/2014/03/22/testing-in-clojure-part-1-unit-testing/ - API for clojure.test – Clojure v1.6 (stable)
https://clojure.github.io/clojure/clojure.test-api.html - Leiningen: úvodní stránka
http://leiningen.org/ - Leiningen: Git repository
https://github.com/technomancy/leiningen - leiningen-win-installer
http://leiningen-win-installer.djpowell.net/ - Clojure 1: Úvod
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/ - Clojure 2: Symboly, kolekce atd.
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/ - Clojure 3: Funkcionální programování
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-3-cast-funkcionalni-programovani/ - Clojure 4: Kolekce, sekvence a lazy sekvence
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-4-cast-kolekce-sekvence-a-lazy-sekvence/ - Clojure 5: Sekvence, lazy sekvence a paralelní programy
http://www.root.cz/clanky/clojure-a-bezpecne-aplikace-pro-jvm-sekvence-lazy-sekvence-a-paralelni-programy/ - Clojure 6: Podpora pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/ - Clojure 7: Další funkce pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/ - Clojure 8: Identity, stavy, neměnné hodnoty a reference
http://www.root.cz/clanky/programovaci-jazyk-clojure-8-identity-stavy-nemenne-hodnoty-a-referencni-typy/ - Clojure 9: Validátory, pozorovatelé a kooperace s Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-9-validatory-pozorovatele-a-kooperace-mezi-clojure-a-javou/ - Clojure 10: Kooperace mezi Clojure a Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/ - Clojure 11: Generátorová notace seznamu/list comprehension
http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/ - Clojure 12: Překlad programů z Clojure do bajtkódu JVM I:
http://www.root.cz/clanky/programovaci-jazyk-clojure-12-preklad-programu-z-clojure-do-bajtkodu-jvm/ - Clojure 13: Překlad programů z Clojure do bajtkódu JVM II:
http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/ - Clojure 14: Základy práce se systémem maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/ - Clojure 15: Tvorba uživatelských maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/ - Clojure 16: Složitější uživatelská makra
http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/ - Clojure 17: Využití standardních maker v praxi
http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/ - Clojure 18: Základní techniky optimalizace aplikací
http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Clojure 19: Vývojová prostředí pro Clojure
http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/ - Clojure 20: Vývojová prostředí pro Clojure (Vimu s REPL)
http://www.root.cz/clanky/programovaci-jazyk-clojure-20-vyvojova-prostredi-pro-clojure-integrace-vimu-s-repl/ - Clojure 21: ClojureScript aneb překlad Clojure do JS
http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/