     cl-git 2.0.0, Jan 21, 2023

     Russell Sim

     Copyright © 2011-2022, Russell Sim

   Generated by Sphinx 6.1.3.

cl-git Documentation
********************

     cl-git 2.0.0, Jan 21, 2023

     Russell Sim

     Copyright © 2011-2022, Russell Sim

CL-Git is an interface to the C library libgit2(1).  The API is an
almost complete exposure of the underlying library.

License LLGPL(2)

This is the HTML documentation, but there is also, ‘pdf’ and ‘info’

The source is available on SourceHut(3).

     GIT> (resolve
           (get-object 'reference "HEAD"
                       (open-repository
                        (merge-pathnames #p"projects/lisp/cl-git"
                                         (user-homedir-pathname)))))
     #<COMMIT 276EE31DD4F35E49AEB7C7FCFB8094D557A25AD1 {100817E383}>
     (#<REFERENCE refs/heads/master {100817C403}> #<REFERENCE HEAD {100817C0C3}>)

     GIT> (tree-directory (commit-tree *))
     (#<TREE-BLOB .gitignore (weak) {100A8A1E73}>
      #<TREE-BLOB AUTHORS (weak) {100A8A3E33}>
      #<TREE-BLOB CHANGELOG (weak) {100A8A5483}>
      ...)

 — The Detailed Node Listing —

Objects

Errors

Repositories

Creating

References

Accessing

Listing

Commits

Accessing

Tag

Details

Tree

Listing Contents

Blob

Index

Using

Internals

Memory Management

Changelog

2.0.0 - 2023-01-05

Contributing

Testing

   ---------- Footnotes ----------

   (1) http://libgit2.github.com/

   (2) http://opensource.franz.com/preamble.html

   (3) https://sr.ht/~rsl/cl-git/

1 Objects
*********

1.1 Creating
============

 -- Common Lisp Generic: (make-objectclass id/name repository &key url
          type force target signature message log-message
          &allow-other-keys)

      -- Method: (see make-object. (class (eq REFERENCE))
               (name T(1)) (repository T(2)) &KEY (TYPE :OID) FORCE
               TARGET SIGNATURE (LOG-MESSAGE ""))

      -- Method: (‘make-object’ (class (eq BRANCH)) (name T(3))
               (repository T(4)) &KEY TARGET FORCE)

      -- Method: (see make-object. (class (eq TAG)) (name
               T(5)) (repository T(6)) &KEY (TYPE :ANNOTATED) FORCE
               TARGET SIGNATURE MESSAGE)

      -- Method: (‘make-object’ (class (eq REMOTE)) (name
               T(7)) (repository T(8)) &KEY URL)

     Create objects within a Git repository, Please see the
     documentation for each implementing method.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (3) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (4) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (5) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (6) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (7) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (8) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

1.2 Accessing
=============

 -- Common Lisp Generic: (get-objectclass id/name repository)

      -- Method: (‘get-object’ (class (eq OBJECT)) (oid T(1))
               (repository T(2)))

      -- Method: (see get-object. (class (eq BLOB)) (oid
               T(3)) (repository T(4)))

      -- Method: (see get-object. (class (eq TREE)) (oid
               T(5)) (repository T(6)))

      -- Method: (see get-object. (class (eq COMMIT))
               (oid T(7)) (repository T(8)))

      -- Method: (‘get-object’ (class (eq COMMIT)) (commit
               COMMIT) (repository T(9)))

      -- Method: (see get-object. (class (eq REFERENCE))
               (name T(10)) (repository T(11)))

      -- Method: (see get-object. (class (eq TAG))
               (name-or-oid T(12)) (repository T(13)))

      -- Method: (see get-object. (class (eq REMOTE))
               (name T(14)) (repository T(15)))

      -- Method: (see get-object. (class (eq ODB-OBJECT))
               (oid T(16)) (odb ODB))

      -- Method: (see get-object. (class (eq ODB-OBJECT))
               (oid T(17)) (repository REPOSITORY))

     Return an object of type ‘CLASS’ from the object database.  The
     lookup will use either an oid or a name to find the object.

 -- Common Lisp Generic: (list-objectsclass repository &key test
          test-not)

      -- Method: (see list-objects. (class (eq REFERENCE))
               (repository T(18)) &KEY TEST TEST-NOT)

      -- Method: (see list-objects. (class (eq TAG))
               (repository T(19)) &KEY TEST TEST-NOT)

      -- Method: (see list-objects. (class (eq REMOTE))
               (repository T(20)) &KEY TEST TEST-NOT)

      -- Method: (see list-objects. (class (eq :OID)) (repository
               ODB) &KEY TEST TEST-NOT)

      -- Method: (see list-objects. (class (eq :OID)) (repository
               REPOSITORY) &KEY TEST TEST-NOT)

Note that although we are looking up a commit we specify as class
OBJECT. The advantage of specifying OBJECT instead of COMMIT is that you
do not need to know that the SHA refers to a commit.  If the SHA refers
to a tag a tag will be returned.

However if we do not know the SHA-1 but we do know a reference, such as
a branch name or tag.  We can get to the commit in a slightly more
cumbersome way.  (A list of references is easy to get, see the previous
section.)

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (3) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (4) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (5) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (6) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (7) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (8) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (9) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (10) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (11) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (12) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (13) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (14) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (15) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (16) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (17) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (18) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (19) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (20) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

1.3 Inspecting
==============

 -- Common Lisp Generic: (oidobject)

      -- Method: (‘oid’ (object CL-GIT::GIT-OBJECT))

      -- Method: (‘oid’ (reference REFERENCE))

      -- Method: (‘oid’ (object ODB-OBJECT))

     Return the identifier of ‘OBJECT’.  The identifier is typically the
     ‘SHA’-1 checksum or hash code.

     Note that this is an integer, and not the string you typically see
     reported by Git.

     To get the string representation use format like this:

          (format nil “~40,’0X” (oid object))

     or if you want lowercase hexadecimal digits:

          (format nil “~(~40,’0X~)” (oid object))

 -- Common Lisp Generic: (full-nameobject)

      -- Method: (‘full-name’ (object CL-GIT::GIT-OBJECT))

      -- Method: (see full-name. (object REFERENCE))

      -- Method: (see full-name. (tag TAG))

      -- Method: (see full-name. (remote REMOTE))

     Returns the name of ‘OBJECT’, as a string.

     What exactly the name is depends on the type of the object.

 -- Common Lisp Generic: (short-nameobject)

      -- Method: (‘short-name’ (object CL-GIT::GIT-OBJECT))

      -- Method: (see short-name. (object REFERENCE))

      -- Method: (see short-name. (tag TAG))

      -- Method: (see short-name. (remote REMOTE))

     Returns the short name of ‘OBJECT’, as a string.

     What exactly the name is depends on the type of the object.

1.4 Errors
==========

Error conditions can be raised from libgit2 and will be converted into
conditions instead of returning NIL values.

     GIT> (get-object 'object 1
                      (open-repository #p"/home/russell/projects/ecl/"))
     ; Raises NOT-FOUND condition

For each of the possible libgit2 errors there is a different condition
that will be raised.

 -- Common Lisp Class: general-error

     Generic error

 -- Common Lisp Class: not-found-error

     Requested object could not be found

 -- Common Lisp Class: exists-error

     Object exists preventing operation

 -- Common Lisp Class: ambiguous-error

     More than one object matches

 -- Common Lisp Class: buffer-error

     Output buffer too short to hold data

 -- Common Lisp Class: user-error

     GIT_EUSER is a special error that is never generated by libgit2
     code.  You can return it from a callback (e.g to stop an iteration)
     to know that it was generated by the callback and not by libgit2.

 -- Common Lisp Class: barerepo-error

     Operation not allowed on bare repository

 -- Common Lisp Class: unborn-branch-error

     HEAD refers to branch with no commits

 -- Common Lisp Class: unmerged-error

     Merge in progress prevented operation

 -- Common Lisp Class: non-fast-forward-error

     Reference was not fast-forwardable

 -- Common Lisp Class: invalid-spec-error

     Name/ref spec was not in a valid format

 -- Common Lisp Class: conflict-error

     Checkout conflicts prevented operation

 -- Common Lisp Class: locked-error

     Lock file prevented operation

 -- Common Lisp Class: modified-error

     Reference value does not match expected

 -- Common Lisp Class: auth-error

     Authentication error

 -- Common Lisp Class: certificate-error

     Server certificate is invalid

 -- Common Lisp Class: applied-error

     Patch/merge has already been applied

 -- Common Lisp Class: peel-error

     The requested peel operation is not possible

 -- Common Lisp Class: eof-error

     Unexpected EOF

 -- Common Lisp Class: invalid-error

     Invalid operation or input

 -- Common Lisp Class: uncommitted-error

     Uncommitted changes in index prevented operation

 -- Common Lisp Class: directory-error

     The operation is not valid for a directory

 -- Common Lisp Class: merge-conflict-error

     A merge conflict exists and cannot continue

 -- Common Lisp Class: mismatch-error

     Hashsum mismatch in object

 -- Common Lisp Class: index-dirty-error

     Unsaved changes in the index would be overwritten

 -- Common Lisp Class: apply-fail-error

     Patch application failedq

1.4.1 Control Flow Errors
-------------------------

 -- Common Lisp Class: passthrough

     A user-configured callback refused to act

 -- Common Lisp Class: stop-iteration

     Signals end of iteration with iterator

 -- Common Lisp Class: retry

     Internal only

2 Repositories
**************

 -- Common Lisp Class: repository

     Repository is the root type, it contains the object database.

2.1 Creating
============

 -- Common Lisp Generic: (init-repositorypath/name &key bare)

      -- Method: (‘init-repository’ (path STRING(1)) &KEY BARE)

      -- Method: (‘init-repository’ (path PATHNAME(2)) &KEY BARE)

     Create a new Git repository.  ‘PATH/NAME’ can be either an instance
     of a STRING(3) or a PATHNAME(4). A truthful value for the key
     ‘BARE’ will init a repository that does not have a local checkout,
     it’s normally appropriate for the basename of the path to end in
     ‘.git’.  A REPOSITORY instance is returned.

          GIT> (init-repository #p"/tmp/test-repo/")
          #<REPOSITORY 7FFFE8006800 {1005F3CE43}>

 -- Common Lisp Generic: (empty-prepository)

      -- Method: (‘empty-p’ (repository REPOSITORY))

     Return T(5) if the repository is empty and contains no references.

          GIT> (empty-p (open-repository #p"/tmp/test-repo/"))
          T

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_string.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_pn.htm

   (3) http://www.lispworks.com/reference/HyperSpec/Body/a_string.htm

   (4) http://www.lispworks.com/reference/HyperSpec/Body/a_pn.htm

   (5) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

2.1.1 Bare
----------

Bare repositories can be created by passing a truthful value to the key
argument BARE when initialising a repository.

     GIT> (init-repository #p"/tmp/test-bare/" :bare t)
     #<REPOSITORY 7FFFE8008CD0 {10062DE723}>

Whether an existing repository is bare can be determined using the
bare-p method.

 -- Common Lisp Generic: (bare-prepository)

      -- Method: (‘bare-p’ (repository REPOSITORY))

     Return T(1) if the repository is bare.

          GIT> (bare-p (open-repository #p"/tmp/test-bare/"))
          T

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

2.2 Accessing
=============

 -- Common Lisp Generic: (open-repositorypath/name)

      -- Method: (‘open-repository’ (path STRING(1)))

      -- Method: (‘open-repository’ (path PATHNAME(2)))

     Open an existing repository located at ‘PATH/NAME’.  The repository
     object will be garbage collected.  If it’s freed explicitly then
     all related objects will have undefined behaviour.

          GIT> (open-repository #p"/home/russell/projects/ecl/")
          #<REPOSITORY 7FFFE8003E00 {1004CCDBA3}>
          GIT> (open-repository "/home/russell/projects/ecl/")
          #<REPOSITORY 7FFFE8004000 {1004D617F3}>

 -- Common Lisp Macro: (with-repository (var pathname-or-string) &body
          body)

     Evaluates the body with ‘VAR’ bound to a newly opened located
     repository at ‘PATHNAME-OR-STRING’.  Repository is freed upon exit
     of this scope so any objects that leave this scope will no longer
     be able to access the repository.

     Parameters:

        * ‘pathname-or-string’ – the location of the repository.

        * ‘path’ – the path to the git repository.

        * ‘body’ – the body of the macro.

          CL-GIT> (with-repository (repository #p"/home/russell/projects/ecl/")
                    (prin1 repository)
                    nil)
          #<REPOSITORY 7FFFE8003E00 {1003880DA3}>
          NIL

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_string.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_pn.htm

2.3 Checkout
============

 -- Common Lisp Generic: (checkoutobject repository)

      -- Method: (‘checkout’ (object REFERENCE) (repository
               T(1)))

      -- Method: (‘checkout’ (object T(2)) (repository T(3)))

     Checkout an object and replace the working tree and index with it’s
     content.  If passed a reference update the head ot point at the
     reference.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (3) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

2.4 Head
========

 -- Common Lisp Generic: (repository-headrepository)

      -- Method: (‘repository-head’ (repository REPOSITORY))

     Returns the resolved reference for ‘HEAD’.

 -- Common Lisp Generic: (head-detached-prepository)

      -- Method: (‘head-detached-p’ (repository REPOSITORY))

     Returns T(1) if the ‘HEAD’ in the repository is detached, in other
     words, the ‘HEAD’ reference is not a symbolic reference to a
     branch, but a direct commit.

 -- Common Lisp Generic: (head-unborn-prepository)

      -- Method: (‘head-unborn-p’ (repository REPOSITORY))

     Returns T(2) if the ‘HEAD’ points to a commit that doesn’t exist.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

2.5 Path
========

 -- Common Lisp Generic: (repository-pathobject)

      -- Method: (‘repository-path’ (repository REPOSITORY))

     Return the path to the repository.  In the case where the
     repository isn’t bare then it will be the location of the .git
     directory.

 -- Common Lisp Generic: (repository-workdirobject)

      -- Method: (‘repository-workdir’ (repository REPOSITORY))

     Return the path to the root of the repository.

2.6 Status
==========

 -- Common Lisp Function: (repository-statusrepository)

     Return the current status values for each of the object in the
     repository.  For each element of the list the FIRST(1) is the name
     of the file and the CDR(2) is a list of keywords that containing
     the current state of the file.  Possible states are: ‘:CURRENT’
     ‘:INDEX-NEW’ ‘:INDEX-MODIFIED’ ‘:INDEX-DELETED’ ‘:INDEX-RENAMED’
     ‘:INDEX-TYPECHANGE’ ‘:WORKTREE-NEW’ ‘:WORKTREE-MODIFIED’
     ‘:WORKTREE-DELETED’ ‘:WORKTREE-TYPECHANGE’ ‘:WORKTREE-RENAMED’
     ‘:WORKTREE-UNREADABLE’ ‘:IGNORED’ or ‘:CONFLICTED’

          CL-GIT> (with-repository (repository #p"/home/russell/projects/lisp/cl-git/")
                     (repository-status repository))

          (("src/status.lisp" :CURRENT :WORKTREE-MODIFIED)
           ("src/package.lisp" :CURRENT :WORKTREE-MODIFIED)
           ("fabfile.pyc" :CURRENT :IGNORED)
           ("doc/repositories.rst" :CURRENT :WORKTREE-MODIFIED)
           ("doc/cl-git.html" :CURRENT :WORKTREE-NEW)
           ("doc/.installed.cfg" :CURRENT :IGNORED))

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/f_firstc.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/f_car_c.htm

2.7 Configuration
=================

Configuration details of a particular repository can be done with the
‘GIT-CONFIG’ method.

 -- Common Lisp Method: (git-config (object REPOSITORY) &key
          level)

     Open a Git config.  ‘LEVEL’ can be used to limit the git config to
     a specific level.  Possible levels are ‘:HIGHEST-LEVEL’ ‘:SYSTEM’
     ‘:XDG’ ‘:GLOBAL’ or ‘:LOCAL’

     See also: ‘git-config’

3 References
************

 -- Common Lisp Class: reference

3.1 Creating
============

 -- Common Lisp Method: (make-object (class (eq REFERENCE))
          (id/name T(1)) (repository T(2)) &key url type force target
          signature message log-message &allow-other-keys)

     Create a reference to ‘TARGET’.  The type of reference depends on
     ‘TYPE’.  If ‘TYPE’ is ‘:OID’ the value of ‘TARGET’ should be an
     OID and a direct reference is created.  If ‘TYPE’ is
     ‘:SYMBOLIC’, a symbolic reference is created and ‘TARGET’ should be
     a string.  ‘SIGNATURE’ should be a signature plist.  ‘LOG-MESSAGE’
     should be a string.

     If ‘FORCE’ is t the reference will be created, even if a reference
     with the same name already exists.  If ‘FORCE’ is nil, it will
     return an error if that is the case.

     See also: make-object.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

3.2 Accessing
=============

To access a single reference get object can be used, but the fully
qualified name of the reference must be specified.

 -- Common Lisp Method: (get-object (class (eq REFERENCE))
          (id/name T(1)) (repository T(2)))

     Find a reference by its full name e.g.: refs/heads/master Note that
     this function name clashes with the generic lookup function.  We
     need to figure this out by using the type argument to do dispatch.

          GIT> (get-object 'reference "refs/heads/master"
                   (open-repository (merge-pathnames #p"projects/lisp/cl-git"
                                                     (user-homedir-pathname))))
          #<REFERENCE refs/heads/master {100BA0E543}>

     See also: get-object.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

3.2.1 Details
-------------

 -- Common Lisp Method: (full-name (object REFERENCE))

     Return the full path to the REFERENCE as a STRING(1).

          GIT> (full-name
                 (get-object 'reference "refs/heads/master"
                               (open-repository (merge-pathnames #p"projects/lisp/cl-git"
                                                                 (user-homedir-pathname)))))
          "refs/heads/master"

     See also: full-name.

 -- Common Lisp Method: (short-name (object REFERENCE))

     Return the short name of the REFERENCE as a STRING(2).
     This could for example be the text “master” or “HEAD”.

          GIT> (short-name
                 (get-object 'reference "refs/heads/master"
                               (open-repository (merge-pathnames #p"projects/lisp/cl-git"
                                                                 (user-homedir-pathname)))))
          "master"

     See also: short-name.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_string.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_string.htm

3.2.2 Listing
-------------

 -- Common Lisp Method: (list-objects (class (eq REFERENCE))
          (repository T(1)) &key test test-not)

     List all the refs the returned list can be filtered using a
     PREDICATE.

     To list all the references present in a repository we use the
     function LIST-OBJECTS and tell to only list objects of
     type REFERENCE.

          GIT> (list-objects 'reference
                             (open-repository "/home/russell/projects/lisp/cl-git/"))
          (#<REFERENCE refs/remotes/origin/master (weak) {1004A66973}>
           #<REFERENCE refs/remotes/origin/0.17.0 (weak) {1004A66C53}>
           #<REFERENCE refs/remotes/origin/0.18.0 (weak) {1004A66DC3}>
           #<REFERENCE refs/remotes/origin/HEAD (weak) {1004A66F33}>
           #<REFERENCE refs/tags/0.1 (weak) {1004A677D3}>
           #<REFERENCE refs/heads/master (weak) {1004A67943}>
           #<REFERENCE refs/heads/0.18.0 (weak) {1004A67C23}>)

     See also: list-objects.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

3.2.2.1 Filtering Results
.........................

 -- Common Lisp Generic: (branch-preference)

      -- Method: (‘branch-p’ (reference REFERENCE))

      -- Method: (‘branch-p’ (reference STRING(1)))

     Return T(2) if the reference is within the git heads namespace.

          GIT> (list-objects 'reference repo :test #'branch-p)
          (#<REFERENCE refs/heads/master (weak) {1004A67943}>
           #<REFERENCE refs/heads/0.18.0 (weak) {1004A67C23}>)

 -- Common Lisp Generic: (symbolic-preference)

      -- Method: (‘symbolic-p’ (reference REFERENCE))

     Return T(3) if the reference is symbolic.

          GIT> (list-objects 'reference repo :test #'symbolic-p)
          (#<REFERENCE refs/remotes/origin/HEAD (weak) {1004A66F33}>)

 -- Common Lisp Generic: (remote-preference)

      -- Method: (‘remote-p’ (reference REFERENCE))

      -- Method: (‘remote-p’ (reference STRING(4)))

     Return T(5) if the reference is within the git remotes namespace.

          GIT> (list-objects 'reference repo :test #'remote-p)
          (#<REFERENCE refs/remotes/origin/master (weak) {1004A66973}>
           #<REFERENCE refs/remotes/origin/0.17.0 (weak) {1004A66C53}>
           #<REFERENCE refs/remotes/origin/0.18.0 (weak) {1004A66DC3}>
           #<REFERENCE refs/remotes/origin/HEAD (weak) {1004A66F33}>)

 -- Common Lisp Generic: (head-pbranch)

      -- Method: (‘head-p’ (branch REFERENCE))

     Returns T(6) if the current ‘HEAD’ points to this branch.  This
     means that this is the branch that is checked out.

          GIT> (list-objects 'reference repo :test #'head-p)
          (#<REFERENCE refs/remotes/origin/master (weak) {1004A66973}>)

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_string.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (3) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (4) http://www.lispworks.com/reference/HyperSpec/Body/a_string.htm

   (5) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (6) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

3.2.3 Resolving
---------------

 -- Common Lisp Generic: (targetobject)

      -- Method: (‘target’ (reference REFERENCE))

      -- Method: (see target. (tag TAG))

      -- Method: (setf (target (reference REFERENCE) &key
               signature (log-message "")) (val T(1)))

     Returns the target of ‘OBJECT’.

          GIT> (target (get-object 'reference "HEAD"
                   (open-repository (merge-pathnames #p"projects/ecl"
                                                     (user-homedir-pathname)))))
          #<REFERENCE refs/heads/master {1007CD3D53}>

 -- Common Lisp Generic: (resolveobject &optional stop-at)

      -- Method: (‘resolve’ (object REFERENCE) &OPTIONAL
               (STOP-AT ' (COMMIT TAG)))

      -- Method: (see resolve. (object TAG) &OPTIONAL
               (STOP-AT ' (COMMIT)))

          GIT> (resolve (get-object 'reference "HEAD"
                   (open-repository (merge-pathnames #p"projects/ecl"
                                                     (user-homedir-pathname)))))
          #<COMMIT E92F8C418F626A5041FC242C0FB1CEB1BEC4D61B {1007497AB3}>
          (#<REFERENCE refs/heads/master {1007496723}> #<REFERENCE HEAD {1007495C53}>)

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

3.2.4 Branches
--------------

In libgit2 and in cl-git, branches are references but in a different
namespace.  Which means that, the same function used to list references
is used to list branches.  To limit the references to branches only use
BRANCH-P.

 -- Common Lisp Generic: (branch-preference)

      -- Method: (‘branch-p’ (reference REFERENCE))

      -- Method: (‘branch-p’ (reference STRING(1)))

     Return T(2) if the reference is within the git heads namespace.

          GIT> (list-objects 'reference repo :test #'branch-p)
          (#<REFERENCE refs/heads/master (weak) {10051CF843}>
           #<REFERENCE refs/heads/0.18.0 (weak) {10051CF9B3}>)

     So a branch is a special kind of reference.  In git there are a few
     differences between branches and references:

        - branches are stored in a special location in the .git folder

        - branches are moved/updated during a git commit operation

     For a user of the git repository, this small difference between
     branches and normal references makes a huge difference.  You commit
     on branches and merge different branches.  But typically you will
     not deal with non branch references.

     Listing remote branches can be done with.

          GIT> (list-objects 'reference (open-repository #p"/home/russell/projects/ecl/")
                             :test #'remote-p)
          (#<REFERENCE refs/remotes/origin/master (weak) {1007A39EA3}>
           #<REFERENCE refs/remotes/origin/HEAD (weak) {1007A3A2F3}>)

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_string.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

4 Reference Logs
****************

 -- Common Lisp Generic: (reflogreference)

      -- Method: (‘reflog’ (reference REFERENCE))

 -- Common Lisp Method: (entries (object REFLOG) &key start
          end)

     Returns the elements of the collection ‘OBJECT’ as a list.  The
     start and end keyword arguments allow to retrieve a subset of all
     elements.  All entries with index satisfying

          START <= INDEX < END

     are returned.  If ‘END’ is not specified or nil, no ‘END’ condition
     exists.  start defaults to 0.

     See also: ‘entries’

 -- Common Lisp Method: (message (object REFLOG-ENTRY))

     Return the message associated with ‘OBJECT’.

     For example for commits this will return the commit message and for
     tags the message associated with the tag.

     See also: message.

 -- Common Lisp Method: (committer (object REFLOG-ENTRY))

     Returns the committer’s signature of ‘OBJECT’.

     A signature is a list with the keys ‘:NAME’ ‘:EMAIL’ and ‘:TIME’.
     The ‘:NAME’ and ‘:EMAIL’ values are strings, and the ‘:TIME’ value
     is ‘LOCAL’-TIME timestamp.

     See also: committer.

5 Commits
*********

 -- Common Lisp Class: commit

     Commit objects link the state of the tree with a description.
     Commits contain a description of the author, commit author and a
     message about the commit.  They also contain state information
     about the current tree and links to any parent commits.  Commits
     that have more then one parent are considered to be merges.

5.1 Creating
============

 -- Common Lisp Function: (make-committree-or-oid message &key
          (update-ref "head") author committer parents repository)

     Create a new commit from the tree with the OID specified
     and ‘MESSAGE’.  Optional ‘:UPDATE-REF’ is the name of the reference
     that will be updated to point to this commit.  The default value
     “HEAD” will update the head of the current branch.  If it’s value
     is NULL(1) then no reference will be updated.  ‘:AUTHOR’ is an
     optional instance of a ‘GIT-SIGNATURE’ that details the commit
     author.  ‘:COMMITTER’ is an optional instance of a ‘GIT-SIGNATURE’
     the details the committer.  ‘:PARENTS’ is an optional list of
     parent commits sha1 hashes.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_null.htm

5.2 Accessing
=============

There are a few ways to find commits in the repository, the easiest is
to find a commit when we know the SHA-1 has.  In that case the process
is as follows:

     GIT> (get-object 'commit "15b8410814ec05d63b85c5e4b735dcdc77719a08"
                      (open-repository #p"/home/russell/projects/ecl/"))
     #<COMMIT 15B8410814EC05D63B85C5E4B735DCDC77719A08 {10060B27A3}>

To get access to a single reference.

     GIT> (get-object 'reference "refs/heads/master"
                      (open-repository "/home/russell/projects/ecl/"))
     #<REFERENCE refs/heads/master {1006F13CB3}>

However to get from a reference to a commit is easy using the
TARGET method.

     GIT> (target (get-object 'reference "refs/heads/master"
                              (open-repository "/home/russell/projects/ecl/")))
     #<COMMIT E92F8C418F626A5041FC242C0FB1CEB1BEC4D61B {10071DE5B3}>

In this case we ended up with a commit, however a reference can refer to
any object in the git database, so tags, blobs and trees are also
possible.

Now in normal use you do not see references to blobs or trees very
frequently, but references to tags are more common.

So in normal code you have to check for that and act accordingly.

 -- Common Lisp Method: (get-object (class (eq COMMIT))
          (id/name T(1)) (repository T(2)))

     Return an object of type ‘CLASS’ from the object database.  The
     lookup will use either an oid or a name to find the object.

     See also: get-object.

 -- Common Lisp Macro: (bind-git-commits (bindings repository-or-odb)
          &body body)

     Lookup commits specified in the bindings.  The bindings syntax is
     similar to the LET(3) syntax except instead of needing to specify
     an initial form key arguments are used.  Atleast one key arguments
     ‘SHA’ or ‘HEAD’ must be specified.  ‘SHA’ is a hash of the commit.
     ‘HEAD’ is a full ref path.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (3) http://www.lispworks.com/reference/HyperSpec/Body/s_let_l.htm

5.2.1 Iterating
---------------

 -- Common Lisp Function: (revision-walkcommits &key (ordering :time))

     Create a revision walker starts iteration from the ‘COMMITS’
     listed.

     The ordering can be adjusted to ‘:NONE’ ‘:TOPOLOGICAL’ ‘:REVERSE’
     or ‘:TIME’, which is the default.

     Once created iteration over commits can be done with the method
     NEXT-REVISION method.

 -- Common Lisp Generic: (next-revisionwalker)

      -- Method: (‘next-revision’ (walker CL-GIT::REVISION-WALKER))

     Returns the next object for the walker.  If no objects are
     available anymore return nil.

To walk commits, see REVISION-WALK and NEXT-REVISION.
are provided.

     GIT> (let ((repository (open-repository (merge-pathnames #p"projects/ecl"
                                                (user-homedir-pathname)))))
            (loop
              :with walker = (revision-walk
                              (get-object 'commit "ea010dee347e50666331b77edcf0588735c3205a"
                                          repository))
              :for revision = (next-revision walker)
              :until (null revision)
              :collect revision))

     (#<COMMIT EA010DEE347E50666331B77EDCF0588735C3205A {1007BA1003}>
      #<COMMIT F2DA18A5913EEA2D3F8BBD336F08AB48D9D3ECCE {1007BA1253}>
      #<COMMIT DC4DF60020DF2BFF026B26E6227127F6A3CC9FC {1007BA14A3}>
      #<COMMIT FE8BCD1B8BD27891F260892CC16BBA4A93999D89 {1007BA16F3}>
      #<COMMIT 2D8D0CD44B87C724ACBCA9F835C2142778007DA9 {1007BA1943}>)

5.3 Inspecting
==============

 -- Common Lisp Generic: (messageobject)

      -- Method: (‘message’ (commit COMMIT))

      -- Method: (see message. (reflog-entry REFLOG-ENTRY))

      -- Method: (see message. (tag TAG))

     Return the message associated with ‘OBJECT’.

     For example for commits this will return the commit message and for
     tags the message associated with the tag.

          GIT> (message
                (get-object 'commit "ea010dee347e50666331b77edcf0588735c3205a"
                            (open-repository #p"/home/russell/projects/ecl/")))
          "Add new declaration, si::c-export-fname, which produces lisp compiled files with
          meaningful names for the exported functions. For instance,
              (proclaim '(si::c-export-fname union))
          is used to produce a C function with name clLunion, which can be directly used
          in other compiled files. This feature has been applied to almost all functions
          in the Lisp runtime.
          "

 -- Common Lisp Generic: (message-trailersmessage)

      -- Method: (‘message-trailers’ (message STRING(1)))

      -- Method: (‘message-trailers’ (message COMMIT))

     Read the message trailers and return a list of them.

          GIT> (message-trailers
                (get-object 'commit "ea010dee347e50666331b77edcf0588735c3205a"
                            (open-repository #p"/home/russell/projects/ecl/")))
          '((:key "Fixes" :value "https://example.com/foobar")
            (:key "Signed-off-by" :value "John Doe <john@doe.example.com>"))

 -- Common Lisp Generic: (authorobject)

      -- Method: (‘author’ (commit COMMIT))

     Returns the author’s signature of ‘OBJECT’.

     A signature is a list with the keys ‘:NAME’ ‘:EMAIL’ and ‘:TIME’.
     The ‘:NAME’ and ‘:EMAIL’ values are strings, and the ‘:TIME’ value
     is ‘LOCAL’-TIME timestamp.

          GIT> (author
                (get-object 'commit "ea010dee347e50666331b77edcf0588735c3205a"
                            (open-repository #p"/home/russell/projects/ecl/")))
          (:NAME "jjgarcia"
           :EMAIL "jjgarcia"
           :TIME @2001-07-13T02:32:15.000000+10:00
           :TIMEZONE #<LOCAL-TIME::TIMEZONE +0000>)

 -- Common Lisp Generic: (committerobject)

      -- Method: (‘committer’ (commit COMMIT))

      -- Method: (see committer. (reflog-entry REFLOG-ENTRY))

     Returns the committer’s signature of ‘OBJECT’.

     A signature is a list with the keys ‘:NAME’ ‘:EMAIL’ and ‘:TIME’.
     The ‘:NAME’ and ‘:EMAIL’ values are strings, and the ‘:TIME’ value
     is ‘LOCAL’-TIME timestamp.

          GIT> (committer
                (get-object 'commit "ea010dee347e50666331b77edcf0588735c3205a"
                            (open-repository #p"/home/russell/projects/ecl/")))
          (:NAME "jjgarcia"
           :EMAIL "jjgarcia"
           :TIME @2001-07-13T02:32:15.000000+10:00
           :TIMEZONE #<LOCAL-TIME::TIMEZONE +0000>)

 -- Common Lisp Generic: (parentscommit)

      -- Method: (‘parents’ (commit COMMIT))

     Returns a list of oids identifying the parents of ‘OBJECT’.

          GIT> (parents
                (get-object 'commit "ea010dee347e50666331b77edcf0588735c3205a"
                            (open-repository #p"/home/russell/projects/ecl/")))
          (#<COMMIT F2DA18A5913EEA2D3F8BBD336F08AB48D9D3ECCE (weak) {100559E5A3}>)

 -- Common Lisp Generic: (commit-treecommit)

      -- Method: (‘commit-tree’ (commit COMMIT))

     Returns the TREE object of the commit.

     To see the state of the repository when this commit was made, use
     the COMMIT-TREE.

          GIT> (commit-tree
                (target
                 (repository-head
                  (open-repository (merge-pathnames #p"projects/ecl"
                                                    (user-homedir-pathname))))))
          #<TREE 96F8A446E020204589710FE1BF0CE1DD5B5B5AD0 {10079C9C03}>

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_string.htm

5.4 Graph Traversal
===================

 -- Common Lisp Generic: (reachable-fromrepository commit commits)

      -- Method: (‘reachable-from’ (repository REPOSITORY)
               (commit COMMIT) (commits T(1)))

     Return T(2) if given commit is an ancestor of any of the given
     potential descendant commits.

          GIT> (with-repository (repository (merge-pathnames
                                             #p"projects/cl-git"
                                             (user-homedir-pathname)))
                (reachable-from
                 repository
                 (resolve (car (list-objects 'tag repository)) '(commit))
                 (list (get-object 'reference "refs/heads/master" repository))))
          T

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

6 Tag
*****

Within git there are 2 types of tags, lightweight and annotated.
Lightweight tags are ‘REFERENCES’ within the tag namespace.  Annotated
tags are objects stored in the ODB. Annotated tags have a TARGET and a
TAGGER, which makes them different from commits.  ‘TAG-P’ can be used to
determine if a tag or reference is a “tag”.

 -- Common Lisp Class: tag

     Tags are used to identify interesting points in the repositories
     history.

6.1 Details
===========

 -- Common Lisp Method: (full-name (object TAG))

     Returns the name of ‘OBJECT’, as a string.

     What exactly the name is depends on the type of the object.

     See also: full-name.

 -- Common Lisp Method: (short-name (object TAG))

     Returns the short name of ‘OBJECT’, as a string.

     What exactly the name is depends on the type of the object.

     See also: short-name.

 -- Common Lisp Generic: (taggerobject)

      -- Method: (‘tagger’ (tag REFERENCE))

      -- Method: (‘tagger’ (tag TAG))

     Returns the signature of the tagger of ‘OBJECT’.

     The return value is a signature (a property list with keys ‘:NAME’,
     ‘:EMAIL’ and ‘:TIME’.  If the tag is not annotated then nil will be
     returned.

 -- Common Lisp Method: (message (object TAG))

     Return the message associated with ‘OBJECT’.

     For example for commits this will return the commit message and for
     tags the message associated with the tag.

     See also: message.

6.1.1 Target
------------

 -- Common Lisp Method: (target (object TAG))

     Returns the target of a tag.

     See also: target.

 -- Common Lisp Method: (resolve (object TAG) &optional
          stop-at)

     Resolve the tag target until the target object is not a tag
     anymore.  Basically calls TARGET on tag and result until
     there is a COMMIT returned.

     Using values returns the finally found object and a list of the
     traversed objects.

     See also: resolve.

6.2 Creating
============

 -- Common Lisp Method: (make-object (class (eq TAG)) (id/name
          T(1)) (repository T(2)) &key url type force target signature
          message log-message &allow-other-keys)

     Create a tag to ‘TARGET’.  The type of tag depends on ‘TYPE’.  If
     ‘TYPE’ is ‘:ANNOTATED’ the value of ‘TARGET’ should be an
     OID and a direct tag is created.  If ‘TYPE’ is ‘:LIGHTWEIGHT’,
     a reference is created and ‘TARGET’ should be a OID.
     ‘SIGNATURE’ should be a signature plist.

     If ‘FORCE’ is t the tag will be created, even if a tag with the
     same name already exists.  If ‘FORCE’ is nil, it will return an
     error if that is the case.

     See also: make-object.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

6.3 Accessing
=============

 -- Common Lisp Method: (get-object (class (eq TAG)) (id/name
          T(1)) (repository T(2)))

     Return an object of type ‘CLASS’ from the object database.  The
     lookup will use either an oid or a name to find the object.

     See also: get-object.

 -- Common Lisp Method: (list-objects (class (eq TAG))
          (repository T(3)) &key test test-not)

     Returns a list of tag for the repository.  If the tag is an
     annotated tag then a TAG object will be returned,
     otherwise it will be a ref with the in the tag namespace.

          GIT> (list-objects 'tag (open-repository #p"/home/russell/projects/ecl/"))

          (#<TAG refs/tags/ECL.8.12.0 {1006621153}>
           #<REFERENCE refs/tags/ECL.9.8.3 {1006B277C3}>
           #<REFERENCE refs/tags/ECL.9.8.4 {1006B279C3}>
           #<REFERENCE refs/tags/ECL.9.8.2 {1006B27BC3}>
           #<REFERENCE refs/tags/ECLS.0.4 {1006B27DC3}>
           #<REFERENCE refs/tags/ECL.13.5.1 {1006B27FD3}>
           ...)

     See also: list-objects.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (3) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

7 Tree
******

 -- Common Lisp Class: tree

 -- Common Lisp Method: (get-object (class (eq TREE))
          (id/name T(1)) (repository T(2)))

     Return an object of type ‘CLASS’ from the object database.  The
     lookup will use either an oid or a name to find the object.

     See also: get-object.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

7.1 Listing Contents
====================

 -- Common Lisp Generic: (tree-directorytree &optional pathname)

      -- Method: (‘tree-directory’ (object TREE) &OPTIONAL
               PATHNAME)

     List objects from a tree.  Optional argument pathname a wild
     pathname that the entries must match.

          GIT> (tree-directory
                (commit-tree
                 (target
                  (repository-head
                   (open-repository (merge-pathnames #p"projects/ecl" (user-homedir-pathname)))))))
          (#<TREE-BLOB .gitignore (weak) {1007732933}>
           #<TREE-BLOB ANNOUNCEMENT (weak) {1007733AE3}>
           #<TREE-BLOB Copyright (weak) {1007734C53}>
           #<TREE-BLOB INSTALL (weak) {1007735DC3}>
           #<TREE-BLOB LGPL (weak) {1007736F13}>
           #<TREE-BLOB Makefile.in (weak) {10077380D3}>
           #<TREE-BLOB README.1st (weak) {1007739283}>
           #<TREE-BLOB configure (weak) {100773A3F3}>
           #<TREE-TREE contrib/ (weak) {100773B523}>
           #<TREE-TREE examples/ (weak) {100773C683}>
           #<TREE-TREE msvc/ (weak) {100773D7D3}>
           #<TREE-TREE src/ (weak) {100773E8D3}>)

7.1.1 Filtering
---------------

In the same way that DIRECTORY(1) can take wildcard pathnames to produce
limited list of results.

     GIT> (directory (merge-pathnames #p"projects/ecl/co*"
                                      (user-homedir-pathname)))
     (#P"/home/russell/projects/ecl/configure"
      #P"/home/russell/projects/ecl/contrib/")

TREE-DIRECTORY can be used to limit the results from the
directory tree.  Using a wild card will filter the results that are
returned.  Extending on the example above we can just list a subset of
the content with.

     GIT> (tree-directory
           (get-tree
            (target
             (repository-head
              (open-repository (merge-pathnames #p"projects/ecl"
                                                (user-homedir-pathname))))))
           #P"co*")
     (#<TREE-BLOB configure (weak) {1007C11A23}>
      #<TREE-TREE contrib/ (weak) {1007C130F3}>)

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/f_dir.htm

8 Blob
******

 -- Common Lisp Class: blob

     A git blob.

 -- Common Lisp Generic: (blob-sizeblob)

      -- Method: (‘blob-size’ (blob BLOB))

     Return the size of the blob in bytes.

 -- Common Lisp Generic: (blob-contentblob)

      -- Method: (‘blob-content’ (blob BLOB))

     Returns the content of the blob ‘BLOB’ as an array of
     UNSIGNED-BYTE’s

 -- Common Lisp Generic: (binary-pblob)

      -- Method: (‘binary-p’ (blob BLOB))

     Return T(1) if the contents of the blob is binary.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

8.1 Accessing
=============

Blobs can be accessed usually via TREE objects or directly by
OID.

 -- Common Lisp Method: (get-object (class (eq BLOB)) (id/name
          T(1)) (repository T(2)))

     Return an object of type ‘CLASS’ from the object database.  The
     lookup will use either an oid or a name to find the object.

     See also: get-object.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

8.2 Content
===========

Before we dive into this, we can get the content of the file by
extracting the OID, “6AEF1FC9F802DB1D903200F39E1D776CE355565F” and
lookup this object:

     GIT> (get-object 'blob "6AEF1FC9F802DB1D903200F39E1D776CE355565F"
                      (open-repository (merge-pathnames #p"projects/ecl"
                                                (user-homedir-pathname))))
     #<BLOB 6AEF1FC9F802DB1D903200F39E1D776CE355565F {10068F1493}>

A blob is just raw data, stored as raw bytes.  Basically everything in
the git database is stored as blobs.  So to extract the content we can
do

     GIT> (blob-content
           (get-object 'blob "6AEF1FC9F802DB1D903200F39E1D776CE355565F"
                       (open-repository (merge-pathnames #p"projects/ecl"
                                                         (user-homedir-pathname)))))
     #(35 33 47 98 105 110 47 115 104 10 35 10 35 32 84 104 105 115 32 105 115 32
       106 117 115 116 32 97 32 100 114 105 118 101 114 32 102 111 114 32 99 111 110
       102 105 103 117 114 101 44 32 116 104 101 32 114 101 97 108 32 99 111 110 102
       105 103 117 114 101 32 105 115 32 105 110 32 115 114 99 46 10 35 32 84 104
       105 115 32 115 99 114 105 112 116 32 105 100 101 110 116 105 102 105 101 115
       32 116 104 101 32 109 97 99 104 105 110 101 44 32 97 110 100 32 99 114 ....)

If the content is of a string type then we can print it’s contents.

     GIT> (binary-p
           (get-object 'blob "6AEF1FC9F802DB1D903200F39E1D776CE355565F"
                       (open-repository (merge-pathnames #p"projects/ecl"
                                                         (user-homedir-pathname)))))
     NIL

Since this is a string then we can convert it, flexi-streams(1) has a
convenient mechanism to convent this to a string.

     GIT> (flexi-streams:octets-to-string
           (blob-content
            (get-object 'blob "6AEF1FC9F802DB1D903200F39E1D776CE355565F"
                        (open-repository (merge-pathnames #p"projects/ecl"
                                                          (user-homedir-pathname))))))
     "#!/bin/sh
     #
     # This is just a driver for configure, the real configure is in src.
     # This script identifies the machine, and creates a directory for
     # the installation, where it runs ${srcdir}/configure.
     set -e

     #if uname -a | grep -i 'mingw32' > /dev/null; then
     #  srcdir=`pwd -W`/src;

   ---------- Footnotes ----------

   (1) http://weitz.de/flexi-streams/

9 Index
*******

 -- Common Lisp Class: index

     A git index

9.1 Using
=========

 -- Common Lisp Generic: (open-indexobject)

      -- Method: (‘open-index’ (repository REPOSITORY))

      -- Method: (‘open-index’ (path STRING(1)))

      -- Method: (‘open-index’ (path PATHNAME(2)))

     Returns an index object for ‘OBJECT’ (a repository)

 -- Common Lisp Macro: (with-index (var &optional repository-or-path)
          &body body)

     Load an index from a repository, path or if none is specified then
     an in-memory index is used.  The newly opened index is bound to the
     variable ‘VAR’.

     Parameters:

        * ‘var’ – the symbol the opened index will be bound to.

        * ‘repository-or-path’ – the repository or path to open the
          index from.

        * ‘body’ – the body of the macro.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_string.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_pn.htm

9.1.1 Adding
------------

 -- Common Lisp Generic: (index-add-filepath index)

      -- Method: (‘index-add-file’ (path STRING(1)) (index INDEX))

      -- Method: (‘index-add-file’ (path PATHNAME(2)) (index
               INDEX))

      -- Method: (‘index-add-file’ (entry LIST(3)) (index INDEX))

     Adds the ‘PATH’ to the ‘INDEX’.

     Parameters:

        * ‘path’ – the relative path of a file to be added to the
          repository.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_string.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_pn.htm

   (3) http://www.lispworks.com/reference/HyperSpec/Body/a_list.htm

9.1.2 State
-----------

 -- Common Lisp Generic: (index-conflicts-pindex)

      -- Method: (‘index-conflicts-p’ (index INDEX))

     Return T(1) if the index contains any conflicting

          changes.

These functions assist management of the state of the in memory copy of
the index.

 -- Common Lisp Generic: (index-reloadindex)

      -- Method: (‘index-reload’ (index INDEX))

     Reload the state of the ‘INDEX’ with objects read from disk.

 -- Common Lisp Generic: (index-writeindex)

      -- Method: (‘index-write’ (index INDEX))

     Write the ‘INDEX’ back to the file system.

 -- Common Lisp Method: (entries (object INDEX) &key start
          end)

     Returns the elements of the collection ‘OBJECT’ as a list.  The
     start and end keyword arguments allow to retrieve a subset of all
     elements.  All entries with index satisfying

          START <= INDEX < END

     are returned.  If ‘END’ is not specified or nil, no ‘END’ condition
     exists.  start defaults to 0.

     See also: ‘entries’

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

9.1.3 Clearing
--------------

 -- Common Lisp Generic: (index-clearindex)

      -- Method: (‘index-clear’ (index INDEX))

     Clear contents of the ‘INDEX’ removing all entries.  Changes need
     to be written back to disk to take effect.

9.1.4 Convert to Tree
---------------------

 -- Common Lisp Generic: (index-to-treeindex)

      -- Method: (‘index-to-tree’ (index INDEX))

     Write the current index to a new tree object.

10 Remote
*********

     Warning: This functionally is still under development.  So
     stability of this part of the API is uncertain.

 -- Common Lisp Class: remote

 -- Common Lisp Method: (full-name (object REMOTE))

     The name of the remote.

     See also: full-name.

 -- Common Lisp Method: (short-name (object REMOTE))

     The name of the remote.

     See also: short-name.

 -- Common Lisp Method: (get-object (class (eq REMOTE))
          (id/name T(1)) (repository T(2)))

     Return an object of type ‘CLASS’ from the object database.  The
     lookup will use either an oid or a name to find the object.

     See also: get-object.

 -- Common Lisp Method: (list-objects (class (eq REMOTE))
          (repository T(3)) &key test test-not)

     See also: list-objects.

 -- Common Lisp Generic: (ls-remoteremote)

      -- Method: (‘ls-remote’ (remote REMOTE))

     Lists the current refs at the remote.  Return a list of the refs
     described by ‘NAME’, ‘REMOTE’-OID, ‘LOCAL’-OID and a ‘LOCAL’ bool
     that is true if the ref has a local copy.

 -- Common Lisp Generic: (remote-urlremote)

      -- Method: (‘remote-url’ (remote REMOTE))

     Return the url to the remote.

 -- Common Lisp Generic: (remote-fetch-refspecsremote)

      -- Method: (‘remote-fetch-refspecs’ (remote REMOTE))

     Returns a list of fetch specifications for the remote.

 -- Common Lisp Generic: (remote-push-urlremote)

      -- Method: (‘remote-push-url’ (remote REMOTE))

 -- Common Lisp Generic: (remote-push-refspecsremote)

      -- Method: (‘remote-push-refspecs’ (remote REMOTE))

     Returns a list of push specifications of the remote.

 -- Common Lisp Generic: (remote-pushremote &key refspecs credentials)

      -- Method: (‘remote-push’ (remote REMOTE) &KEY REFSPECS
               CREDENTIALS)

     Perform a push.

 -- Common Lisp Generic: (remote-connectobject &key direction
          credentials)

      -- Method: (‘remote-connect’ (remote REMOTE) &KEY
               (DIRECTION :FETCH) CREDENTIALS)

     Opens the remote connection.  The url used for the connection can
     be queried by GIT-URL.

     The opened connection is one way, either data is retrieved from the
     remote, or data is send to the remote.  The direction is specified
     with the ‘DIRECTION’ argument, ‘:FETCH’ is for retrieving data,
     ‘:PUSH’ is for sending data.

 -- Common Lisp Generic: (remote-connected-premote)

      -- Method: (‘remote-connected-p’ (remote REMOTE))

     Returns t if the connection is open, nil otherwise.

 -- Common Lisp Generic: (remote-disconnectremote)

      -- Method: (‘remote-disconnect’ (remote REMOTE))

     Disconnects an opened connection.

 -- Common Lisp Generic: (remote-downloadremote)

      -- Method: (‘remote-download’ (remote REMOTE))

     Download the required packfile from the remote to bring the
     repository into sync.

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (3) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

11 Config
*********

     Warning: This functionally is still under development.  So
     stability of this part of the API is uncertain.

12 ODB
******

     Warning: This functionally is still under development.  So
     stability of this part of the API is uncertain.

 -- Common Lisp Class: odb

 -- Common Lisp Class: odb-object

 -- Common Lisp Generic: (open-odbpath-or-repository)

      -- Method: (‘open-odb’ (repository REPOSITORY))

     Open the ODB at the specified path or repository.

 -- Common Lisp Method: (list-objects (class (eq :OID)) (repository
          See ODB) &key test test-not)

     See also: list-objects.

 -- Common Lisp Method: (list-objects (class (eq :OID)) (repository
          See REPOSITORY) &key test test-not)

     See also: list-objects.

 -- Common Lisp Method: (get-object (class (eq ODB-OBJECT))
          (id/name T(1)) (repository ODB))

     Return an object of type ‘CLASS’ from the object database.  The
     lookup will use either an oid or a name to find the object.

     See also: get-object.

 -- Common Lisp Method: (get-object (class (eq ODB-OBJECT))
          (id/name T(2)) (repository REPOSITORY))

     Return an object of type ‘CLASS’ from the object database.  The
     lookup will use either an oid or a name to find the object.

     See also: get-object.

 -- Common Lisp Method: (odb-type (object ODB-OBJECT))

     See also: ‘odb-type’

 -- Common Lisp Generic: (odb-dataobject)

      -- Method: (‘odb-data’ (object ODB-OBJECT))

 -- Common Lisp Generic: (odb-sizeobject)

      -- Method: (‘odb-size’ (object ODB-OBJECT))

   ---------- Footnotes ----------

   (1) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

   (2) http://www.lispworks.com/reference/HyperSpec/Body/a_t.htm

13 Internals
************

13.1 Libgit2
============

 -- Common Lisp Function: (libgit2-featuresn i l)

     Return a list of the libgit2 capabilities, possible values in the
     list return values are ‘:THREADS’ and ‘:HTTPS’.

 -- Common Lisp Function: (libgit2-versionn i l)

     Returns the libgit2 C-library version number as a list of three
     integers, (major minor revision).

13.2 Memory Management
======================

Because C has manual memory management and Lisp automatic memory
management there is the question on how these two systems integrate.

First most libgit2 objects need to be freeed.  There are different free
calls in libgit2, but in CL-git they are all replaced by git-free.

Second of all, this call is made optional.  The package
‘trivial-garbage’ takes care of freeing the object when the garbage
collector collects the Lisp git object wrappers.

So normally you do not have to call the free explicitly.  However there
are a few reasons you might want to do it anyway:

   * Having a repository and commit objects open has the side effect
     that file descriptors to the underlying git files stay open.  When
     you iterate over may commits manually (not using the convenience
     macros) can trigger the Lisp process to run out of available file
     handles.

   * Some libgit2 calls can potentially allocate lots of memory.
     Because the Lisp garbage collector does not see the memory
     allocated by the libgit2 library, it helps to call the git-free
     call to avoid usage build up.

 -- Common Lisp Generic: (freeobject)

      -- Method: (‘free’ (object CL-GIT::GIT-POINTER))

     TODO

Object that have been freed have ‘(disposed)’ in their title when
printed.

13.2.1 Lazy Loading
-------------------

Some types like references are lazy loaded when possible.  This can be
seen when they are printed.

     GIT> (list-objects 'reference  (open-repository #p"/home/russell/projects/ecl/"))
     (...
     #<REFERENCE refs/tags/ECL.0.9f (weak) {100657CCB3}>
     ...)

The ‘(weak)’ identifier shows that this object hasn’t been looked up in
the odb yet.

13.2.2 Dependant Objects
------------------------

Some objects, such as commits, are only valid as long as another object
is valid, like a repository.  This means that as soon as a repository is
git-free’ed the commit becomes invalid.  Also conversely, as long as we
keep a reference to a commit and we expect that one to be valid, the
repository can not be collected.  We call the commit the depend object
and the repository the facilitating object.

These dependencies are handled in CL-git in the following way:

   * When a facilitating object is explicitly freed, or when a
     convenience macro such as with-repository frees the object because
     the execution path leaves scope, all dependend objects on that
     facilitating object are freed.

   * Any depenend object holds a reference to its facilitator as long as
     it is not freed.

The consequences are that the following is not correct

     (with-repository (..)
        (object-get ...))

Because the returned object from the lookup call is not valid anymore
because the repository is closed.

However the following, although uncertain when the repository is closed,
is correct

     (object-get ... (repository-open ...))

14 Changelog
************

14.1 2.0.0 - 2023-01-05
=======================

14.1.1 Features
---------------

   * add support for libgit2 0.27, 0.28, 1.0, 1.1, 1.2, 1.4, 1.5

   * add REACHABLE-FROM API for inspecting the graph.

   * add MESSAGE-TRAILERS API for parsing commit message trailers.

   * unify the git tag creation API

   * pass credentials through to remote-push

   * expose libgit2 init functions

   * add git checkout method

   * add branch make-object method

14.1.2 Minor Fixes
------------------

   * force a GC after tests

   * convert some types to size-t

   * translate to foreign type

   * proxy options translation

   * update more structs to support libgit 1.3.0

   * move remote callbacks to fetch remotes

   * load cffi before building docs

   * update remote callbacks location

   * bug where missing USER or USERNAME would error

   * backwards compatible support for libgit2

   * only implemented in some versions of libgit2

   * expose missing error symbols

   * make the get-object return a commit if looking for a commit

   * remove duplicate git-dif-options-version constant

   * rename COMMIT to TARGET

   * FETCH-OPTIONS struct is now freed

   * disable follow redirects for old versions

   * bug in definition of checkout generic

14.1.3 Documentation
--------------------

   * produce all formats and update urls

   * make documentation building more portable

   * add documentation for reference logs

   * exposed documentation or the git index entries method

14.2 1.3.0 - 2022-07-03
=======================

   * updated to work with libgit2 1.3.0

14.3 0.20.0 - 2014-06-18
========================

   * updated to work with libgit2 0.20.0.

   * re-factored some of the internals to work better with CFFI.

   * updated for asdf 3

   * updated and improved diff interface

14.4 0.19.0 - 2013-10-23
========================

   * added initial diff interface

   * added more CFFI like translations to string lists

   * added groveling for some platform specific datatypes

14.5 0.18.1 - 2013-07-02
========================

   * get-tree has been renamed to commit-tree

   * re-factored index functionality

   * documentation improvements

   * now exporting of error symbols.

   * removed with-revisions

   * updated revision-walker, it now uses commit objects not direct
     oids.  It also uses conditions handling instead of return values to
     stop iteration.

14.6 0.18.0 - 2013-06-13
========================

   * Changed numbering to match libgit2.

   * support for multiple start revisions when doing revision walk
     [Willem]

   * Git blob interface [Willem]

   * Conversion to new CFFI struct interface [Willem]

   * Signature translation to native types [Willem]

   * New Tree API using a mixin [Russell]

   * Implementation of remotes [Willem]

   * OID Translation to native types [Willem]

   * initial implementation of narrative documentation [Willem]

   * Complete re-factoring of public API, changes since 0.1 Removed
     symbols:

        - ‘git-repository’

        - ‘git-repository-index’

        - git-repository-init

        - git-repository-open

        - git-repository-free

     Renamed Symbols:

        - git-commit-create -> make-commit

        - git-commit-author -> commit-author

        - git-commit-message -> commit-message

        - git-commit-committer -> commit-committer

        - git-commit-create -> commit-create

        - git-commit-create -> commit-create

        - with-git-repository-index -> with-repository-index

        - ensure-git-repository-exist -> ensure-repository-exist

        - with-git-repository -> with-repository

     Most other changes involved removing git- prefixes from symbols.

14.7 0.1 - 2012-01-20
=====================

   * basic support for the libgit2 features like creating a new
     repository and listing it’s commit history [Russell]

15 Contributing
***************

15.1 Testing
============

CL-Git uses FiveAM(1) as the testing harness and inferior shell(2) to
call lsof(3) to check for file descriptor leaks.

follow the Roswell install documentation(4).

install lsof:

     apt install lsof

install SBCL and run tests.:

     ros install sbcl

     ./run-tests.lisp

   ---------- Footnotes ----------

   (1) http://common-lisp.net/project/fiveam/

   (2) http://www.cliki.net/inferior-shell/

   (3) https://github.com/lsof-org/lsof

   (4) https://roswell.github.io/Installation.html

15.1.1 CI Builds
----------------

CI builds are done with Earthly(1) it bulids and tests using buildkit
(either docker or podman containers), once it is installed, you can list
the build targets like this:

     % earthly ls
     +base
     +build
     +deps
     +libgit2
     +test-libgit2-0.27-sbcl
     +test-libgit2-0.28-sbcl
     +test-libgit2-1.0-sbcl
     +test-libgit2-1.1-sbcl
     +test-libgit2-1.2-sbcl
     +test-libgit2-1.3-sbcl
     +test-libgit2-1.4-sbcl
     +test-libgit2-1.5-ccl
     +test-libgit2-1.5-clasp
     +test-libgit2-1.5-ecl
     +test-libgit2-1.5-sbcl
     +test-libgit2-ccl
     +test-libgit2-clasp
     +test-libgit2-ecl
     +test-libgit2-sbcl

All the targets with the format ‘test-libgit2-<version>-<lisp>’ can be
executed to test that version combination.

To run a build you would use a command like:

     earthly +test-libgit2-1.5-sbcl

Currently SBCL is the only working Lisp, but others are there in case we
want to extend our support to them.

   ---------- Footnotes ----------

   (1) https://earthly.dev/get-earthly

15.2 Documentation
==================

To build the documentation you need sphinxcontrib.cldomain which depends
on:

   * Sphinx

   * sphinxcontrib.cldomain(1) latest pypi(2)

   * >>‘pygments-cl-repl‘_<< latest pypi(3)

   * roswell(4) 3.21.7 git(5)

   * Quicklisp(6)

build documentation:

     ./doc/build.sh

The compiled documentation is output into ‘doc/build/html’.

   ---------- Footnotes ----------

   (1) http://cldomain.russellsim.org/

   (2) https://pypi.python.org/pypi/sphinxcontrib-cldomain

   (3) https://pypi.python.org/pypi/pygments-cl-repl

   (4) https://roswell.github.io/

   (5) https://github.com/roswell/roswell

   (6) http://www.quicklisp.org/beta/

Indices and tables
******************

   * genindex

   * search