git.fiddlerwoaroof.com
Raw Blame History
* CL-GIT: the pure lisp interface to Git objects
** Introduction

   Git libraries for Common Lisp common in a couple forms. Some attempt
   to wrap the libgit2 git library
   (e.g. https://github.com/russell/cl-git).  Others wrap the git binary
   in a subprocess (e.g. http://shinmera.github.io/legit/).  Such
   libraries work well in cases where you control the environment but
   not all lisp programs run in such circumstances.  This library, on the
   contrary, attempts to implement parsers for git's file formats as well
   as a thin "porcelain" interface for manipulating git objects.

** Contributing

  This project uses (loosely) conventional-commits: https://www.conventionalcommits.org/en/v1.0.0/

  Also, some use of https://github.com/fiddlerwoaroof/git-issue has been made

  To run the tests in a clean environment, you can do (this will eventually be a Github Action):

  #+BEGIN_SRC sh
    docker run \
      -v $PWD/docker-run:/code fiddlerwoaroof/sbcl-static:latest \
      --load /code/main.lisp
  #+END_SRC

** Installation

   #+BEGIN_SRC sh
     % git clone https://github.com/fiddlerwoaroof/fwoar.lisputils.git "$HOME/quicklisp/local-projects/fwoar-lisputils"
     % git clone https://github.com/fiddlerwoaroof/cl-git.git "$HOME/quicklisp/local-projects/cl-git"
     % sbcl --load "$HOME/quicklisp/setup.lisp"
     CL-USER> (ql:quickload :cl-git)
   #+END_SRC

** Example usage

*** Get the commit id of the master branch for a specific repository:

    #+BEGIN_SRC lisp :exports both :results verbatim
      (git:in-repository "~/quicklisp/local-projects/cl-git")
      (git:git (branch "master")) ;; the argument to branch defaults to "master"
    #+END_SRC

    #+RESULTS:
    : #<fwoar.cl-git::loose-ref 1869d7e of ~/git_repos/cl-git/>


*** Show the commit message

    #+BEGIN_SRC lisp :exports both :results verbatim
      (git:in-repository "~/quicklisp/local-projects/cl-git")
      (git:git (branch "master") ;; the argument to branch defaults to "master"
               (component :message))
    #+END_SRC

    #+RESULTS:
    : bug: fix filter-tree

*** Show the messages of the commit's parent

    #+BEGIN_SRC lisp :exports both :results verbatim
      (git:in-repository "~/quicklisp/local-projects/cl-git")
      (git:git (branch "master") ;; the argument to branch defaults to "master"
               (commit-parents)
               (map (component :message)))
    #+END_SRC

    #+RESULTS:
    : ("feat: resolve strings as refs in first argument to GIT:GIT
    : ")

*** Show the files in a commit
    - Note taken on [2020-11-15 Sun 01:49] \\
      If the table comes out wrong, =*print-case*= must be =:downcase=

    #+BEGIN_SRC lisp :exports both :results table :hlines yes
      (git:in-repository "~/quicklisp/local-projects/cl-git")
      (list* #("Name" "Mode" "Hash")
             'hline
             (git:git (branch "master")
                      (component :tree :entries)
                      (map (juxt (component :name)
                                 (component :mode)
                                 (component :hash)))))
    #+END_SRC

    #+RESULTS:
    | Name            |   Mode | Hash                                     |
    |-----------------+--------+------------------------------------------|
    | .gitignore      | 100644 | 8a9fe9f77149f74fed5c05388be8e5ffd4a31678 |
    | .projectile     | 100644 | e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 |
    | LICENSE         | 100644 | 0306819e780fa57dc3bf6b99a0a059670b605ae0 |
    | README.org      | 100644 | 06173630a1337132bf87a68bb1276100e4ea89b6 |
    | branch.lisp     | 100644 | e06b66967fa4fa005ccf00dcbc7d839b22259593 |
    | cl-git.asd      | 100644 | b17701de06b3d67f4edd556a5b704485cbc830c0 |
    | commit.lisp     | 100644 | 197e10755343900cfbcb7fc6d863d4b3231e74d4 |
    | delta.lisp      | 100644 | 995d5a4fb90f02caeda47c01a2b3427828d2be0e |
    | extract.lisp    | 100644 | 4707eca4ee0c70520ccdc57c0e831187b21271e7 |
    | git.lisp        | 100644 | c516dfc248544509c3ae58e3a8c2ab81c225aa9c |
    | graph.lisp      | 100644 | 31576396aff0fff28f69e0ef84571c0dc8cc43ec |
    | model.lisp      | 100644 | aa372879f4feeb170bc6d06047bf50f55a23042e |
    | package.lisp    | 100644 | 65b2d0c35ea59f3d3cb88161402fd7e3de9798e4 |
    | porcelain.lisp  | 100644 | eb040e54b6113931cac47b7ac1f828f0357dd846 |
    | protocol.lisp   | 100644 | 7e24a6a7a4349497fce06830fa132e9a8ef6fd06 |
    | repository.lisp | 100644 | 3eded300aa984e9ad2eb066e5ca4f78fe83e4137 |
    | tree.lisp       | 100644 | 06bceb0a932817adedc9192edd6f9d4077277624 |
    | undelta.lisp    | 100644 | ae0a070133d1a14d6e940a0f790f40b37e885b22 |
    | util.lisp       | 100644 | 66279b2fa08c9d0872e888b85fe14d9950e27326 |

*** Show the files that match a pattern
    - Note taken on [2020-11-15 Sun 01:49] \\
      If the table comes out wrong, =*print-case*= must be =:downcase=

    #+BEGIN_SRC lisp :exports both :results table :hlines yes
      (git:with-repository ("~/quicklisp/local-projects/cl-git/")
        (list* '("Name" "Mode" "Hash")
               'hline
               (git:git (branch "master")
                        (tree)
                        (filter-tree "^.....?[.]lisp")
                        (map (juxt (component :name)
                                   (component :mode)
                                   (component :hash))))))
    #+END_SRC

    #+RESULTS:
    | Name       |   Mode | Hash                                     |
    |------------+--------+------------------------------------------|
    | delta.lisp | 100644 | 995d5a4fb90f02caeda47c01a2b3427828d2be0e |
    | graph.lisp | 100644 | 31576396aff0fff28f69e0ef84571c0dc8cc43ec |
    | model.lisp | 100644 | aa372879f4feeb170bc6d06047bf50f55a23042e |
    | tree.lisp  | 100644 | 06bceb0a932817adedc9192edd6f9d4077277624 |
    | util.lisp  | 100644 | 66279b2fa08c9d0872e888b85fe14d9950e27326 |

** Partially Implemented:

*** Delta refs
    Git uses a [[https://git-scm.com/docs/pack-format#_deltified_representation][delta calculation]] routine to compress some of the blobs
    in a pack file. This delta stores a reference to a base object and
    a sequence of commands for transforming the base object into the
    new object. My plan to support this is to first just extract the
    commands from the pack file and store them as a [[file:delta.lisp::(defclass delta () ((%repository :initarg :repository :reader repository) (%base :initarg :base :reader base) (%commands :initarg :commands :reader commands)))][delta object]]. When
    this works adequately, I'll write an interpreter to do the actual
    merge.

    A workaround for the moment is to manually unpack the pack files:

    #+BEGIN_SRC sh
      mkdir tmp
      mv .git/objects/pack/* tmp
      git unpack-obj < tmp/*.pack
    #+END_SRC

    Or, you can undeltify the packs by, first unpacking the packfile as above and then doing:

    #+BEGIN_SRC sh
      git repack --window=0
    #+END_SRC