lucid.git wrapper for org.eclipse.jgit

Author: Chris Zheng  (z@caudate.me)
Date: 16 February 2017
Repository: https://www.github.com/zcaudate/lucidity
Version: 1.3.4

1    Introduction

lucid.git is used to as an interface to jgit.

The aims of this project are:

  • self-directed exploration of the jgit library
  • simple and easy to use interface

1.1    Installation

Add to project.clj dependencies:

[im.chit/lucid.git "1.3.4"]

All functionality is in the lucid.git namespace:

(require '[lucid.git :refer [git]])

2    Usage

2.1    Help

To see all commands, there is the :help command:

(git :help) ;; or (git)
=> [:add :apply :archive :blame :branch :checkout :cherry
    :clean :clone :commit :describe :diff :fetch :gc :init
    :log :ls :merge :name :notes :pull :push :rebase :reflog
    :remote :reset :revert :rm :stash :status :submodule :tag]

To see a command's sub-commands, just

(git :branch)
=> #{:create :delete :rename :list}

2.2    Basics

2.2.1    :init

The :init command initialise a directory:

(git :init :directory "/tmp/git-example")
=> "/tmp/git-example/.git"

2.2.2    :status

The :status command checks the status of our new repository:

(git "/tmp/git-example" :status)
=> {:clean? true
    :uncommitted-changes! false}

Having a directory as the first parameter sets the default directory so that next time :status is called, it doesn't need to be set:

(git :status)
=> {:clean? true
    :uncommitted-changes! false}

We can add a file and check for the repository status:

(spit "/tmp/git-example/hello.txt" "hello there")
(git :status)
=> {:clean? false,
    :uncommitted-changes! false,
    :untracked #{"hello.txt"}}

2.2.3    :cd

:cd sets the default directory:

(git :cd "/tmp/git-example")
(git :status)
=> {:clean? false,
    :uncommitted-changes! false,
    :untracked #{"hello.txt"}}

2.2.4    :pwd

:pwd retruns the current working directory:

(git :pwd)
=> "/tmp/git-example"

2.3    Exploration

Help is avaliable at anytime by using :? or :help after the first command:

(git :init :?)
=> {:bare boolean,
    :directory java.lang.String,
    :git-dir java.lang.String}

Additional parameters may be put in:

(git :init
     :bare false
     :directory "/tmp/git-example"
     :git-dir "/tmp/git-example/.mercurial")
=> "/tmp/git-example/.mercurial"

Let's take a closer look at :status

(git :status :?)
=> {:working-tree-it   org.eclipse.jgit.treewalk.WorkingTreeIterator, 
    :progress-monitor  org.eclipse.jgit.lib.ProgressMonitor, 
    :ignore-submodules #{"NONE" "UNTRACKED" "DIRTY" "ALL"}, 
    :path              [java.lang.String]}

We can decode the representation of the options needed for:

  • :working-tree-it an input of type org.eclipse.jgit.treewalk.WorkingTreeIterator
  • :progress-monitor an input of type org.eclipse.jgit.lib.ProgressMonitor
  • :ignore-submodules an input of the following options #{"NONE" "UNTRACKED" "DIRTY" "ALL"}
  • :path, either a single or a vector input of type java.lang.String

2.4    Local

2.4.1    :add

Options that :add take are:

(git :add :?)
=> {:filepattern [java.lang.String]
    :update boolean
    :working-tree-iterator org.eclipse.jgit.treewalk.WorkingTreeIterator}

We can now create three files and calling :add on hello.txt

(git :init :directory "/tmp/git-example")
(git :cd "/tmp/git-example")
(do (spit "/tmp/git-example/hello.txt" "hello")
    (spit "/tmp/git-example/world.txt" "world")
    (spit "/tmp/git-example/again.txt" "again"))

(git :add :filepattern ["hello.txt"])
=> {"hello.txt" #{:merged}}

2.4.2    :commit

Options that :commit take are:

(git :commit :?)
=> {:all boolean
    :allow-empty boolean
    :amend boolean
    :author java.lang.String
    :committer java.lang.String
    :hook-output-stream java.lang.String
    :insert-change-id boolean
    :message java.lang.String
    :no-verify boolean
    :only java.lang.String
    :reflog-comment java.lang.String}

The revision can now be committed:

(git :commit :message "added hello.txt")
=> {:commit-time 1487219645,
    :author-ident {:email-address "z@caudate.me",
                   :name "Chris Zheng",
                   :time-zone-offset 660,
                   :when #inst "2017-02-16T04:34:05.000-00:00"},
    :full-message "added hello.txt",
    :name "c115771e38cfd22954cfbc0c1a5c0b7e7890b09f"}

:commit works like the shell git commit command, such as if the message is neede to be amended:

(git :commit :message "added hello.txt with fix" :amend true)
=> {:commit-time 1487219780,
    :author-ident {:email-address "z@caudate.me",
                   :name "Chris Zheng",
                   :time-zone-offset 660,
                   :when #inst "2017-02-16T04:34:05.000-00:00"},
    :full-message "added hello.txt with fix",
    :name "fa705232c13d19d3ef4b4b6cfd6993593615a55d"}

2.4.3    :log

``

(git :log)
=> [{:commit-time 1487219780,
     :author-ident {:email-address "z@caudate.me",
                   :name "Chris Zheng",
                   :time-zone-offset 660,
                   :when #inst "2017-02-16T04:34:05.000-00:00"},
     :full-message "added hello.txt with fix",
     :name "fa705232c13d19d3ef4b4b6cfd6993593615a55d"}]

2.4.4    :rm

:rm removes files from git:

(git :rm :?)
=> {:filepattern [java.lang.String], :cached boolean}

hello.txt is removed and the revision committed

(git :rm :filepattern ["hello.txt"])
(git :add :filepattern ["again.txt"])
=> {"again.txt" #{:merged}}

(git :commit :message "added again.txt, removed hello.txt")
=> {:commit-time 1487219780,
     :author-ident {:email-address "z@caudate.me",
                    :name "Chris Zheng",
                    :time-zone-offset 660,
                    :when #inst "2017-02-16T04:34:05.000-00:00"},
     :full-message "added hello.txt with fix",
    :name "fa705232c13d19d3ef4b4b6cfd6993593615a55d"}

2.4.5    workflow

:log and :status show more information about the revision whilst more changes can be committed

(git :log)
=> [{:commit-time 1487223636,
     :author-ident {:email-address "z@caudate.me",
                    :name "Chris Zheng",
                    :time-zone-offset 660,
                    :when #inst "2017-02-16T05:40:36.000-00:00"},
     :full-message "added again.txt, removed hello.txt",
     :name "f00dae4b70f00daf90816ece100d49678b0f9271"}
    {:commit-time 1487219780,
     :author-ident {:email-address "z@caudate.me",
                    :name "Chris Zheng",
                    :time-zone-offset 660,
                    :when #inst "2017-02-16T04:34:05.000-00:00"},
     :full-message "added hello.txt with fix",
     :name "fa705232c13d19d3ef4b4b6cfd6993593615a55d"}]

(git :status)
=> {:untracked ["world.txt"] :clean? false}

(git :add :filepattern ["."])
=> {"again.txt" #{:merged}, "world.txt" #{:merged}}

(git :commit :message "added ALL files" :amend true)
=> {:commit-time 1487224441,
    :author-ident {:email-address "z@caudate.me"
                   :name "Chris Zheng",
                   :time-zone-offset 660,
                   :when #inst "2017-02-16T05:52:34.000-00:00"},
    :full-message "added ALL files",
    :name "02cecb2b8c08c1599ba95c165e08b633698cad99"}

(git :status)
=> {:clean? true}

2.5    Raw Objects

When :& is used in the parameter, the raw result of the commant call is returned instead of being converted into a corresponding map/string:

(git :status :&)
;; => #status{:conflicting []
;;            :untracked-folders []
;;            :missing []
;;            :removed []
;;            :clean? true}

(type (git :status :&))
=> org.eclipse.jgit.api.Status

(type (git :log :&))
=> org.eclipse.jgit.revwalk.RevWalk

2.6    Branching

2.6.1    :branch

The subcommands for :branch are:

(git :branch)
=> #{:create :delete :rename :list}

Branches for the repository are shown with the :list subcommand:

(git :branch :list)
=> [{:name "refs/heads/master",
     :object-id "02cecb2b8c08c1599ba95c165e08b633698cad99",
     :storage "LOOSE",
     :peeled? false,
     :symbolic? false}]

New branches are be created through the :create subcommand:

(git :branch :create :name "dev")
=> {:name "refs/heads/dev",
    :object-id "02cecb2b8c08c1599ba95c165e08b633698cad99",
    :storage "LOOSE",
    :peeled? false,
    :symbolic? false}
  
(git :branch :list)
=> [{:name "refs/heads/dev",
     :object-id "02cecb2b8c08c1599ba95c165e08b633698cad99",
     :storage "LOOSE",
     :peeled? false,
     :symbolic? false}
    {:name "refs/heads/master",
     :object-id "02cecb2b8c08c1599ba95c165e08b633698cad99",
     :storage "LOOSE",
     :peeled? false,
     :symbolic? false}]

Branches are renamed through the :rename subcommand:

(git :branch :rename :?)
=> {:new-name java.lang.String,
    :old-name java.lang.String}

(git :branch :rename :new-name "development" :old-name "dev")
=> {:name "refs/heads/development",
    :object-id "02cecb2b8c08c1599ba95c165e08b633698cad99",
    :storage "LOOSE",
    :peeled? false,
    :symbolic? false}

Branches are deleted through the :delete subcommand:

(git :branch :delete :?)
=> {:branch-names [java.lang.String]
    :force boolean}

(git :branch :delete :branch-names (into-array ["development"]))
=> ["refs/heads/development"]

2.6.2    :checkout

Branches for the repository can be accessed through :checkout

(git :checkout :?)
=> {:path [java.lang.String],
    :start-point java.lang.String,
    :create-branch boolean,
    :stage #{"BASE" "THEIRS" "OURS"},
    :force boolean,
    :name java.lang.String,
    :paths [java.util.List],
    :upstream-mode #{"SET_UPSTREAM" "NOTRACK" "TRACK"},
    :all-paths boolean,
    :orphan boolean}

(git :branch :create :name "dev")

(git :checkout :name "dev")
=> {:name "refs/heads/dev",
    :object-id "02cecb2b8c08c1599ba95c165e08b633698cad99",
    :storage "LOOSE",
    :peeled? false,
    :symbolic? false}