# How witr Detects Git Repositories and Branches from a Working Directory

> Learn how witr detects Git repositories and branches by traversing your working directory and parsing .git entries and HEAD files. Discover Git repo names and current branches.

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

---

**witr detects Git repositories and branches by traversing up the directory tree from a process's working directory, parsing `.git` entries and `HEAD` files to extract repository names and current branches.**

witr is an open-source process monitoring tool that enriches process listings with contextual Git metadata. Understanding how witr detects Git repositories and branches from a working directory reveals a lightweight filesystem traversal approach that handles standard repositories, worktrees, and submodules without invoking the `git` binary.

## The Detection Algorithm in internal/proc/git.go

The core detection logic resides in **[`internal/proc/git.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/git.go)**, specifically within the `detectGitInfo` function. This implementation performs an iterative upward search from the supplied working directory to locate Git metadata.

### Early Exit and Directory Traversal

The function first validates the input path. If the supplied working directory (`cwd`) is empty or equals the placeholder string `"unknown"`, the function returns empty strings for both the repository name and branch immediately.

For valid paths, witr implements a bounded upward search:

1. Starting at `cwd`, the code climbs up to **10 parent directories** (`for depth := 0; depth < 10; depth++`)
2. At each level, it checks for the existence of a `.git` entry using filesystem operations
3. If found, it proceeds to extract metadata; if the loop completes without finding `.git`, it returns empty strings

### Resolving Git Directories for Worktrees and Submodules

When witr encounters a `.git` entry, it must determine whether this represents a standard repository root or a pointer to an external Git directory (used by worktrees and submodules):

- **If `.git` is a directory**: The current search directory is the repository root
- **If `.git` is a file**: The file contains a `gitdir:` pointer that must be resolved

The helper function `gitDirFromFile(gitFile, baseDir string) string` handles the second case. It reads the `.git` file, extracts the path following the `gitdir:` prefix, and converts relative paths to absolute paths by joining them with `baseDir`.

### Extracting Repository and Branch Names

Once a valid Git directory is identified, witr extracts two pieces of metadata:

**Repository name**: Derived from `filepath.Base(searchDir)`, returning the directory name that contained the `.git` entry.

**Branch name**: Obtained via `gitBranchFromHEAD(gitDir string)`, which reads the `<gitDir>/HEAD` file. If the file content starts with `ref: refs/heads/`, the function returns the suffix as the branch name. For detached HEAD states or unreadable files, it returns an empty string.

## Platform Integration via Process Collectors

The Git detection integrates with platform-specific process collection through the `ReadProcess` functions implemented in files like [`internal/proc/process_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/process_linux.go) (with equivalents for macOS and Windows).

`ReadProcess` obtains a process's working directory via platform-native mechanisms—such as reading `/proc/<pid>/cwd` on Linux—and passes this path to `detectGitInfo(cwd)`. The resulting strings populate the `GitRepo` and `GitBranch` fields of the `model.Process` struct defined in [`pkg/model/process.go`](https://github.com/pranshuparmar/witr/blob/main/pkg/model/process.go), making the metadata available for display.

## Code Implementation Examples

The following Go code demonstrates the helper functions that enable Git metadata extraction:

```go
// Resolves a .git file pointer (used by worktrees/submodules)
func gitDirFromFile(gitFile, baseDir string) string {
    data, err := os.ReadFile(gitFile)
    if err != nil { return "" }
    for _, line := range strings.Split(string(data), "\n") {
        if rest, ok := strings.CutPrefix(strings.TrimSpace(line), "gitdir:"); ok {
            dir := strings.TrimSpace(rest)
            if !filepath.IsAbs(dir) {
                dir = filepath.Join(baseDir, dir)
            }
            return dir
        }
    }
    return ""
}

```

```go
// Extracts branch name from the Git HEAD file
func gitBranchFromHEAD(gitDir string) string {
    head, err := os.ReadFile(filepath.Join(gitDir, "HEAD"))
    if err != nil { return "" }
    if ref, ok := strings.CutPrefix(strings.TrimSpace(string(head)), "ref: "); ok {
        return strings.TrimPrefix(ref, "refs/heads/")
    }
    return "" // detached HEAD
}

```

```go
// Usage example within process detection
cwd := "/home/alice/projects/witr/submodule"
repo, branch := detectGitInfo(cwd)
// repo  => "submodule"
// branch => "feature/awesome"

```

## Summary

- **Bounded traversal**: witr searches up to 10 parent directories from the working directory to locate `.git` entries, preventing infinite loops in deeply nested filesystems.
- **Worktree support**: The `gitDirFromFile` helper resolves `gitdir:` pointers in `.git` files, enabling detection for Git worktrees and submodules.
- **Direct file parsing**: Branch detection reads the `HEAD` file directly rather than executing `git` commands, minimizing overhead.
- **Platform abstraction**: Git detection integrates with OS-specific process collectors via `ReadProcess`, supporting Linux, macOS, and Windows through `/proc` filesystem or equivalent APIs.
- **Graceful degradation**: When running outside a Git repository or in a detached HEAD state, witr returns empty strings rather than failing.

## Frequently Asked Questions

### How does witr handle Git worktrees?

witr handles Git worktrees by detecting when `.git` is a file rather than a directory. According to the source code in [`internal/proc/git.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/git.go), the `gitDirFromFile` function parses the `gitdir:` path inside this file to locate the actual Git directory, enabling accurate branch detection even when the working directory is a linked worktree.

### What happens if a process runs outside a Git repository?

If no `.git` entry is found within 10 parent directories of the process's working directory, `detectGitInfo` returns empty strings for both the repository name and branch. This is stored in the `model.Process` struct, resulting in blank Git metadata for that process in the witr output.

### Which file contains the core Git detection logic?

The core Git detection logic is implemented in **[`internal/proc/git.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/git.go)**. This file contains the `detectGitInfo` function and its helpers `gitDirFromFile` and `gitBranchFromHEAD`, which together handle repository discovery, worktree resolution, and branch extraction.

### How does witr determine the current branch name?

witr determines the branch name by reading the `HEAD` file within the Git directory via `gitBranchFromHEAD`. If the file contains a reference like `ref: refs/heads/main`, the function extracts and returns `main`. For detached HEAD states or if the file cannot be read, it returns an empty string.