# How witr Extracts and Displays Git Repository Context for Running Processes

> Learn how witr finds and shows Git repo context for running processes by analyzing working directories and HEAD references. Get clear CLI output for your workflow.

- Repository: [Pranshu Parmar/witr](https://github.com/pranshuparmar/witr)
- Tags: internals
- Published: 2026-08-10

---

**witr identifies the Git repository and branch associated with a process by walking up from its working directory, detecting `.git` folders or gitdir files, parsing HEAD references, and rendering the results in formatted CLI output.**

The `witr` command-line tool provides runtime visibility into running processes, including the Git context that owns them. By examining process working directories and their parent paths, witr resolves repository names and active branches without external Git binary calls. This article explains the complete detection pipeline as implemented in the `pranshuparmar/witr` repository.

## Git Context Detection Algorithm

The core detection logic resides in [`internal/proc/git.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/git.go). The `detectGitInfo` function implements a **directory traversal algorithm** with a maximum depth of 10 levels to locate and parse Git metadata.

### Finding the Git Directory

Starting from the process current working directory (`cwd`), the algorithm examines each parent level:

```go
// Simplified logic from internal/proc/git.go
func detectGitInfo(cwd string) (repoName, branch string) {
    // Walk up directory tree (max 10 levels)
    for i := 0; i < 10 && dir != ""; i++ {
        gitPath := filepath.Join(dir, ".git")
        info, err := os.Stat(gitPath)
        if err == nil {
            if info.IsDir() {
                // Standard .git directory found
                gitDir = gitPath
            } else {
                // .git file (worktree/submodule) - parse gitdir: path
                gitDir = gitDirFromFile(gitPath)
            }
            break
        }
        dir = filepath.Dir(dir) // Move up one level
    }
    // ...
}

```

The `gitDirFromFile` helper handles **worktrees and submodules** where `.git` is a file rather than directory. It parses the `gitdir: <path>` directive to resolve the actual Git metadata location.

### Resolving the Current Branch

Once the Git directory is located, `gitBranchFromHEAD` extracts branch information:

```go
func gitBranchFromHEAD(gitDir string) string {
    headPath := filepath.Join(gitDir, "HEAD")
    data, err := os.ReadFile(headPath)
    if err != nil {
        return ""
    }
    content := strings.TrimSpace(string(data))
    
    // Parse "ref: refs/heads/main" format
    if strings.HasPrefix(content, "ref: refs/heads/") {
        return strings.TrimPrefix(content, "ref: refs/heads/")
    }
    // Detached HEAD or other state returns empty string
    return ""
}

```

The function returns the branch name only when HEAD references a named branch. **Detached HEAD states and unreadable files result in empty branch strings**, with only the repository name displayed.

## Platform-Specific Process Integration

The Git detector is invoked uniformly across all supported platforms through platform-specific process reading implementations.

### Linux Implementation

In [`internal/proc/process_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/process_linux.go) (line 48), the detector receives the resolved working directory:

```go
gitRepo, gitBranch := detectGitInfo(cwd)

```

The returned values populate the `model.Process` struct fields.

### Windows Implementation

[`internal/proc/process_windows.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/process_windows.go) (lines 51-53) assigns the same values during process construction:

```go
GitRepo:   gitRepo,
GitBranch: gitBranch,

```

This pattern repeats identically in [`process_darwin.go`](https://github.com/pranshuparmar/witr/blob/main/process_darwin.go) for macOS and [`process_freebsd.go`](https://github.com/pranshuparmar/witr/blob/main/process_freebsd.go) for FreeBSD, ensuring **cross-platform consistency** in Git context extraction.

## Storing Git Context in Process Models

The `model.Process` struct in [`pkg/model/process.go`](https://github.com/pranshuparmar/witr/blob/main/pkg/model/process.go) defines dedicated fields for Git information:

```go
type Process struct {
    PID       int
    PPID      int
    // ... other fields ...
    GitRepo   string  // Base name of repository directory
    GitBranch string  // Current branch name (may be empty)
}

```

These fields enable downstream consumers to access Git context without re-executing detection logic.

## Rendering Git Information in CLI Output

The [`standard.go`](https://github.com/pranshuparmar/witr/blob/main/standard.go) output formatter in [`internal/output/standard.go`](https://github.com/pranshuparmar/witr/blob/main/internal/output/standard.go) conditionally renders Git repository and branch information:

```go
if proc.GitRepo != "" {
    if proc.GitBranch != "" {
        out.Printf("%sGit Repo%s    : %s (%s)\n", 
            ColorCyan, ColorReset,
            proc.GitRepo, proc.GitBranch)
    } else {
        out.Printf("%sGit Repo%s    : %s\n", 
            ColorCyan, ColorReset,
            proc.GitRepo)
    }
}

```

The formatter applies **terminal sanitization** (`SanitizeTerminal`) to prevent control-character injection from malicious repository paths.

## Practical Usage Examples

### Command-Line Inspection

Display Git context for a specific process:

```bash
$ witr info 1234
...
Git Repo    : my-app (main)
...

```

The output shows repository name with branch in parentheses when available.

### Programmatic Library Usage

Access Git context directly through the witr internal API:

```go
package main

import (
    "fmt"
    "github.com/pranshuparmar/witr/internal/proc"
)

func main() {
    p, err := proc.ReadProcess(1234)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Process %d runs in repo %s on branch %s\n",
        p.PID, p.GitRepo, p.GitBranch)
}

```

This pattern enables building custom tooling atop witr's process inspection capabilities.

## Key Source Files

| File | Purpose |
|------|---------|
| [`internal/proc/git.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/git.go) | Core detection: `detectGitInfo`, `gitDirFromFile`, `gitBranchFromHEAD` |
| [`internal/proc/process_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/process_linux.go) | Linux process reading with Git context |
| [`internal/proc/process_windows.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/process_windows.go) | Windows process reading with Git context |
| [`internal/proc/process_darwin.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/process_darwin.go) | macOS process reading with Git context |
| [`internal/proc/process_freebsd.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/process_freebsd.go) | FreeBSD process reading with Git context |
| [`pkg/model/process.go`](https://github.com/pranshuparmar/witr/blob/main/pkg/model/process.go) | `Process` struct definition with `GitRepo` and `GitBranch` fields |
| [`internal/output/standard.go`](https://github.com/pranshuparmar/witr/blob/main/internal/output/standard.go) | CLI formatter rendering Git repository and branch |

## Summary

- **witr extracts Git context** by walking up to 10 parent directories from a process working directory, locating `.git` entries, and parsing HEAD references.

- **Dual detection modes** handle standard repositories (`.git` directories) and worktrees/submodules (`.git` files with `gitdir:` pointers).

- **Cross-platform invocation** occurs in [`process_linux.go`](https://github.com/pranshuparmar/witr/blob/main/process_linux.go), [`process_windows.go`](https://github.com/pranshuparmar/witr/blob/main/process_windows.go), and other OS-specific files, populating `model.Process` fields consistently.

- **Conditional output rendering** in [`standard.go`](https://github.com/pranshuparmar/witr/blob/main/standard.go) displays repository names with optional branch names, with safety sanitization applied.

## Frequently Asked Questions

### How does witr handle processes running outside any Git repository?

According to the `detectGitInfo` implementation, when no `.git` entry is found within 10 directory levels, the function returns empty strings for both repository and branch. The output formatter skips Git information entirely in this case, showing only standard process details.

### Does witr require the Git binary to be installed?

No. The detection algorithm in [`internal/proc/git.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/git.go) performs **direct filesystem inspection** of `.git` directories and HEAD files without shelling out to Git commands. This eliminates external dependencies and improves performance.

### What happens when a process runs in a Git worktree or submodule?

The `gitDirFromFile` function specifically handles these cases. When `.git` is a file rather than directory, it parses the `gitdir: <path>` line to locate the actual Git metadata, then proceeds with normal HEAD resolution from that path.

### Can witr detect Git context for processes with changed working directories?

witr reads the current working directory at the time of inspection. If a process has changed its working directory since startup and the original directory no longer exists in the process state, detection may fail or return incorrect context based on the newly resolved path.