Skip to content

A Common Lisp implementation of parsers for the git object file formats

License

Notifications You must be signed in to change notification settings

fiddlerwoaroof/cl-git

Repository files navigation

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):

docker run \
  -v $PWD/docker-run:/code fiddlerwoaroof/sbcl-static:latest \
  --load /code/main.lisp

Installation

% 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)

Example usage

Get the commit id of the default branch for a specific repository:

(co.fwoar.git:with-repository (".")
  ;; the argument to branch defaults to "master" or "main"
  (co.fwoar.git:branch))
#<LOOSE-REF ba6fdb of #<GIT-REPOSITORY {70161A1853}> {70161A2893}>

Show the commit message

(co.fwoar.git:in-repository ".")
(co.fwoar.git:component :message (co.fwoar.git:branch "main"))
feat: don't assume that the default branch is \"master\"

Show the messages of the commit’s parent

(co.fwoar.git:in-repository ".")
(let* ((branch (co.fwoar.git:branch "main"))
       (parents (co.fwoar.git:parents branch)))
  (mapcar (lambda (it)
            (co.fwoar.git:component :message it))
          parents))
("feat: handle bare repositories
")

Show the files in a commit

(co.fwoar.git:in-repository ".")
(list* '("Name" "Mode" "Hash")
       'hline
       (co.fwoar.git:git (branch "main")
                         (component :tree :entries)
                         (map (juxt (component :name)
                                    (component :mode)
                                    (component :hash)))))
NameModeHash
.github40000beabf775f686fb2608a580b4d58dd589cf160354
.gitignore1006448a9fe9f77149f74fed5c05388be8e5ffd4a31678
.projectile100644e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
LICENSE1006440306819e780fa57dc3bf6b99a0a059670b605ae0
README.org100644f25aa710e8c3053f4a6618728702e41c68eb52c5
branch.lisp100644d82ad3bdbae4af13b5a703bf350dd2bb2c9dadd0
co.fwoar.cl-git.asd100644560a0f63f48161e2ba787ed42332515de7f86f14
commit.lisp1006446ff88d884da171adf49ed022decd537a5964e41c
delta.lisp1006441014147a1946752542c1ea7dd9700cb047055047
docker-run400004703dc01430d67c5d60f00ad412fddfa22f60764
docs400009fe62496fc4ab6debd3c5e1b26f844b5566c36d5
extract.lisp1006444fc2d479ff5c37fc52a51a2cf884e5226fb3b14d
git.lisp100644bccecfd98285f2ab98a277a3284bd98b3dd363bf
graph.lisp10064425596749c5bf5ee2d5a76b355821f57010beb31a
model.lisp100644ade5096654ea6ff352354d381784a5d9dda0a3e7
pack.lisp10064416b02b061756f59d615b5f1f7f473789ad86b676
package.lisp100644f8bd75abedd62bd51155ebd1727b5b9476d02c57
porcelain.lisp1006443f044e12ae9fc5a98a5c84f2f54e6892ae42216a
protocol.lisp10064484a10444b7bce2b844128917cdfc79fa4df6377b
ref.lisp100644b508a5546a0bc0b7189a8cf8cebb33a967f3ffb2
repository.lisp1006444e64262b40bcd0e239276a73426d0d1ac9d0772c
tests40000df1addf5dae76e35e84e6ded6fee14cda501f119
tree.lisp100644c798b0c4d0b5f552548bac98f44b5b5c19334e66
types.lisp1006443f53e0f33ee260a962b97ef26de1d66b32a12a15
undelta.lisp100644ae0a070133d1a14d6e940a0f790f40b37e885b22
util.lisp1006445374d96e5e29d836a427c40999e0f9c88fb1587a

Show the files that match a pattern

(co.fwoar.git:with-repository (".")
  (let* ((branch (co.fwoar.git:branch "main"))
         (tree (co.fwoar.git:tree branch))
         (tree-entries (co.fwoar.git:filter-tree "^.....?[.]lisp" tree)))
    (flet ((component (component)
             (lambda (it)
               (co.fwoar.git:component component it))))
      (list* '("Name" "Mode" "Hash")
             'hline
             (mapcar (data-lens:juxt (component :name)
                                     (component :mode)
                                     (component :hash))
                     tree-entries)))))
NameModeHash
delta.lisp1006441014147a1946752542c1ea7dd9700cb047055047
graph.lisp10064425596749c5bf5ee2d5a76b355821f57010beb31a
model.lisp100644ade5096654ea6ff352354d381784a5d9dda0a3e7
pack.lisp10064416b02b061756f59d615b5f1f7f473789ad86b676
tree.lisp100644c798b0c4d0b5f552548bac98f44b5b5c19334e66
types.lisp1006443f53e0f33ee260a962b97ef26de1d66b32a12a15
util.lisp1006445374d96e5e29d836a427c40999e0f9c88fb1587a

Partially Implemented:

Delta refs

Git uses a 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 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:

mkdir tmp
mv .git/objects/pack/* tmp
for pack in tmp/*.pack; do
  git unpack-objects < "$pack";
done

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

git repack --window=0

git:git porcelain

I have some thoughts abound a (git:git ...) form that can be used as a lQuery-like DSL for manipulating git repositories, and this is partially implemented in porcelain.lisp, but the details need more thought before it is ready.

TODOs

start implementing Pharo-like git integration (read-only first, commits later)

(mapcar (lambda (it)
          (if (equal it 'HLINE)
              'hline
            it))
        data)

About

A Common Lisp implementation of parsers for the git object file formats

Topics

Resources

License

Stars

Watchers

Forks