Skip to main content
The Git backend implements sophisticated data processing pipelines that transform raw git data into frontend-ready structures for transparency visualization.

Data Processing Pipelines

Status Processing

+===============================================================================+
|                                                                               |
|  STATUS PROCESSING PIPELINE                                                   |
|                                                                               |
+===============================================================================+
|                                                                               |
|  INPUT: path (repository path)                                                |
|                                                                               |
|  Step 1: Repository::open(path)                                               |
|       |                                                                       |
|       v                                                                       |
|  +-------------------------------------------------------------------------+  |
|  | Step 2: Configure StatusOptions                                         |  |
|  +-------------------------------------------------------------------------+  |
|  |   opts.include_untracked(true)                                          |  |
|  |   opts.recurse_untracked_dirs(true)                                     |  |
|  |   opts.include_ignored(false)                                           |  |
|  |   opts.exclude_submodules(true)                                         |  |
|  +-------------------------------------------------------------------------+  |
|       |                                                                       |
|       v                                                                       |
|  Step 3: repo.statuses(Some(&mut opts))                                       |
|       |                                                                       |
|       v                                                                       |
|  +-------------------------------------------------------------------------+  |
|  | Step 4: Iterate and classify each entry                                 |  |
|  +-------------------------------------------------------------------------+  |
|  |   for entry in statuses.iter() {                                        |  |
|  |       let status = entry.status();                                      |  |
|  |                                                                         |  |
|  |       is_staged     |  is_unstaged   |  is_untracked                    |  |
|  |       status.is_*   |  status.is_*   |  status.is_wt_new()              |  |
|  |            |                |                |                           |  |
|  |            v                v                v                           |  |
|  |      staged.push     unstaged.push   untracked.push                     |  |
|  |   }                                                                     |  |
|  +-------------------------------------------------------------------------+  |
|       |                                                                       |
|       v                                                                       |
|  +-------------------------------------------------------------------------+  |
|  | Step 5: Get branch info + ahead/behind counts                           |  |
|  +-------------------------------------------------------------------------+  |
|  |   branch = repo.head().shorthand()                                      |  |
|  |   (ahead, behind) = get_ahead_behind(&repo)                             |  |
|  +-------------------------------------------------------------------------+  |
|       |                                                                       |
|       v                                                                       |
|  OUTPUT: GitStatus {                                                          |
|      branch, is_head_detached, ahead, behind,                                 |
|      staged, unstaged, untracked                                              |
|  }                                                                            |
|                                                                               |
+===============================================================================+

Diff Parsing

The diff parser uses VTE callbacks to classify each line:
+===============================================================================+
|                                                                               |
|  DIFF PARSING PIPELINE                                                        |
|                                                                               |
+===============================================================================+
|                                                                               |
|  INPUT: path, file_path, staged (bool)                                        |
|                                                                               |
|  +-------------------------------------------------------------------------+  |
|  | Step 1: Setup diff options with pathspec                                |  |
|  +-------------------------------------------------------------------------+  |
|  |   let mut diff_opts = DiffOptions::new();                               |  |
|  |   diff_opts.pathspec(file_path);                                        |  |
|  +-------------------------------------------------------------------------+  |
|       |                                                                       |
|       v                                                                       |
|  +-------------------------------------------------------------------------+  |
|  | Step 2: Get HEAD tree for comparison base                               |  |
|  +-------------------------------------------------------------------------+  |
|  |   let head = repo.head()?;                                              |  |
|  |   let head_tree = head.peel_to_tree()?;                                 |  |
|  +-------------------------------------------------------------------------+  |
|       |                                                                       |
|       v                                                                       |
|  +-------------------------------------------------------------------------+  |
|  | Step 3: Choose diff method based on staged flag                         |  |
|  +-------------------------------------------------------------------------+  |
|  |                                                                         |  |
|  |   if staged {                     } else {                              |  |
|  |     diff_tree_to_index              diff_tree_to_workdir_with_index     |  |
|  |   }                                 }                                   |  |
|  |           |                                   |                          |  |
|  |           v                                   v                          |  |
|  |   Compare HEAD to index            Compare HEAD to working dir           |  |
|  +-------------------------------------------------------------------------+  |
|       |                                                                       |
|       v                                                                       |
|  +-------------------------------------------------------------------------+  |
|  | Step 4: Parse diff using print callback                                 |  |
|  +-------------------------------------------------------------------------+  |
|  |   diff.print(Patch, |delta, hunk, line| {                               |  |
|  |       match line.origin() {                                             |  |
|  |           +------------------------------------------------+            |  |
|  |           | Origin | Line Type  | Action                   |            |  |
|  |           |--------|------------|--------------------------|            |  |
|  |           | 'F'    | "header"   | File header              |            |  |
|  |           | 'H'    | "header"   | Hunk header              |            |  |
|  |           | '@'    | "hunk"     | Hunk marker              |            |  |
|  |           | '+'    | "addition" | Count additions          |            |  |
|  |           | '-'    | "deletion" | Count deletions          |            |  |
|  |           | ' '    | "context"  | Context line             |            |  |
|  |           +------------------------------------------------+            |  |
|  |       }                                                                 |  |
|  |   });                                                                   |  |
|  +-------------------------------------------------------------------------+  |
|       |                                                                       |
|       v                                                                       |
|  OUTPUT: ParsedDiff {                                                         |
|      path: file_path,                                                         |
|      lines: Vec<ParsedDiffLine>,                                              |
|      additions: count,                                                        |
|      deletions: count                                                         |
|  }                                                                            |
|                                                                               |
+===============================================================================+

Commit Graph Generation

+===============================================================================+
|                                                                               |
|  COMMIT GRAPH PIPELINE                                                        |
|                                                                               |
+===============================================================================+
|                                                                               |
|  INPUT: path, limit (max commits to process)                                  |
|                                                                               |
|  +-------------------------------------------------------------------------+  |
|  | Step 1: Collect branch tips                                             |  |
|  +-------------------------------------------------------------------------+  |
|  |   for branch in repo.branches()? {                                      |  |
|  |       branch_tips.insert(tip_oid, branch_name);                         |  |
|  |   }                                                                     |  |
|  +-------------------------------------------------------------------------+  |
|       |                                                                       |
|       v                                                                       |
|  +-------------------------------------------------------------------------+  |
|  | Step 2: Walk commits from HEAD                                          |  |
|  +-------------------------------------------------------------------------+  |
|  |   let mut revwalk = repo.revwalk()?;                                    |  |
|  |   revwalk.push_head()?;                                                 |  |
|  |   revwalk.set_sorting(Topological | Time);                              |  |
|  +-------------------------------------------------------------------------+  |
|       |                                                                       |
|       v                                                                       |
|  +-------------------------------------------------------------------------+  |
|  | Step 3: Assign columns to branches                                      |  |
|  +-------------------------------------------------------------------------+  |
|  |                                                                         |  |
|  |   Column Assignment Algorithm:                                          |  |
|  |   +-------------------------------------------------------------------+ |  |
|  |   |  Column 0   |  Column 1   |  Column 2   |  Column N               | |  |
|  |   |-------------|-------------|-------------|-------------------------| |  |
|  |   |  main       |  feature-a  |  feature-b  |  ...                    | |  |
|  |   |  branch     |             |             |                         | |  |
|  |   +-------------------------------------------------------------------+ |  |
|  |                                                                         |  |
|  |   - Main branch gets column 0                                           |  |
|  |   - Feature branches get 1, 2, ...                                      |  |
|  |   - Reuse columns when branches merge                                   |  |
|  +-------------------------------------------------------------------------+  |
|       |                                                                       |
|       v                                                                       |
|  +-------------------------------------------------------------------------+  |
|  | Step 4: Build graph connections                                         |  |
|  +-------------------------------------------------------------------------+  |
|  |   for commit in commits {                                               |  |
|  |       Condition            | Connection Type                             |  |
|  |       parents.len() > 1    | "merge_left/right"                          |  |
|  |       column changes       | "branch_left/right"                         |  |
|  |       otherwise            | "straight"                                  |  |
|  |   }                                                                     |  |
|  +-------------------------------------------------------------------------+  |
|       |                                                                       |
|       v                                                                       |
|  OUTPUT: CommitGraph {                                                        |
|      nodes: Vec<CommitGraphNode>,                                             |
|      branches: Vec<BranchInfo>,                                               |
|      total_commits,                                                           |
|      max_columns                                                              |
|  }                                                                            |
|                                                                               |
+===============================================================================+

Error Handling

All errors are converted to String for IPC compatibility:
// Pattern 1: Direct conversion
let repo = Repository::open(path).map_err(|e| e.to_string())?;

// Pattern 2: With custom context
let output = Command::new("git")
    .args(&["..."])
    .output()
    .map_err(|e| format!("Failed to run git: {}", e))?;

// Pattern 3: Check status and return stderr
if !output.status.success() {
    let stderr = String::from_utf8_lossy(&output.stderr);
    return Err(stderr.to_string());
}

Graceful Degradation

The backend returns partial data on non-critical errors:
+===============================================================================+
|                                                                               |
|  GRACEFUL DEGRADATION STRATEGY                                                |
|                                                                               |
+===============================================================================+
|                                                                               |
|                    Operation                                                  |
|                        |                                                      |
|               +-------+-------+                                               |
|               |               |                                               |
|               v               v                                               |
|            Success         Failure                                            |
|               |               |                                               |
|               v               v                                               |
|           Use value      Try fallback 1                                       |
|                              |                                                |
|                      +-------+-------+                                        |
|                      |               |                                        |
|                      v               v                                        |
|                   Success         Failure                                     |
|                      |               |                                        |
|                      v               v                                        |
|                  Use value      Try fallback 2                                |
|                                     |                                         |
|                             +-------+-------+                                 |
|                             |               |                                 |
|                             v               v                                 |
|                          Success         Failure                              |
|                             |               |                                 |
|                             v               v                                 |
|                         Use value      Use default                            |
|                                                                               |
|  Result: Always return SOMETHING rather than fail completely                  |
|                                                                               |
+===============================================================================+

Data Transformation Chain

+===============================================================================+
|                                                                               |
|  DATA TRANSFORMATION CHAIN                                                    |
|                                                                               |
+===============================================================================+
|                                                                               |
|  RAW GIT DATA                RUST PROCESSING              FRONTEND-READY     |
|  ============                ===============              ==============      |
|                                                                               |
|  +--------------------+      +--------------------+      +------------------+ |
|  | commit.author()    | ---> | GitCommitInfo.     | ---> | "John Doe"       | |
|  | .name()            |      | author             |      |                  | |
|  +--------------------+      +--------------------+      +------------------+ |
|                                                                               |
|  +--------------------+      +--------------------+      +------------------+ |
|  | commit.time()      | ---> | format_relative_   | ---> | "5m ago"         | |
|  | .seconds()         |      | time()             |      |                  | |
|  +--------------------+      +--------------------+      +------------------+ |
|                                                                               |
|  +--------------------+      +--------------------+      +------------------+ |
|  | diff.print()       | ---> | ParsedDiffLine     | ---> | Ready for CSS    | |
|  | (raw callback)     |      | with line_type     |      | class binding    | |
|  +--------------------+      +--------------------+      +------------------+ |
|                                                                               |
|  +--------------------+      +--------------------+      +------------------+ |
|  | repo.branches()    | ---> | group_branches_    | ---> | "Today",         | |
|  | (iterator)         |      | by_time()          |      | "Yesterday", ... | |
|  +--------------------+      +--------------------+      +------------------+ |
|                                                                               |
+===============================================================================+

Optimization Strategies

Batch API for IPC Reduction

Single call replaces 5 separate roundtrips:
BEFORE: 5 Separate IPC Calls
  - git_status
  - git_branches
  - git_log
  - worktree_list
  - stash_list

Total: 5 roundtrips, 5 repository opens

AFTER: Single Batch Call
  - git_full_refresh

Total: 1 roundtrip, 1 repository open

PERFORMANCE GAIN: ~5x reduction in IPC overhead

Parsed Diff Optimization

BEFORE: Raw Diff + JS Parsing
  Backend sends raw diff string
  Frontend splits by lines, detects types, parses headers
  Cost: ~10ms per 1000-line diff

AFTER: Parsed Diff
  Backend sends ParsedDiff with line_type classification
  Frontend iterates array, applies CSS classes
  Cost: <1ms per 1000-line diff

PERFORMANCE GAIN: 5-10x improvement on large diffs

Time Formatting in Rust

Relative time formatting moved from JavaScript to Rust:
diff (seconds)Output
< 60”just now”
< 3600m ago”
< 86400h ago”
< 604800d ago”
< 2592000w ago”
>= 2592000”YYYY-MM-DD” format
Benefit: Formatted strings sent over IPC, no JS computation

THE CENTER

These implementation patterns optimize for speed, structure, and completeness. Human should not wait to see AI work. Data must be ready for direct rendering. All relevant context must be included.