git-issue 0.5.0

Git-native issue tracker
# git-issue 🗂️

A Git-native, file-backed issue tracker.

Issues live alongside your code inside `.gitissues/`, making them platform-independent, version-controlled, branchable, mergeable, reviewable and offline-friendly.

## 1.) Features

- ✅ Git-native, file-backed issues under `.gitissues/`
- ✅ Core commands: `init`, `new`, `list`, `show`, `set`, `edit`, `link`
- ✅ Each issue has a markdown description incl. attachments
- ✅ Each issue has metadata: `id`, `title`, `state`, `type`, `labels`, `reporter`, `assignee`, `priority`, `due_date`, `created`, `updated`
- ✅ Each issue has `relationships`: Desired relationship categories (e.g, related, child/parent, ...) are configurable and bidirectional links can be managed automatically
- ✅ Issues can be filtered and sorted
- ✅ Highly configurable: default columns for `list`, available options for `state` and `type`, relation ship categories, commit message template, external editor
- ✅ External editor renders issue information as markdown
- ✅ Git-integration: auto-commit of changes
- ✅ Possibility to export issue list into CSV file
- ✅ Automated integration tests
- 🚧 Add `search` command across all issue titles and descriptions
- 🚧 Comments / discussions

## 2.) Usage

### 2.1) Installation

Different installation approaches are explained here.

#### 2.1.1) GitHub Release

Download the latest release from GitHub and put the binary on your PATH.

1) Go to the Releases page and download the binary for your platform:
   - `git-issue-linux-x86_64`
   - `git-issue-macos-x86_64` or `git-issue-macos-aarch64`
   - `git-issue-windows-x86_64.exe`
2) Rename to the canonical name and place on your PATH
   - Linux/macOS:
     ```bash
     mv git-issue-<your-platform> git-issue
     chmod +x git-issue
     sudo mv git-issue /usr/local/bin/
     ```
   - Windows: rename `git-issue-windows-x86_64.exe` to `git-issue.exe` and move it to a directory on your PATH.
3) Verify:
   ```bash
   git issue -h
   ```

#### 2.1.2) Cargo

Installation with cargo works as follows:

```
cargo install --git https://github.com/timonburkard/git-issue
```

#### 2.1.3) Crates

Package is available on https://crates.io/crates/git-issue, so it can be installed as follows:

```
cargo install git-issue
```

### 2.2) How To

Lets image this is the structure of your git repo, for which you want to add issue tracking:

```
.git/
src/
README.md
.gitignore
```

In the root of your repo, run:

```bash
git issue init
```

This will automatically create the `.gitissues/` directory in your git repo:

```
.git/
.gitissues/
src/
README.md
.gitignore
```

For infos about the `.gitissues/` directory structure, see chapter [4.) Storage Layout](#4-storage-layout).

#### 2.3) Gitignore

This is the suggested content for the `.gitignore`:

```
.gitissues/.tmp/
.gitissues/exports/
.gitissues/settings.yaml
```

### 2.3) Commands

```bash
# Help page
git issue -h

# Version
git issue -V
git issue --version

# Initialize tracking in your repo
git issue init
git issue init --no-commit

# Create a new issue
git issue new "Login redirection problem"
git issue new "Login redirection problem" --type bug --labels software,ui --reporter alice --assignee bob --priority P1 --due-date 2026-02-15
git issue new "Login redirection problem" --reporter me --assignee me  # 'me' is automatically replaced with `settings.yaml:user`

# List issues
git issue list
git issue list --columns id,assignee,title
git issue list --columns "*"
git issue list --filter priority=p2 title=*driver*
git issue list --sort assignee=asc priority=desc
git issue list --csv

# Show all issue information (markdown) -- launches external text editor
git issue show 1234

# Change issue meta fields
git issue set 1234 --title "LCD driver has a problem"
git issue set 1234 --state resolved --type bug --reporter alice --assignee bob --priority P1 --due-date 2026-01-31
git issue set 1234 --reporter me --assignee me  # 'me' is automatically replaced with `settings.yaml:user`

# Change issue meta fields: labels
git issue set 1234 --labels cli,driver         # set labels (overwrite)
git issue set 1234 --labels-add cli,driver     # add labels
git issue set 1234 --labels-remove cli,driver  # remove labels

# Change issue relationships
git issue link 1234 --add related=5678                                       # add relationship link
git issue link 1234 --remove related=5678                                    # remove relationship links
git issue link 1234 --add related=5678,3333 parent=9999 --remove child=7777  # batch update relationship links

# Edit issue description (markdown) -- launches external text editor
git issue edit 1234
```

### 2.4) Example

Dummy example project to see how `git-issue` is used in a repo: [Example Project](https://github.com/timonburkard/example-project)

## 3.) Configuration

After running `git issue init`, the following default files are automatically created:

 - `.gitissues/config.yaml`:    Project configuration file (should be version-controlled)
 - `.gitissues/settings.yaml`:  Local user settings file (should **not** be version-controlled)
 - `.gitissues/users.yaml`:     Users (should be version-controlled)
 - `.gitissues/description.md`: Issue description template (should be version-controlled)

These files can be edited by the user.

### 3.1) config.yaml

This file holds the project configuration. It should be version-controlled.

```yaml
# Automatically create a git commit after mutating commands
commit_auto: true

# Commit message template
# Available placeholders: {action}, {id}, {title}
commit_message: "[issue] {action} #{id} -- {title}"

# Default columns to display in `issue list`
# ["*"] can be used to include all available columns
list_columns:
  - id
  - state
  - assignee
  - title

# Available issue states
# First state in the list is the initial state for new issues
states:
  - new
  - active
  - closed
  - deleted

# Available issue types
# Per default the type is empty for new issues
types:
  - bug
  - feature
  - task

# Available relationships between issues
# link: specifies the name of the reciprocal relationship
#  - same name:      bidirectional, symmetric
#  - different name: bidirectional, asymmetric
#  - null:           unidirectional
relationships:
  related:
    link: related
  parent:
    link: child
  child:
    link: parent

# Separator used when exporting to CSV
export_csv_separator: ','
```

#### 3.1.1) Options

- `commit_auto` (boolean): If `true`, automatically commit changes to `.gitissues/`. Default: `true`
- `commit_message` (string): Template for git commit messages. Supports placeholders:
  - `{id}`: Issue ID
  - `{title}`: Issue title
  - `{action}`: Command that triggered the commit (`new`, `edit description`, `set <field>`)
- `list_columns` (list of strings): Default columns shown in `list` command
- `states` (list of strings): Available issue states. Default is the first element.
- `types` (list of strings): Available issue types. Default is empty.
- `relationships` (object): Available relationships between issues
- `export_csv_separator` (char): Separator for CSV file exports

### 3.2) users.yaml

This file holds the available users in the project. It should be version-controlled.

```yaml
users:
  - id: alice
  - id: bob
  - id: carol
```

### 3.3) settings.yaml

This file holds the local user settings. It should **not** be version-controlled.

```yaml
# Editor to edit/show issue descriptions
# git = use the git-configured editor
editor: git

# User name
# Used as default reporter for new issues
user: alice
```

#### 3.3.1) Options

- `editor` (string): External text editor (set `git` to use configured git core.editor)
- `user` (string): User name, used per default as reporter for new issues (can be '')

### 3.4) description.md

This file holds the template for the issue descriptions. It is use when a new issue is created with `git issue new`.

```md
# Description

# Repro Steps

# Expected Behavior

# System Info

```

## 4.) Storage Layout

This is the directory structure of `.gitissues/`:

```
.gitissues/
├── .tmp/           # Temporary files (put in `.gitignore`)
├── config.yaml     # Project configuration
├── description.md  # Description template
├── users.yaml      # Available users
├── settings.yaml   # Local user settings (put in `.gitignore`)
├── exports/        # Location of CSV exports (put in `.gitignore`)
└── issues/
    └── 0000000001/
        ├── meta.yaml       # Structured metadata
        ├── description.md  # Markdown description
        └── attachments/    # Attachments of markdown description
    ├── 0000000002/
        ├── meta.yaml       # Structured metadata
        ├── description.md  # Markdown description
        └── attachments/    # Attachments of markdown description
    └── ...
```

### 4.1) meta.yaml Format

```yaml
id: 1234                       # (Integer) Identifier
title: Login screen is broken  # (String) Title
state: new                     # (String) E.g.: new, active, resolved, junked
type: bug                      # (String) E.g.: feature, bug, task
labels:                        # (List of Strings) Labels / tags
  - software
  - ui
reporter: t.burkard            # (String) Who reported the issue
assignee: j.doe                # (String) To whom the issue is assigned
priority: P2                   # (Enum) Priority: P0 = highest, P2 = default, P4 = lowest
due_date: 2026-01-31           # (Date) Due date in ISO format: YYYY-MM-DD
relationships:                 # (Object) Relationships with other issues
  related:
    - 5678
    - 7777
  parent:
    - 5555
  child:
    - 3333
    - 4444
created: 2025-11-13T15:54:52Z  # (Timestamp) Issue was created at
updated: 2025-12-22T20:36:11Z  # (Timestamp) Issue was last updated at
```

Don't edit these files manually. Instead use the `git issue set` and `git issue link` commands.

## 5.) Development

### 5.1) Building & Testing

```bash
# Build
cargo build

# Format code
cargo fmt

# Lint
cargo clippy

# Run tests
cargo test
```

### 5.2) Architecture

- `config/`
  - `config-default.yaml`    -- Default configuration, copy-pasted at `git issue init` to `.gitissues/`
  - `description-default.md` -- Default description template, copy-pasted at `git issue init` to `.gitissues/`
  - `users-default.yaml`     -- Default users, copy-pasted at `git issue init` to `.gitissues/`
  - `settings-default.yaml`  -- Default local user settings, copy-pasted at `git issue init` to `.gitissues/`
- `src/`
  - `main.rs`  -- CLI parsing with clap
  - `model.rs` -- Shared data types, functions and utilities
  - `edit.rs`  -- Edit issue description (markdown) with external text editor
  - `init.rs`  -- Initialize `.gitissues/` directory and copy default config
  - `link.rs`  -- Change relationships between issues
  - `list.rs`  -- List all issues
  - `new.rs`   -- Create new issues
  - `set.rs`   -- Change issue meta fields
  - `show.rs`  -- Show all issue information
- `tests/`     -- Automated tests

### 5.3) Dependencies

- `clap`        -- CLI argument parsing
- `chrono`      -- Timestamp generation
- `serde`       -- Serialization framework
- `serde_yaml`  -- YAML parsing for meta.yaml files
- `shell-words` -- Process command line according to parsing rules of Unix shell
- `regex`       -- Regular expressions
- `indexmap`    -- Provides IndexMap datatype