git-case is a bug tracker that lives inside a git repo.

The working prototype is here:

Some commands are slow, but we intended to port those to C and link against git object files, much the way that cgit works.

The important design consideration to recognize is that in GIT, everything is content-addressable. The tree structure appears to have much duplicate information, but they are just different paths to the same content. The git tree objects index to our content.

And information in the ticket is purposely kept in focussed, single-purpose files (inside trees if the information is list-like) so that merging case updates (it is distrubuted afterall) can only conflict on direct conflicting changes (both sides change the state differently, etc).

The cases branch is never checked out, instead the git-case commands operate on the raw branch using a private index so to not clobber any work the user is doing.

The commands for git case are:

  • git-case-active
  • git-case-assign
  • git-case-comment
  • git-case-edit-description
  • git-case-field
  • git-case-ids
  • git-case-list
  • git-case-mark
  • git-case-merge
  • git-case-new
  • git-case-pull
  • git-case-show
  • git-case-state
  • git-case-type

Here is some data that we store:

$ git case list
   0dc37c  [closed] [bug]       implement git-case-merge
   16e8cf  [new] [feature]      implement git-case-import
   330f3b  [new] [feature]      implement perl skeleton
   3ed4c7  [closed] [bug]       load git-case-common from the location of the exec
   5a3624  [closed] [feature]   git-case-show should display IDs
   637685  [new] [feature]      implement git-case-grep
   77d673  [closed] [feature]   improve comment storage
** a31696  [new] [feature]      implement git-case-pull
   a33f60  [closed] [feature]   Implement test harness framework
   c8005e  [new] [feature]      implement git-case-export
   e28a19  [new] [feature]      implement threaded comment display for git-case-sh
   ee5fd5  [new] [feature]      figure out how to automate merging origin/cases to

$ git case show a31696
Case ID:     a31696 (a316966a3b3db85914e647b8a77b6f30441885d1)
Description: implement git-case-pull
Created on:  Mon Apr 14 23:33:25 EDT 2008
Type:        feature
State:       new
Assigned to: Bart Trojanowski <>
Found in:    dbde1f9... git-case-merge will create a cases branch if one is not present

Here is what the data store looks like for a case...

$ git ls-tree -r cases -- 5a3624c08f8606c87107aa1828f1c81cf0aaf453
100644 blob 8b137891791fe96927ad78e64b0aad7bded08bdc    5a3624c08f8606c87107aa1828f1c81cf0aaf453/assigned
100644 blob 6c47757eeed911f92ef168c37b14fee52b4e4f89    5a3624c08f8606c87107aa1828f1c81cf0aaf453/comments/6c47757eeed911f92ef168c37b14fee52b4e4f89
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391    5a3624c08f8606c87107aa1828f1c81cf0aaf453/comments/by-message-id/
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391    5a3624c08f8606c87107aa1828f1c81cf0aaf453/comments/by-timestamp/1208739405/6c47757eeed911f92ef168c37b14fee52b4e4f89
100644 blob f7993ad6433cdebb5b8bd680dd2be43644509112    5a3624c08f8606c87107aa1828f1c81cf0aaf453/created
100644 blob 54257dd4dc02b3d053118206ed17424d86396cf1    5a3624c08f8606c87107aa1828f1c81cf0aaf453/description
100644 blob 0ca855d6e79d399d2853d1536b9a5e8d90d218ab    5a3624c08f8606c87107aa1828f1c81cf0aaf453/found
100644 blob 67be85f1274474029aad8a75b823592324305aa4    5a3624c08f8606c87107aa1828f1c81cf0aaf453/ids/5a5506c0bb8f6e84d8171548b87213a412d76fb6
100644 blob 12799ccbe7ce445b11b7bd4833bcc2c2ce1b48b7    5a3624c08f8606c87107aa1828f1c81cf0aaf453/ids/96384b4eaed5e2673f2a2b8629c81ad7f42ddebc
100644 blob 1ac208286a54bf10746bac5466010b15663a0a6e    5a3624c08f8606c87107aa1828f1c81cf0aaf453/state
100644 blob a7453f07505c42ea8d6fdda75fa91710c81c53d6    5a3624c08f8606c87107aa1828f1c81cf0aaf453/type

== Repository layout ==

<id>/               # directory per case
|-- description     # 1st line title, then free form description
|-- type            # bug/feature/question/...
|-- found           # git commit worktree was in when case created RO
|-- state           # new/open/invalid/etc
|-- assigned        # name <email>
|-- marks/          # list of marks - tags in most tracker talk
|   `-- <name>      # empty file
|-- comments/       # comments, one per file
|   `-- <sha1>      # contains arbitrary text
|-- files/          # attachements to the case/comment
|   `-- <filename>/ # the name of the dir is actually the name of the file
|       `-- <sha1>  # hash of the file, contais the file
|-- ids/            # commits for which the state of thsi bug is known
|   `-- <sha1>      # file contains either 'good' or 'bad'
`-- fields/         # additional field
    `-- <name>      # contains one line of text


  • can be referenced by comments (in the text)
  • same filename can be used from multiple attachments, but could actually be a different sha1
  • file contents can be obtained with git plumbing, or by following files// because the is the same that is computed by git