How witr Extracts and Displays Git Repository Context for Running Processes
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. 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:
// 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:
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 (line 48), the detector receives the resolved working directory:
gitRepo, gitBranch := detectGitInfo(cwd)
The returned values populate the model.Process struct fields.
Windows Implementation
internal/proc/process_windows.go (lines 51-53) assigns the same values during process construction:
GitRepo: gitRepo,
GitBranch: gitBranch,
This pattern repeats identically in process_darwin.go for macOS and 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 defines dedicated fields for Git information:
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 output formatter in internal/output/standard.go conditionally renders Git repository and branch information:
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:
$ 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:
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 |
Core detection: detectGitInfo, gitDirFromFile, gitBranchFromHEAD |
internal/proc/process_linux.go |
Linux process reading with Git context |
internal/proc/process_windows.go |
Windows process reading with Git context |
internal/proc/process_darwin.go |
macOS process reading with Git context |
internal/proc/process_freebsd.go |
FreeBSD process reading with Git context |
pkg/model/process.go |
Process struct definition with GitRepo and GitBranch fields |
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
.gitentries, and parsing HEAD references. -
Dual detection modes handle standard repositories (
.gitdirectories) and worktrees/submodules (.gitfiles withgitdir:pointers). -
Cross-platform invocation occurs in
process_linux.go,process_windows.go, and other OS-specific files, populatingmodel.Processfields consistently. -
Conditional output rendering in
standard.godisplays 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →